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