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