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