Add URL into .info and MetaData, work on Library
[fanfix.git] / src / be / nikiroo / fanfix / Library.java
... / ...
CommitLineData
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
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;
18import be.nikiroo.fanfix.supported.InfoReader;
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;
31 private int lastId;
32 private OutputType text;
33 private OutputType image;
34
35 /**
36 * Create a new {@link Library} with the given backend directory.
37 *
38 * @param dir
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
44 */
45 public Library(File dir, OutputType text, OutputType image) {
46 this.baseDir = dir;
47 this.stories = new HashMap<MetaData, File>();
48 this.lastId = 0;
49 this.text = text;
50 this.image = image;
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
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 File getFile(String luid) {
87 if (luid != null) {
88 for (Entry<MetaData, File> entry : getStories().entrySet()) {
89 if (luid.equals(entry.getKey().getLuid())) {
90 return entry.getValue();
91 }
92 }
93 }
94
95 return null;
96 }
97
98 /**
99 * Retrieve a specific {@link Story}.
100 *
101 * @param luid
102 * the Library UID of the story
103 *
104 * @return the corresponding {@link Story}
105 */
106 public Story getStory(String luid) {
107 if (luid != null) {
108 for (Entry<MetaData, File> entry : getStories().entrySet()) {
109 if (luid.equals(entry.getKey().getLuid())) {
110 try {
111 SupportType type = SupportType.valueOfAllOkUC(entry
112 .getKey().getType());
113 URL url = entry.getValue().toURI().toURL();
114 if (type != null) {
115 return BasicSupport.getSupport(type).process(url);
116 } else {
117 throw new IOException("Unknown type: "
118 + entry.getKey().getType());
119 }
120 } catch (IOException e) {
121 // We should not have not-supported files in the
122 // library
123 Instance.syserr(new IOException(
124 "Cannot load file from library: "
125 + entry.getValue().getPath(), e));
126 }
127 }
128 }
129 }
130
131 return null;
132 }
133
134 /**
135 * Import the {@link Story} at the given {@link URL} into the
136 * {@link Library}.
137 *
138 * @param url
139 * the {@link URL} to import
140 *
141 * @return the imported {@link Story}
142 *
143 * @throws IOException
144 * in case of I/O error
145 */
146 public Story imprt(URL url) throws IOException {
147 BasicSupport support = BasicSupport.getSupport(url);
148 if (support == null) {
149 throw new IOException("URL not supported: " + url.toString());
150 }
151
152 return save(support.process(url), null);
153 }
154
155 /**
156 * Export the {@link Story} to the given target in the given format.
157 *
158 * @param luid
159 * the {@link Story} ID
160 * @param type
161 * the {@link OutputType} to transform it to
162 * @param target
163 * the target to save to
164 *
165 * @return the saved resource (the main saved {@link File})
166 *
167 * @throws IOException
168 * in case of I/O error
169 */
170 public File export(String luid, OutputType type, String target)
171 throws IOException {
172 BasicOutput out = BasicOutput.getOutput(type, true);
173 if (out == null) {
174 throw new IOException("Output type not supported: " + type);
175 }
176
177 return out.process(getStory(luid), target);
178 }
179
180 /**
181 * Save a {@link Story} to the {@link Library}.
182 *
183 * @param story
184 * the {@link Story} to save
185 *
186 * @return the same {@link Story}, whose LUID may have changed
187 *
188 * @throws IOException
189 * in case of I/O error
190 */
191 public Story save(Story story) throws IOException {
192 return save(story, null);
193 }
194
195 /**
196 * Save a {@link Story} to the {@link Library} -- the LUID <b>must</b> be
197 * correct, or NULL to get the next free one.
198 *
199 * @param story
200 * the {@link Story} to save
201 * @param luid
202 * the <b>correct</b> LUID or NULL to get the next free one
203 *
204 * @return the same {@link Story}, whose LUID may have changed
205 *
206 * @throws IOException
207 * in case of I/O error
208 */
209 private Story save(Story story, String luid) throws IOException {
210 MetaData key = story.getMeta();
211
212 if (luid == null || luid.isEmpty()) {
213 getStories(); // refresh lastId if needed
214 key.setLuid(String.format("%03d", (++lastId)));
215 } else {
216 key.setLuid(luid);
217 }
218
219 getDir(key).mkdirs();
220 if (!getDir(key).exists()) {
221 throw new IOException("Cannot create library dir");
222 }
223
224 OutputType out;
225 if (key != null && key.isImageDocument()) {
226 out = image;
227 } else {
228 out = text;
229 }
230
231 BasicOutput it = BasicOutput.getOutput(out, true);
232 File file = it.process(story, getFile(key).getPath());
233 getStories().put(story.getMeta(), file);
234
235 return story;
236 }
237
238 /**
239 * The directory (full path) where the {@link Story} related to this
240 * {@link MetaData} should be located on disk.
241 *
242 * @param key
243 * the {@link Story} {@link MetaData}
244 *
245 * @return the target directory
246 */
247 private File getDir(MetaData key) {
248 String source = key.getSource().replaceAll("[^a-zA-Z0-9._+-]", "_");
249 return new File(baseDir, source);
250 }
251
252 /**
253 * The target (full path) where the {@link Story} related to this
254 * {@link MetaData} should be located on disk.
255 *
256 * @param key
257 * the {@link Story} {@link MetaData}
258 *
259 * @return the target
260 */
261 private File getFile(MetaData key) {
262 String title = key.getTitle().replaceAll("[^a-zA-Z0-9._+-]", "_");
263 return new File(getDir(key), key.getLuid() + "_" + title);
264 }
265
266 /**
267 * Return all the known stories in this {@link Library} object.
268 *
269 * @return the stories
270 */
271 private Map<MetaData, File> getStories() {
272 if (stories.isEmpty()) {
273 lastId = 0;
274
275 String ext = ".info";
276 for (File dir : baseDir.listFiles()) {
277 if (dir.isDirectory()) {
278 for (File file : dir.listFiles()) {
279 try {
280 if (file.getPath().toLowerCase().endsWith(ext)) {
281 MetaData meta = InfoReader.readMeta(file);
282 try {
283 int id = Integer.parseInt(meta.getLuid());
284 if (id > lastId) {
285 lastId = id;
286 }
287
288 // Replace .info with whatever is needed:
289 String path = file.getPath();
290 path = path.substring(0, path.length()
291 - ext.length());
292
293 String newExt = getOutputType(meta)
294 .getDefaultExtension();
295
296 file = new File(path + newExt);
297 //
298
299 stories.put(meta, file);
300
301 } catch (Exception e) {
302 // not normal!!
303 Instance.syserr(new IOException(
304 "Cannot understand the LUID of "
305 + file.getPath() + ": "
306 + meta.getLuid(), e));
307 }
308 }
309 } catch (IOException e) {
310 // We should not have not-supported files in the
311 // library
312 Instance.syserr(new IOException(
313 "Cannot load file from library: "
314 + file.getPath(), e));
315 }
316 }
317 }
318 }
319 }
320
321 return stories;
322 }
323
324 /**
325 * Return the {@link OutputType} for this {@link Story}.
326 *
327 * @param meta
328 * the {@link Story} {@link MetaData}
329 *
330 * @return the type
331 */
332 private OutputType getOutputType(MetaData meta) {
333 if (meta != null && meta.isImageDocument()) {
334 return image;
335 } else {
336 return text;
337 }
338 }
339}