Fixes, new version number: 0.9.2
[fanfix.git] / src / be / nikiroo / fanfix / Library.java
CommitLineData
08fe2e33
NR
1package be.nikiroo.fanfix;
2
3import java.io.File;
4import java.io.IOException;
5import java.net.URL;
6import java.util.ArrayList;
7import java.util.HashMap;
8import java.util.List;
9import java.util.Map;
10import java.util.Map.Entry;
11
08fe2e33
NR
12import be.nikiroo.fanfix.data.MetaData;
13import be.nikiroo.fanfix.data.Story;
14import be.nikiroo.fanfix.output.BasicOutput;
15import be.nikiroo.fanfix.output.BasicOutput.OutputType;
16import be.nikiroo.fanfix.supported.BasicSupport;
17import be.nikiroo.fanfix.supported.BasicSupport.SupportType;
68686a37 18import be.nikiroo.fanfix.supported.InfoReader;
08fe2e33
NR
19
20/**
21 * Manage a library of Stories: import, export, list.
22 * <p>
23 * Each {@link Story} object will be associated with a (local to the library)
24 * unique ID, the LUID, which will be used to identify the {@link Story}.
25 *
26 * @author niki
27 */
28public class Library {
29 private File baseDir;
30 private Map<MetaData, File> stories;
08fe2e33 31 private int lastId;
2206ef66
NR
32 private OutputType text;
33 private OutputType image;
08fe2e33
NR
34
35 /**
36 * Create a new {@link Library} with the given backend directory.
37 *
38 * @param dir
2206ef66
NR
39 * the directory where to find the {@link Story} objects
40 * @param text
41 * the {@link OutputType} to save the text-focused stories into
42 * @param image
43 * the {@link OutputType} to save the images-focused stories into
08fe2e33 44 */
2206ef66 45 public Library(File dir, OutputType text, OutputType image) {
08fe2e33
NR
46 this.baseDir = dir;
47 this.stories = new HashMap<MetaData, File>();
48 this.lastId = 0;
2206ef66
NR
49 this.text = text;
50 this.image = image;
08fe2e33
NR
51
52 dir.mkdirs();
53 }
54
55 /**
56 * List all the stories of the given source type in the {@link Library}, or
57 * all the stories if NULL is passed as a type.
58 *
59 * @param type
60 * the type of story to retrieve, or NULL for all
61 *
62 * @return the stories
63 */
64 public List<MetaData> getList(SupportType type) {
65 String typeString = type == null ? null : type.getSourceName();
66
67 List<MetaData> list = new ArrayList<MetaData>();
68 for (Entry<MetaData, File> entry : getStories().entrySet()) {
69 String storyType = entry.getValue().getParentFile().getName();
70 if (typeString == null || typeString.equalsIgnoreCase(storyType)) {
71 list.add(entry.getKey());
72 }
73 }
74
75 return list;
76 }
77
301791d3
NR
78 /**
79 * Retrieve a {@link File} corresponding to the given {@link Story}.
80 *
81 * @param luid
82 * the Library UID of the story
83 *
84 * @return the corresponding {@link Story}
85 */
86 public MetaData getInfo(String luid) {
87 if (luid != null) {
88 for (Entry<MetaData, File> entry : getStories().entrySet()) {
89 if (luid.equals(entry.getKey().getLuid())) {
90 return entry.getKey();
91 }
92 }
93 }
94
95 return null;
96 }
97
2206ef66
NR
98 /**
99 * Retrieve a {@link File} corresponding to the given {@link Story}.
100 *
101 * @param luid
102 * the Library UID of the story
103 *
104 * @return the corresponding {@link Story}
105 */
106 public File getFile(String luid) {
107 if (luid != null) {
108 for (Entry<MetaData, File> entry : getStories().entrySet()) {
109 if (luid.equals(entry.getKey().getLuid())) {
110 return entry.getValue();
111 }
112 }
113 }
114
115 return null;
116 }
117
08fe2e33
NR
118 /**
119 * Retrieve a specific {@link Story}.
120 *
121 * @param luid
122 * the Library UID of the story
123 *
124 * @return the corresponding {@link Story}
125 */
126 public Story getStory(String luid) {
127 if (luid != null) {
128 for (Entry<MetaData, File> entry : getStories().entrySet()) {
129 if (luid.equals(entry.getKey().getLuid())) {
130 try {
fe999aa4
NR
131 SupportType type = SupportType.valueOfAllOkUC(entry
132 .getKey().getType());
133 URL url = entry.getValue().toURI().toURL();
134 if (type != null) {
135 return BasicSupport.getSupport(type).process(url);
136 } else {
137 throw new IOException("Unknown type: "
138 + entry.getKey().getType());
139 }
08fe2e33
NR
140 } catch (IOException e) {
141 // We should not have not-supported files in the
142 // library
143 Instance.syserr(new IOException(
144 "Cannot load file from library: "
145 + entry.getValue().getPath(), e));
146 }
147 }
148 }
149 }
150
151 return null;
152 }
153
154 /**
155 * Import the {@link Story} at the given {@link URL} into the
156 * {@link Library}.
157 *
158 * @param url
159 * the {@link URL} to import
160 *
161 * @return the imported {@link Story}
162 *
163 * @throws IOException
164 * in case of I/O error
165 */
166 public Story imprt(URL url) throws IOException {
167 BasicSupport support = BasicSupport.getSupport(url);
168 if (support == null) {
169 throw new IOException("URL not supported: " + url.toString());
170 }
171
2206ef66 172 return save(support.process(url), null);
08fe2e33
NR
173 }
174
175 /**
176 * Export the {@link Story} to the given target in the given format.
177 *
178 * @param luid
179 * the {@link Story} ID
180 * @param type
181 * the {@link OutputType} to transform it to
182 * @param target
183 * the target to save to
184 *
185 * @return the saved resource (the main saved {@link File})
186 *
187 * @throws IOException
188 * in case of I/O error
189 */
190 public File export(String luid, OutputType type, String target)
191 throws IOException {
192 BasicOutput out = BasicOutput.getOutput(type, true);
193 if (out == null) {
194 throw new IOException("Output type not supported: " + type);
195 }
196
197 return out.process(getStory(luid), target);
198 }
199
200 /**
2206ef66
NR
201 * Save a {@link Story} to the {@link Library}.
202 *
203 * @param story
204 * the {@link Story} to save
205 *
206 * @return the same {@link Story}, whose LUID may have changed
207 *
208 * @throws IOException
209 * in case of I/O error
210 */
211 public Story save(Story story) throws IOException {
212 return save(story, null);
213 }
214
215 /**
216 * Save a {@link Story} to the {@link Library} -- the LUID <b>must</b> be
217 * correct, or NULL to get the next free one.
08fe2e33
NR
218 *
219 * @param story
220 * the {@link Story} to save
2206ef66
NR
221 * @param luid
222 * the <b>correct</b> LUID or NULL to get the next free one
223 *
224 * @return the same {@link Story}, whose LUID may have changed
08fe2e33
NR
225 *
226 * @throws IOException
227 * in case of I/O error
228 */
2206ef66 229 private Story save(Story story, String luid) throws IOException {
301791d3 230 MetaData key = story.getMeta().clone();
08fe2e33 231
2206ef66
NR
232 if (luid == null || luid.isEmpty()) {
233 getStories(); // refresh lastId if needed
234 key.setLuid(String.format("%03d", (++lastId)));
235 } else {
236 key.setLuid(luid);
237 }
238
08fe2e33
NR
239 getDir(key).mkdirs();
240 if (!getDir(key).exists()) {
241 throw new IOException("Cannot create library dir");
242 }
243
244 OutputType out;
08fe2e33 245 if (key != null && key.isImageDocument()) {
2206ef66 246 out = image;
08fe2e33 247 } else {
2206ef66 248 out = text;
08fe2e33 249 }
2206ef66 250
08fe2e33
NR
251 BasicOutput it = BasicOutput.getOutput(out, true);
252 File file = it.process(story, getFile(key).getPath());
2206ef66
NR
253 getStories().put(story.getMeta(), file);
254
255 return story;
08fe2e33
NR
256 }
257
258 /**
259 * The directory (full path) where the {@link Story} related to this
260 * {@link MetaData} should be located on disk.
261 *
262 * @param key
263 * the {@link Story} {@link MetaData}
264 *
265 * @return the target directory
266 */
267 private File getDir(MetaData key) {
268 String source = key.getSource().replaceAll("[^a-zA-Z0-9._+-]", "_");
269 return new File(baseDir, source);
270 }
271
272 /**
273 * The target (full path) where the {@link Story} related to this
274 * {@link MetaData} should be located on disk.
275 *
276 * @param key
277 * the {@link Story} {@link MetaData}
278 *
279 * @return the target
280 */
281 private File getFile(MetaData key) {
282 String title = key.getTitle().replaceAll("[^a-zA-Z0-9._+-]", "_");
283 return new File(getDir(key), key.getLuid() + "_" + title);
284 }
285
286 /**
287 * Return all the known stories in this {@link Library} object.
288 *
289 * @return the stories
290 */
291 private Map<MetaData, File> getStories() {
292 if (stories.isEmpty()) {
293 lastId = 0;
68686a37 294
2206ef66 295 String ext = ".info";
08fe2e33
NR
296 for (File dir : baseDir.listFiles()) {
297 if (dir.isDirectory()) {
298 for (File file : dir.listFiles()) {
299 try {
2206ef66 300 if (file.getPath().toLowerCase().endsWith(ext)) {
68686a37
NR
301 MetaData meta = InfoReader.readMeta(file);
302 try {
303 int id = Integer.parseInt(meta.getLuid());
304 if (id > lastId) {
305 lastId = id;
08fe2e33 306 }
68686a37 307
2206ef66
NR
308 // Replace .info with whatever is needed:
309 String path = file.getPath();
310 path = path.substring(0, path.length()
311 - ext.length());
312
313 String newExt = getOutputType(meta)
314 .getDefaultExtension();
315
316 file = new File(path + newExt);
317 //
318
68686a37
NR
319 stories.put(meta, file);
320
321 } catch (Exception e) {
08fe2e33
NR
322 // not normal!!
323 Instance.syserr(new IOException(
68686a37
NR
324 "Cannot understand the LUID of "
325 + file.getPath() + ": "
326 + meta.getLuid(), e));
08fe2e33
NR
327 }
328 }
329 } catch (IOException e) {
330 // We should not have not-supported files in the
331 // library
332 Instance.syserr(new IOException(
333 "Cannot load file from library: "
334 + file.getPath(), e));
335 }
336 }
337 }
338 }
339 }
340
341 return stories;
342 }
2206ef66
NR
343
344 /**
345 * Return the {@link OutputType} for this {@link Story}.
346 *
347 * @param meta
348 * the {@link Story} {@link MetaData}
349 *
350 * @return the type
351 */
352 private OutputType getOutputType(MetaData meta) {
353 if (meta != null && meta.isImageDocument()) {
354 return image;
355 } else {
356 return text;
357 }
358 }
08fe2e33 359}