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