Renames and jDo
[fanfix.git] / src / be / nikiroo / fanfix / reader / BasicReader.java
1 package be.nikiroo.fanfix.reader;
2
3 import java.awt.Desktop;
4 import java.io.File;
5 import java.io.IOException;
6 import java.net.MalformedURLException;
7 import java.net.URL;
8
9 import be.nikiroo.fanfix.BasicLibrary;
10 import be.nikiroo.fanfix.Instance;
11 import be.nikiroo.fanfix.LocalLibrary;
12 import be.nikiroo.fanfix.bundles.Config;
13 import be.nikiroo.fanfix.bundles.UiConfig;
14 import be.nikiroo.fanfix.data.MetaData;
15 import be.nikiroo.fanfix.data.Story;
16 import be.nikiroo.fanfix.supported.BasicSupport;
17 import be.nikiroo.utils.Progress;
18 import be.nikiroo.utils.serial.SerialUtils;
19
20 /**
21 * The class that handles the different {@link Story} readers you can use.
22 * <p>
23 * All the readers should be accessed via {@link BasicReader#getReader()}.
24 *
25 * @author niki
26 */
27 public abstract class BasicReader {
28 /**
29 * A type of {@link BasicReader}.
30 *
31 * @author niki
32 */
33 public enum ReaderType {
34 /** Simple reader that outputs everything on the console */
35 CLI,
36 /** Reader that starts local programs to handle the stories */
37 GUI,
38 /** A text (UTF-8) reader with menu and text windows */
39 TUI,
40
41 ;
42
43 /**
44 * Return the full class name of a type that implements said
45 * {@link ReaderType}.
46 *
47 * @return the class name
48 */
49 public String getTypeName() {
50 String pkg = "be.nikiroo.fanfix.reader.";
51 switch (this) {
52 case CLI:
53 return pkg + "CliReader";
54 case TUI:
55 return pkg + "TuiReader";
56 case GUI:
57 return pkg + "GuiReader";
58 }
59
60 return null;
61 }
62 }
63
64 private static BasicLibrary defaultLibrary = Instance.getLibrary();
65 private static ReaderType defaultType = ReaderType.GUI;
66
67 private BasicLibrary lib;
68 private Story story;
69 private ReaderType type;
70
71 /**
72 * Take the default reader type configuration from the config file.
73 */
74 static {
75 String typeString = Instance.getConfig().getString(Config.READER_TYPE);
76 if (typeString != null && !typeString.isEmpty()) {
77 try {
78 ReaderType type = ReaderType.valueOf(typeString.toUpperCase());
79 defaultType = type;
80 } catch (IllegalArgumentException e) {
81 // Do nothing
82 }
83 }
84 }
85
86 /**
87 * The type of this reader.
88 *
89 * @return the type
90 */
91 public ReaderType getType() {
92 return type;
93 }
94
95 /**
96 * The type of this reader.
97 *
98 * @param type
99 * the new type
100 *
101 * @return the type
102 */
103 protected BasicReader setType(ReaderType type) {
104 this.type = type;
105 return this;
106 }
107
108 /**
109 * Return the current {@link Story}.
110 *
111 * @return the {@link Story}
112 */
113 public Story getStory() {
114 return story;
115 }
116
117 /**
118 * The {@link LocalLibrary} to load the stories from (by default, takes the
119 * default {@link LocalLibrary}).
120 *
121 * @return the {@link LocalLibrary}
122 */
123 public BasicLibrary getLibrary() {
124 if (lib == null) {
125 lib = defaultLibrary;
126 }
127
128 return lib;
129 }
130
131 /**
132 * Change the {@link LocalLibrary} that will be managed by this
133 * {@link BasicReader}.
134 *
135 * @param lib
136 * the new {@link LocalLibrary}
137 */
138 public void setLibrary(LocalLibrary lib) {
139 this.lib = lib;
140 }
141
142 /**
143 * Create a new {@link BasicReader} for a {@link Story} in the
144 * {@link LocalLibrary}.
145 *
146 * @param luid
147 * the {@link Story} ID
148 * @param pg
149 * the optional progress reporter
150 *
151 * @throws IOException
152 * in case of I/O error
153 */
154 public void setStory(String luid, Progress pg) throws IOException {
155 story = lib.getStory(luid, pg);
156 if (story == null) {
157 throw new IOException("Cannot retrieve story from library: " + luid);
158 }
159 }
160
161 /**
162 * Create a new {@link BasicReader} for an external {@link Story}.
163 *
164 * @param source
165 * the {@link Story} {@link URL}
166 * @param pg
167 * the optional progress reporter
168 *
169 * @throws IOException
170 * in case of I/O error
171 */
172 public void setStory(URL source, Progress pg) throws IOException {
173 BasicSupport support = BasicSupport.getSupport(source);
174 if (support == null) {
175 throw new IOException("URL not supported: " + source.toString());
176 }
177
178 story = support.process(source, pg);
179 if (story == null) {
180 throw new IOException(
181 "Cannot retrieve story from external source: "
182 + source.toString());
183
184 }
185 }
186
187 /**
188 * Start the {@link Story} Reading.
189 *
190 * @throws IOException
191 * in case of I/O error or if the {@link Story} was not
192 * previously set
193 */
194 public abstract void read() throws IOException;
195
196 /**
197 * Read the selected chapter (starting at 1).
198 *
199 * @param chapter
200 * the chapter
201 *
202 * @throws IOException
203 * in case of I/O error or if the {@link Story} was not
204 * previously set
205 */
206 public abstract void read(int chapter) throws IOException;
207
208 /**
209 * Start the reader in browse mode for the given source (or pass NULL for
210 * all sources).
211 *
212 * @param source
213 * the type of {@link Story} to take into account, or NULL for
214 * all
215 */
216 public abstract void browse(String source);
217
218 /**
219 * Return a new {@link BasicReader} ready for use if one is configured.
220 * <p>
221 * Can return NULL if none are configured.
222 *
223 * @return a {@link BasicReader}, or NULL if none configured
224 */
225 public static BasicReader getReader() {
226 try {
227 if (defaultType != null) {
228 return ((BasicReader) SerialUtils.createObject(defaultType
229 .getTypeName())).setType(defaultType);
230 }
231 } catch (Exception e) {
232 Instance.syserr(new Exception("Cannot create a reader of type: "
233 + defaultType + " (Not compiled in?)", e));
234 }
235
236 return null;
237 }
238
239 /**
240 * The default {@link ReaderType} used when calling
241 * {@link BasicReader#getReader()}.
242 *
243 * @return the default type
244 */
245 public static ReaderType getDefaultReaderType() {
246 return defaultType;
247 }
248
249 /**
250 * The default {@link ReaderType} used when calling
251 * {@link BasicReader#getReader()}.
252 *
253 * @param defaultType
254 * the new default type
255 */
256 public static void setDefaultReaderType(ReaderType defaultType) {
257 BasicReader.defaultType = defaultType;
258 }
259
260 /**
261 * Change the default {@link LocalLibrary} to open with the
262 * {@link BasicReader}s.
263 *
264 * @param lib
265 * the new {@link LocalLibrary}
266 */
267 public static void setDefaultLibrary(BasicLibrary lib) {
268 BasicReader.defaultLibrary = lib;
269 }
270
271 /**
272 * Return an {@link URL} from this {@link String}, be it a file path or an
273 * actual {@link URL}.
274 *
275 * @param sourceString
276 * the source
277 *
278 * @return the corresponding {@link URL}
279 *
280 * @throws MalformedURLException
281 * if this is neither a file nor a conventional {@link URL}
282 */
283 public static URL getUrl(String sourceString) throws MalformedURLException {
284 if (sourceString == null || sourceString.isEmpty()) {
285 throw new MalformedURLException("Empty url");
286 }
287
288 URL source = null;
289 try {
290 source = new URL(sourceString);
291 } catch (MalformedURLException e) {
292 File sourceFile = new File(sourceString);
293 source = sourceFile.toURI().toURL();
294 }
295
296 return source;
297 }
298
299 /**
300 * Open the {@link Story} with an external reader (the program will be
301 * passed the main file associated with this {@link Story}).
302 *
303 * @param lib
304 * the {@link BasicLibrary} to select the {@link Story} from
305 * @param luid
306 * the {@link Story} LUID
307 *
308 * @throws IOException
309 * in case of I/O error
310 */
311 public static void open(BasicLibrary lib, String luid) throws IOException {
312 MetaData meta = lib.getInfo(luid);
313 File target = lib.getFile(luid);
314
315 open(meta, target);
316 }
317
318 /**
319 * Open the {@link Story} with an external reader (the program will be
320 * passed the given target file).
321 *
322 * @param meta
323 * the {@link Story} to load
324 * @param target
325 * the target {@link File}
326 *
327 * @throws IOException
328 * in case of I/O error
329 */
330 protected static void open(MetaData meta, File target) throws IOException {
331 String program = null;
332 if (meta.isImageDocument()) {
333 program = Instance.getUiConfig().getString(
334 UiConfig.IMAGES_DOCUMENT_READER);
335 } else {
336 program = Instance.getUiConfig().getString(
337 UiConfig.NON_IMAGES_DOCUMENT_READER);
338 }
339
340 if (program != null && program.trim().isEmpty()) {
341 program = null;
342 }
343
344 if (program == null) {
345 try {
346 Desktop.getDesktop().browse(target.toURI());
347 } catch (UnsupportedOperationException e) {
348 Runtime.getRuntime().exec(
349 new String[] { "xdg-open", target.getAbsolutePath() });
350
351 }
352 } else {
353 Runtime.getRuntime().exec(
354 new String[] { program, target.getAbsolutePath() });
355 }
356 }
357 }