Update nikiroo-utils
[nikiroo-utils.git] / src / be / nikiroo / fanfix / Instance.java
CommitLineData
08fe2e33
NR
1package be.nikiroo.fanfix;
2
3import java.io.File;
4import java.io.IOException;
b42117f1 5import java.util.Date;
08fe2e33
NR
6
7import be.nikiroo.fanfix.bundles.Config;
8import be.nikiroo.fanfix.bundles.ConfigBundle;
99ccbdf6 9import be.nikiroo.fanfix.bundles.StringId;
08fe2e33 10import be.nikiroo.fanfix.bundles.StringIdBundle;
5bc9573b 11import be.nikiroo.fanfix.bundles.StringIdGuiBundle;
b4dc6ab5
NR
12import be.nikiroo.fanfix.bundles.UiConfig;
13import be.nikiroo.fanfix.bundles.UiConfigBundle;
e42573a0 14import be.nikiroo.fanfix.library.BasicLibrary;
5895a958 15import be.nikiroo.fanfix.library.CacheLibrary;
e42573a0 16import be.nikiroo.fanfix.library.LocalLibrary;
e023483b 17import be.nikiroo.fanfix.library.RemoteLibrary;
581d42c0 18import be.nikiroo.utils.Cache;
b42117f1 19import be.nikiroo.utils.IOUtils;
2aac79c7 20import be.nikiroo.utils.TempFiles;
581d42c0 21import be.nikiroo.utils.TraceHandler;
08fe2e33
NR
22import be.nikiroo.utils.resources.Bundles;
23
24/**
25 * Global state for the program (services and singletons).
26 *
27 * @author niki
28 */
29public class Instance {
30 private static ConfigBundle config;
b4dc6ab5 31 private static UiConfigBundle uiconfig;
08fe2e33 32 private static StringIdBundle trans;
f1fb834c 33 private static DataLoader cache;
5bc9573b 34 private static StringIdGuiBundle transGui;
e023483b 35 private static BasicLibrary lib;
08fe2e33 36 private static File coverDir;
3727aae2 37 private static File readerTmp;
b0e88ebd 38 private static File remoteDir;
b42117f1 39 private static String configDir;
581d42c0 40 private static TraceHandler tracer;
2aac79c7 41 private static TempFiles tempFiles;
a8209dd0 42
08fe2e33 43 static {
62c63b07 44 // Before we can configure it:
ae78e517 45 tracer = new TraceHandler(true, checkEnv("DEBUG"), checkEnv("DEBUG"));
62c63b07 46
9f705f1a
NR
47 // config dir:
48 configDir = getConfigDir();
b42117f1
NR
49 if (!new File(configDir).exists()) {
50 new File(configDir).mkdirs();
fe999aa4
NR
51 }
52
9f705f1a 53 // Most of the rest is dependent upon this:
38febea9 54 createConfigs(configDir, false);
4ff0b1a9
N
55
56 // Proxy support
57 // TODO: include new nikiroo-utils version
58 // Proxy.use(Instance.getConfig().getString(Config.USE_PROXY));
2206ef66 59
9f705f1a 60 // update tracer:
581d42c0
NR
61 boolean debug = Instance.getConfig()
62 .getBoolean(Config.DEBUG_ERR, false);
63 boolean trace = Instance.getConfig().getBoolean(Config.DEBUG_TRACE,
64 false);
d0114000
NR
65
66 if (checkEnv("DEBUG")) {
67 debug = true;
ae78e517 68 trace = true;
d0114000
NR
69 }
70
62c63b07 71 tracer = new TraceHandler(true, debug, trace);
581d42c0 72
9f705f1a
NR
73 // default Library
74 remoteDir = new File(configDir, "remote");
75 lib = createDefaultLibrary(remoteDir);
778d8d85 76
9f705f1a
NR
77 // create cache
78 File tmp = getFile(Config.CACHE_DIR);
68e370a4 79 if (tmp == null) {
9f705f1a 80 // Could have used: System.getProperty("java.io.tmpdir")
68e370a4
NR
81 tmp = new File(configDir, "tmp");
82 }
ae78e517 83 String ua = config.getString(Config.USER_AGENT);
08fe2e33 84 try {
08fe2e33
NR
85 int hours = config.getInteger(Config.CACHE_MAX_TIME_CHANGING, -1);
86 int hoursLarge = config
87 .getInteger(Config.CACHE_MAX_TIME_STABLE, -1);
f1fb834c 88 cache = new DataLoader(tmp, ua, hours, hoursLarge);
08fe2e33 89 } catch (IOException e) {
62c63b07 90 tracer.error(new IOException(
08fe2e33 91 "Cannot create cache (will continue without cache)", e));
ae78e517 92 cache = new DataLoader(ua);
08fe2e33 93 }
ae78e517
NR
94
95 cache.setTraceHandler(tracer);
9f705f1a
NR
96
97 // readerTmp / coverDir
98 readerTmp = getFile(UiConfig.CACHE_DIR_LOCAL_READER);
99 if (readerTmp == null) {
100 readerTmp = new File(configDir, "tmp-reader");
101 }
102
103 coverDir = getFile(Config.DEFAULT_COVERS_DIR);
104 if (coverDir != null && !coverDir.exists()) {
105 tracer.error(new IOException(
106 "The 'default covers' directory does not exists: "
107 + coverDir));
108 coverDir = null;
109 }
2aac79c7
NR
110
111 try {
112 tempFiles = new TempFiles("fanfix");
113 } catch (IOException e) {
114 tracer.error(new IOException("Cannot create temporary directory", e));
115 }
08fe2e33
NR
116 }
117
581d42c0
NR
118 /**
119 * The traces handler for this {@link Cache}.
62c63b07
NR
120 * <p>
121 * It is never NULL.
581d42c0 122 *
62c63b07 123 * @return the traces handler (never NULL)
581d42c0
NR
124 */
125 public static TraceHandler getTraceHandler() {
126 return tracer;
127 }
128
129 /**
130 * The traces handler for this {@link Cache}.
131 *
132 * @param tracer
133 * the new traces handler or NULL
134 */
135 public static void setTraceHandler(TraceHandler tracer) {
62c63b07
NR
136 if (tracer == null) {
137 tracer = new TraceHandler(false, false, false);
138 }
139
581d42c0 140 Instance.tracer = tracer;
ae78e517 141 cache.setTraceHandler(tracer);
581d42c0
NR
142 }
143
08fe2e33
NR
144 /**
145 * Get the (unique) configuration service for the program.
146 *
147 * @return the configuration service
148 */
149 public static ConfigBundle getConfig() {
150 return config;
151 }
152
b4dc6ab5
NR
153 /**
154 * Get the (unique) UI configuration service for the program.
155 *
156 * @return the configuration service
157 */
158 public static UiConfigBundle getUiConfig() {
159 return uiconfig;
160 }
161
ae78e517
NR
162 /**
163 * Reset the configuration.
164 *
165 * @param resetTrans
166 * also reset the translation files
167 */
168 public static void resetConfig(boolean resetTrans) {
169 String dir = Bundles.getDirectory();
170 Bundles.setDirectory(null);
171 try {
172 try {
173 ConfigBundle config = new ConfigBundle();
174 config.updateFile(configDir);
175 } catch (IOException e) {
176 tracer.error(e);
177 }
178 try {
179 UiConfigBundle uiconfig = new UiConfigBundle();
180 uiconfig.updateFile(configDir);
181 } catch (IOException e) {
182 tracer.error(e);
183 }
184
185 if (resetTrans) {
186 try {
187 StringIdBundle trans = new StringIdBundle(null);
188 trans.updateFile(configDir);
189 } catch (IOException e) {
190 tracer.error(e);
191 }
192 }
193 } finally {
194 Bundles.setDirectory(dir);
195 }
196 }
197
08fe2e33 198 /**
f1fb834c 199 * Get the (unique) {@link DataLoader} for the program.
08fe2e33 200 *
f1fb834c 201 * @return the {@link DataLoader}
08fe2e33 202 */
f1fb834c 203 public static DataLoader getCache() {
08fe2e33
NR
204 return cache;
205 }
206
207 /**
208 * Get the (unique) {link StringIdBundle} for the program.
5bc9573b
NR
209 * <p>
210 * This is used for the translations of the core parts of Fanfix.
39c3c689 211 *
08fe2e33
NR
212 * @return the {link StringIdBundle}
213 */
214 public static StringIdBundle getTrans() {
215 return trans;
216 }
217
5bc9573b
NR
218 /**
219 * Get the (unique) {link StringIdGuiBundle} for the program.
220 * <p>
221 * This is used for the translations of the GUI parts of Fanfix.
222 *
223 * @return the {link StringIdGuiBundle}
224 */
225 public static StringIdGuiBundle getTransGui() {
226 return transGui;
227 }
228
08fe2e33 229 /**
68e2c6d2 230 * Get the (unique) {@link LocalLibrary} for the program.
08fe2e33 231 *
68e2c6d2 232 * @return the {@link LocalLibrary}
08fe2e33 233 */
68e2c6d2 234 public static BasicLibrary getLibrary() {
778d8d85
NR
235 if (lib == null) {
236 throw new NullPointerException("We don't have a library to return");
237 }
238
08fe2e33
NR
239 return lib;
240 }
241
242 /**
243 * Return the directory where to look for default cover pages.
244 *
245 * @return the default covers directory
246 */
247 public static File getCoverDir() {
248 return coverDir;
249 }
250
3727aae2
NR
251 /**
252 * Return the directory where to store temporary files for the local reader.
253 *
254 * @return the directory
255 */
256 public static File getReaderDir() {
257 return readerTmp;
258 }
259
b0e88ebd
NR
260 /**
261 * Return the directory where to store temporary files for the remote
68e2c6d2 262 * {@link LocalLibrary}.
b0e88ebd
NR
263 *
264 * @param host
265 * the remote for this host
266 *
267 * @return the directory
268 */
269 public static File getRemoteDir(String host) {
9f705f1a
NR
270 return getRemoteDir(remoteDir, host);
271 }
272
273 /**
274 * Return the directory where to store temporary files for the remote
275 * {@link LocalLibrary}.
276 *
277 * @param remoteDir
278 * the base remote directory
279 * @param host
280 * the remote for this host
281 *
282 * @return the directory
283 */
284 private static File getRemoteDir(File remoteDir, String host) {
b0e88ebd
NR
285 remoteDir.mkdirs();
286
287 if (host != null) {
288 return new File(remoteDir, host);
289 }
290
291 return remoteDir;
292 }
293
b42117f1
NR
294 /**
295 * Check if we need to check that a new version of Fanfix is available.
296 *
297 * @return TRUE if we need to
298 */
299 public static boolean isVersionCheckNeeded() {
300 try {
a3641e4b
NR
301 long wait = config.getInteger(Config.UPDATE_INTERVAL, 1) * 24 * 60
302 * 60 * 1000;
b42117f1
NR
303 if (wait >= 0) {
304 String lastUpString = IOUtils.readSmallFile(new File(configDir,
305 "LAST_UPDATE"));
306 long delay = new Date().getTime()
307 - Long.parseLong(lastUpString);
308 if (delay > wait) {
309 return true;
310 }
311 } else {
312 return false;
313 }
314 } catch (Exception e) {
315 // No file or bad file:
316 return true;
317 }
318
319 return false;
320 }
321
322 /**
323 * Notify that we checked for a new version of Fanfix.
324 */
325 public static void setVersionChecked() {
326 try {
327 IOUtils.writeSmallFile(new File(configDir), "LAST_UPDATE",
328 Long.toString(new Date().getTime()));
329 } catch (IOException e) {
581d42c0 330 tracer.error(e);
08fe2e33
NR
331 }
332 }
333
2aac79c7
NR
334 /**
335 * The facility to use temporary files in this program.
336 * <p>
337 * <b>MUST</b> be closed at end of program.
338 *
339 * @return the facility
340 */
341 public static TempFiles getTempFiles() {
342 return tempFiles;
343 }
344
9f705f1a
NR
345 /**
346 * The configuration directory (will check, in order of preference,
347 * {@link Bundles#getDirectory()}, the system properties, the environment
348 * and then defaults to $HOME/.fanfix).
349 *
350 * @return the config directory
351 */
352 private static String getConfigDir() {
353 String configDir = Bundles.getDirectory();
354
355 if (configDir == null) {
356 configDir = System.getProperty("CONFIG_DIR");
357 }
358
359 if (configDir == null) {
360 configDir = System.getenv("CONFIG_DIR");
361 }
362
363 if (configDir == null) {
364 configDir = new File(getHome(), ".fanfix").getPath();
365 }
366
367 return configDir;
368 }
369
370 /**
371 * Create the config variables ({@link Instance#config},
5bc9573b
NR
372 * {@link Instance#uiconfig}, {@link Instance#trans} and
373 * {@link Instance#transGui}).
9f705f1a
NR
374 *
375 * @param configDir
376 * the directory where to find the configuration files
377 * @param refresh
38febea9 378 * TRUE to reset the configuration files from the default
9f705f1a
NR
379 * included ones
380 */
381 private static void createConfigs(String configDir, boolean refresh) {
382 if (!refresh) {
383 Bundles.setDirectory(configDir);
384 }
385
386 try {
387 config = new ConfigBundle();
388 config.updateFile(configDir);
389 } catch (IOException e) {
390 tracer.error(e);
391 }
392
393 try {
394 uiconfig = new UiConfigBundle();
395 uiconfig.updateFile(configDir);
396 } catch (IOException e) {
397 tracer.error(e);
398 }
399
400 // No updateFile for this one! (we do not want the user to have custom
401 // translations that won't accept updates from newer versions)
402 trans = new StringIdBundle(getLang());
5bc9573b 403 transGui = new StringIdGuiBundle(getLang());
9f705f1a
NR
404
405 // Fix an old bug (we used to store custom translation files by
406 // default):
407 if (trans.getString(StringId.INPUT_DESC_CBZ) == null) {
408 trans.deleteFile(configDir);
409 }
410
411 if (checkEnv("NOUTF")) {
412 trans.setUnicode(false);
5bc9573b 413 transGui.setUnicode(false);
9f705f1a
NR
414 }
415
416 Bundles.setDirectory(configDir);
417 }
418
419 /**
420 * Create the default library as specified by the config.
421 *
422 * @param remoteDir
423 * the base remote directory if needed
424 *
425 * @return the default {@link BasicLibrary}
426 */
427 private static BasicLibrary createDefaultLibrary(File remoteDir) {
428 BasicLibrary lib = null;
429
430 String remoteLib = config.getString(Config.DEFAULT_LIBRARY);
431 if (remoteLib == null || remoteLib.trim().isEmpty()) {
432 String libDir = System.getProperty("fanfix.libdir");
433 if (libDir == null || libDir.isEmpty()) {
38febea9 434 libDir = config.getString(Config.LIBRARY_DIR);
9f705f1a
NR
435 }
436 try {
437 lib = new LocalLibrary(getFile(libDir));
438 } catch (Exception e) {
439 tracer.error(new IOException(
440 "Cannot create library for directory: "
441 + getFile(libDir), e));
442 }
443 } else {
444 int pos = remoteLib.lastIndexOf(":");
445 if (pos >= 0) {
446 String port = remoteLib.substring(pos + 1).trim();
447 remoteLib = remoteLib.substring(0, pos);
448 pos = remoteLib.lastIndexOf(":");
449 if (pos >= 0) {
450 String host = remoteLib.substring(pos + 1).trim();
451 String key = remoteLib.substring(0, pos).trim();
452
453 try {
454 tracer.trace("Selecting remote library " + host + ":"
455 + port);
456 lib = new RemoteLibrary(key, host,
457 Integer.parseInt(port));
458 lib = new CacheLibrary(getRemoteDir(remoteDir, host),
459 lib);
460
461 } catch (Exception e) {
462 }
463 }
464 }
465
466 if (lib == null) {
467 tracer.error(new IOException(
468 "Cannot create remote library for: " + remoteLib));
469 }
470 }
471
472 return lib;
473 }
474
08fe2e33
NR
475 /**
476 * Return a path, but support the special $HOME variable.
477 *
478 * @return the path
479 */
480 private static File getFile(Config id) {
b4dc6ab5
NR
481 return getFile(config.getString(id));
482 }
483
484 /**
485 * Return a path, but support the special $HOME variable.
486 *
487 * @return the path
488 */
489 private static File getFile(UiConfig id) {
490 return getFile(uiconfig.getString(id));
491 }
492
493 /**
494 * Return a path, but support the special $HOME variable.
495 *
496 * @return the path
497 */
498 private static File getFile(String path) {
08fe2e33 499 File file = null;
08fe2e33
NR
500 if (path != null && !path.isEmpty()) {
501 path = path.replace('/', File.separatorChar);
502 if (path.contains("$HOME")) {
ae78e517 503 path = path.replace("$HOME", getHome());
08fe2e33
NR
504 }
505
506 file = new File(path);
507 }
508
509 return file;
510 }
511
ae78e517
NR
512 /**
513 * Return the home directory from the system properties.
514 *
515 * @return the home
516 */
517 private static String getHome() {
b4f9071c
NR
518 String home = System.getProperty("fanfix.home");
519 if (home != null && new File(home).isFile()) {
520 home = null;
521 }
522
523 if (home == null || home.trim().isEmpty()) {
524 home = System.getProperty("user.home");
525 if (!new File(home).isDirectory()) {
526 home = null;
527 }
528 }
529
ae78e517
NR
530 if (home == null || home.trim().isEmpty()) {
531 home = System.getProperty("java.io.tmpdir");
b4f9071c
NR
532 if (!new File(home).isDirectory()) {
533 home = null;
534 }
ae78e517
NR
535 }
536
537 if (home == null) {
538 home = "";
539 }
540
541 return home;
542 }
543
08fe2e33
NR
544 /**
545 * The language to use for the application (NULL = default system language).
546 *
547 * @return the language
548 */
549 private static String getLang() {
550 String lang = config.getString(Config.LANG);
551
fee80815
NR
552 if (lang == null | lang.isEmpty()) {
553 if (System.getenv("LANG") != null
554 && !System.getenv("LANG").isEmpty()) {
555 lang = System.getenv("LANG");
556 }
08fe2e33
NR
557 }
558
559 if (lang != null && lang.isEmpty()) {
560 lang = null;
561 }
562
563 return lang;
564 }
d0114000
NR
565
566 /**
567 * Check that the given environment variable is "enabled".
568 *
569 * @param key
570 * the variable to check
571 *
572 * @return TRUE if it is
573 */
574 private static boolean checkEnv(String key) {
575 String value = System.getenv(key);
576 if (value != null) {
577 value = value.trim().toLowerCase();
578 if ("yes".equals(value) || "true".equals(value)
579 || "on".equals(value) || "1".equals(value)
580 || "y".equals(value)) {
581 return true;
582 }
583 }
584
585 return false;
586 }
08fe2e33 587}