Add a new TUI system based upon Jexer (WIP)
[fanfix.git] / src / be / nikiroo / fanfix / reader / BasicReader.java
CommitLineData
89cb07a6
NR
1package be.nikiroo.fanfix.reader;
2
c1873e56 3import java.awt.Desktop;
3b2b638f 4import java.io.File;
89cb07a6 5import java.io.IOException;
3b2b638f 6import java.net.MalformedURLException;
89cb07a6
NR
7import java.net.URL;
8
9import be.nikiroo.fanfix.Instance;
10import be.nikiroo.fanfix.Library;
d0114000 11import be.nikiroo.fanfix.bundles.Config;
c1873e56
NR
12import be.nikiroo.fanfix.bundles.UiConfig;
13import be.nikiroo.fanfix.data.MetaData;
89cb07a6
NR
14import be.nikiroo.fanfix.data.Story;
15import be.nikiroo.fanfix.supported.BasicSupport;
3b2b638f 16import be.nikiroo.utils.Progress;
c1873e56 17import be.nikiroo.utils.ui.UIUtils;
89cb07a6
NR
18
19/**
dd56a893 20 * The class that handles the different {@link Story} readers you can use.
89cb07a6 21 * <p>
dd56a893 22 * All the readers should be accessed via {@link BasicReader#getReader()}.
89cb07a6
NR
23 *
24 * @author niki
25 */
3727aae2
NR
26public 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 */
c1873e56
NR
31 GUI,
32 /** A text (UTF-8) reader with menu and text windows */
33 TUI,
3727aae2
NR
34 }
35
c1873e56 36 private static ReaderType defaultType = ReaderType.GUI;
89cb07a6 37 private Story story;
3727aae2
NR
38 private ReaderType type;
39
d0114000
NR
40 /**
41 * Take the default reader type configuration from the config file.
42 */
3727aae2 43 static {
d0114000
NR
44 String typeString = Instance.getConfig().getString(Config.READER_TYPE);
45 if (typeString != null && !typeString.isEmpty()) {
46 try {
47 ReaderType type = ReaderType.valueOf(typeString.toUpperCase());
48 defaultType = type;
49 } catch (IllegalArgumentException e) {
50 // Do nothing
51 }
52 }
3727aae2
NR
53 }
54
55 /**
56 * The type of this reader.
57 *
58 * @return the type
59 */
60 public ReaderType getType() {
61 return type;
62 }
63
64 /**
65 * The type of this reader.
66 *
67 * @param type
68 * the new type
69 */
70 protected BasicReader setType(ReaderType type) {
71 this.type = type;
72 return this;
73 }
89cb07a6
NR
74
75 /**
76 * Return the current {@link Story}.
77 *
78 * @return the {@link Story}
79 */
80 public Story getStory() {
81 return story;
82 }
83
84 /**
3727aae2 85 * Create a new {@link BasicReader} for a {@link Story} in the
89cb07a6
NR
86 * {@link Library} .
87 *
88 * @param luid
89 * the {@link Story} ID
92fb0719
NR
90 * @param pg
91 * the optional progress reporter
92 *
89cb07a6
NR
93 * @throws IOException
94 * in case of I/O error
95 */
92fb0719
NR
96 public void setStory(String luid, Progress pg) throws IOException {
97 story = Instance.getLibrary().getStory(luid, pg);
89cb07a6 98 if (story == null) {
92fb0719 99 throw new IOException("Cannot retrieve story from library: " + luid);
89cb07a6
NR
100 }
101 }
102
103 /**
3727aae2 104 * Create a new {@link BasicReader} for an external {@link Story}.
89cb07a6
NR
105 *
106 * @param source
107 * the {@link Story} {@link URL}
92fb0719
NR
108 * @param pg
109 * the optional progress reporter
110 *
89cb07a6
NR
111 * @throws IOException
112 * in case of I/O error
113 */
92fb0719 114 public void setStory(URL source, Progress pg) throws IOException {
89cb07a6
NR
115 BasicSupport support = BasicSupport.getSupport(source);
116 if (support == null) {
117 throw new IOException("URL not supported: " + source.toString());
118 }
119
92fb0719 120 story = support.process(source, pg);
89cb07a6
NR
121 if (story == null) {
122 throw new IOException(
123 "Cannot retrieve story from external source: "
124 + source.toString());
125
126 }
127 }
128
129 /**
130 * Start the {@link Story} Reading.
131 *
132 * @throws IOException
133 * in case of I/O error or if the {@link Story} was not
134 * previously set
135 */
136 public abstract void read() throws IOException;
137
138 /**
139 * Read the selected chapter (starting at 1).
140 *
141 * @param chapter
142 * the chapter
edd46289
NR
143 *
144 * @throws IOException
145 * in case of I/O error or if the {@link Story} was not
146 * previously set
89cb07a6 147 */
edd46289 148 public abstract void read(int chapter) throws IOException;
89cb07a6
NR
149
150 /**
151 * Start the reader in browse mode for the given type (or pass NULL for all
152 * types).
153 *
154 * @param type
155 * the type of {@link Story} to take into account, or NULL for
156 * all
157 */
333f0e7b 158 public abstract void start(String type);
3727aae2
NR
159
160 /**
d0114000
NR
161 * Return a new {@link BasicReader} ready for use if one is configured.
162 * <p>
163 * Can return NULL if none are configured.
3727aae2 164 *
d0114000 165 * @return a {@link BasicReader}, or NULL if none configured
3727aae2
NR
166 */
167 public static BasicReader getReader() {
333f0e7b
NR
168 try {
169 if (defaultType != null) {
170 switch (defaultType) {
c1873e56
NR
171 case GUI:
172 UIUtils.setLookAndFeel();
173 return new LocalReader().setType(ReaderType.GUI);
333f0e7b
NR
174 case CLI:
175 return new CliReader().setType(ReaderType.CLI);
c1873e56
NR
176 case TUI:
177 return new TuiReader().setType(ReaderType.TUI);
333f0e7b 178 }
d0114000 179 }
333f0e7b
NR
180 } catch (IOException e) {
181 Instance.syserr(new Exception("Cannot create a reader of type: "
182 + defaultType, e));
3727aae2
NR
183 }
184
185 return null;
186 }
187
188 /**
189 * The default {@link ReaderType} used when calling
190 * {@link BasicReader#getReader()}.
191 *
192 * @return the default type
193 */
194 public static ReaderType getDefaultReaderType() {
195 return defaultType;
196 }
197
198 /**
199 * The default {@link ReaderType} used when calling
200 * {@link BasicReader#getReader()}.
201 *
202 * @param defaultType
203 * the new default type
204 */
205 public static void setDefaultReaderType(ReaderType defaultType) {
206 BasicReader.defaultType = defaultType;
207 }
3b2b638f
NR
208
209 /**
210 * Return an {@link URL} from this {@link String}, be it a file path or an
211 * actual {@link URL}.
212 *
213 * @param sourceString
214 * the source
215 *
216 * @return the corresponding {@link URL}
217 *
218 * @throws MalformedURLException
219 * if this is neither a file nor a conventional {@link URL}
220 */
221 public static URL getUrl(String sourceString) throws MalformedURLException {
222 if (sourceString == null || sourceString.isEmpty()) {
223 throw new MalformedURLException("Empty url");
224 }
225
226 URL source = null;
227 try {
228 source = new URL(sourceString);
229 } catch (MalformedURLException e) {
230 File sourceFile = new File(sourceString);
231 source = sourceFile.toURI().toURL();
232 }
233
234 return source;
235 }
c1873e56
NR
236
237 // open with external player the related file
238 public static void open(String luid) throws IOException {
239 MetaData meta = Instance.getLibrary().getInfo(luid);
240 File target = Instance.getLibrary().getFile(luid);
241
242 open(meta, target);
243 }
244
245 // open with external player the related file
246 protected static void open(MetaData meta, File target) throws IOException {
247 String program = null;
248 if (meta.isImageDocument()) {
249 program = Instance.getUiConfig().getString(
250 UiConfig.IMAGES_DOCUMENT_READER);
251 } else {
252 program = Instance.getUiConfig().getString(
253 UiConfig.NON_IMAGES_DOCUMENT_READER);
254 }
255
256 if (program != null && program.trim().isEmpty()) {
257 program = null;
258 }
259
260 if (program == null) {
261 try {
262 Desktop.getDesktop().browse(target.toURI());
263 } catch (UnsupportedOperationException e) {
264 Runtime.getRuntime().exec(
265 new String[] { "xdg-open", target.getAbsolutePath() });
266
267 }
268 } else {
269 Runtime.getRuntime().exec(
270 new String[] { program, target.getAbsolutePath() });
271 }
272 }
89cb07a6 273}