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