03b584cf760849ec9fcaccc84529db806318ce87
1 package be
.nikiroo
.fanfix
;
4 import java
.io
.IOException
;
6 import java
.util
.ArrayList
;
7 import java
.util
.HashMap
;
10 import java
.util
.Map
.Entry
;
12 import be
.nikiroo
.fanfix
.data
.MetaData
;
13 import be
.nikiroo
.fanfix
.data
.Story
;
14 import be
.nikiroo
.fanfix
.output
.BasicOutput
;
15 import be
.nikiroo
.fanfix
.output
.BasicOutput
.OutputType
;
16 import be
.nikiroo
.fanfix
.supported
.BasicSupport
;
17 import be
.nikiroo
.utils
.ui
.Progress
;
18 import be
.nikiroo
.fanfix
.supported
.BasicSupport
.SupportType
;
19 import be
.nikiroo
.fanfix
.supported
.InfoReader
;
22 * Manage a library of Stories: import, export, list.
24 * Each {@link Story} object will be associated with a (local to the library)
25 * unique ID, the LUID, which will be used to identify the {@link Story}.
29 public class Library
{
31 private Map
<MetaData
, File
> stories
;
33 private OutputType text
;
34 private OutputType image
;
37 * Create a new {@link Library} with the given backend directory.
40 * the directory where to find the {@link Story} objects
42 * the {@link OutputType} to save the text-focused stories into
44 * the {@link OutputType} to save the images-focused stories into
46 public Library(File dir
, OutputType text
, OutputType image
) {
48 this.stories
= new HashMap
<MetaData
, File
>();
57 * List all the known types of stories.
61 public List
<String
> getTypes() {
62 List
<String
> list
= new ArrayList
<String
>();
63 for (Entry
<MetaData
, File
> entry
: getStories().entrySet()) {
64 String storyType
= entry
.getValue().getParentFile().getName();
65 if (!list
.contains(storyType
)) {
74 * List all the stories of the given source type in the {@link Library}, or
75 * all the stories if NULL is passed as a type.
78 * the type of story to retrieve, or NULL for all
82 public List
<MetaData
> getList(String type
) {
83 List
<MetaData
> list
= new ArrayList
<MetaData
>();
84 for (Entry
<MetaData
, File
> entry
: getStories().entrySet()) {
85 String storyType
= entry
.getValue().getParentFile().getName();
86 if (type
== null || type
.equalsIgnoreCase(storyType
)) {
87 list
.add(entry
.getKey());
95 * Retrieve a {@link File} corresponding to the given {@link Story}.
98 * the Library UID of the story
100 * @return the corresponding {@link Story}
102 public MetaData
getInfo(String luid
) {
104 for (Entry
<MetaData
, File
> entry
: getStories().entrySet()) {
105 if (luid
.equals(entry
.getKey().getLuid())) {
106 return entry
.getKey();
115 * Retrieve a {@link File} corresponding to the given {@link Story}.
118 * the Library UID of the story
120 * @return the corresponding {@link Story}
122 public File
getFile(String luid
) {
124 for (Entry
<MetaData
, File
> entry
: getStories().entrySet()) {
125 if (luid
.equals(entry
.getKey().getLuid())) {
126 return entry
.getValue();
135 * Retrieve a specific {@link Story}.
138 * the Library UID of the story
140 * the optional progress reporter
142 * @return the corresponding {@link Story} or NULL if not found
144 public Story
getStory(String luid
, Progress pg
) {
146 for (Entry
<MetaData
, File
> entry
: getStories().entrySet()) {
147 if (luid
.equals(entry
.getKey().getLuid())) {
149 SupportType type
= SupportType
.valueOfAllOkUC(entry
150 .getKey().getType());
151 URL url
= entry
.getValue().toURI().toURL();
153 return BasicSupport
.getSupport(type
).process(url
,
156 throw new IOException("Unknown type: "
157 + entry
.getKey().getType());
159 } catch (IOException e
) {
160 // We should not have not-supported files in the
162 Instance
.syserr(new IOException(
163 "Cannot load file from library: "
164 + entry
.getValue().getPath(), e
));
179 * Import the {@link Story} at the given {@link URL} into the
183 * the {@link URL} to import
185 * the optional progress reporter
187 * @return the imported {@link Story}
189 * @throws IOException
190 * in case of I/O error
192 public Story
imprt(URL url
, Progress pg
) throws IOException
{
193 BasicSupport support
= BasicSupport
.getSupport(url
);
194 if (support
== null) {
195 throw new IOException("URL not supported: " + url
.toString());
198 return save(support
.process(url
, pg
), null);
202 * Export the {@link Story} to the given target in the given format.
205 * the {@link Story} ID
207 * the {@link OutputType} to transform it to
209 * the target to save to
211 * the optional progress reporter
213 * @return the saved resource (the main saved {@link File})
215 * @throws IOException
216 * in case of I/O error
218 public File
export(String luid
, OutputType type
, String target
, Progress pg
)
220 BasicOutput out
= BasicOutput
.getOutput(type
, true);
222 throw new IOException("Output type not supported: " + type
);
225 Story story
= getStory(luid
, pg
);
227 throw new IOException("Cannot find story to export: " + luid
);
230 return out
.process(story
, target
);
234 * Save a {@link Story} to the {@link Library}.
237 * the {@link Story} to save
239 * @return the same {@link Story}, whose LUID may have changed
241 * @throws IOException
242 * in case of I/O error
244 public Story
save(Story story
) throws IOException
{
245 return save(story
, null);
249 * Save a {@link Story} to the {@link Library} -- the LUID <b>must</b> be
250 * correct, or NULL to get the next free one.
253 * the {@link Story} to save
255 * the <b>correct</b> LUID or NULL to get the next free one
257 * @return the same {@link Story}, whose LUID may have changed
259 * @throws IOException
260 * in case of I/O error
262 public Story
save(Story story
, String luid
) throws IOException
{
263 // Do not change the original metadata, but change the original story
264 MetaData key
= story
.getMeta().clone();
267 if (luid
== null || luid
.isEmpty()) {
268 getStories(); // refresh lastId if needed
269 key
.setLuid(String
.format("%03d", (++lastId
)));
274 getDir(key
).mkdirs();
275 if (!getDir(key
).exists()) {
276 throw new IOException("Cannot create library dir");
280 if (key
!= null && key
.isImageDocument()) {
286 BasicOutput it
= BasicOutput
.getOutput(out
, true);
287 File file
= it
.process(story
, getFile(key
).getPath());
288 getStories().put(story
.getMeta(), file
);
294 * The directory (full path) where the {@link Story} related to this
295 * {@link MetaData} should be located on disk.
298 * the {@link Story} {@link MetaData}
300 * @return the target directory
302 private File
getDir(MetaData key
) {
303 String source
= key
.getSource().replaceAll("[^a-zA-Z0-9._+-]", "_");
304 return new File(baseDir
, source
);
308 * The target (full path) where the {@link Story} related to this
309 * {@link MetaData} should be located on disk.
312 * the {@link Story} {@link MetaData}
316 private File
getFile(MetaData key
) {
317 String title
= key
.getTitle().replaceAll("[^a-zA-Z0-9._+-]", "_");
318 return new File(getDir(key
), key
.getLuid() + "_" + title
);
322 * Return all the known stories in this {@link Library} object.
324 * @return the stories
326 private Map
<MetaData
, File
> getStories() {
327 if (stories
.isEmpty()) {
330 String ext
= ".info";
331 for (File dir
: baseDir
.listFiles()) {
332 if (dir
.isDirectory()) {
333 for (File file
: dir
.listFiles()) {
335 if (file
.getPath().toLowerCase().endsWith(ext
)) {
336 MetaData meta
= InfoReader
.readMeta(file
);
338 int id
= Integer
.parseInt(meta
.getLuid());
343 // Replace .info with whatever is needed:
344 String path
= file
.getPath();
345 path
= path
.substring(0, path
.length()
348 String newExt
= getOutputType(meta
)
349 .getDefaultExtension();
351 file
= new File(path
+ newExt
);
354 stories
.put(meta
, file
);
356 } catch (Exception e
) {
358 Instance
.syserr(new IOException(
359 "Cannot understand the LUID of "
360 + file
.getPath() + ": "
361 + meta
.getLuid(), e
));
364 } catch (IOException e
) {
365 // We should not have not-supported files in the
367 Instance
.syserr(new IOException(
368 "Cannot load file from library: "
369 + file
.getPath(), e
));
380 * Return the {@link OutputType} for this {@link Story}.
383 * the {@link Story} {@link MetaData}
387 private OutputType
getOutputType(MetaData meta
) {
388 if (meta
!= null && meta
.isImageDocument()) {