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