1 /*
2  * Copyright (c) 2019 Helmut Neemann.
3  * Use of this source code is governed by the GPL v3 license
4  * that can be found in the LICENSE file.
5  */
6 package de.neemann.digital;
7 
8 import de.neemann.digital.draw.library.ElementLibrary;
9 import de.neemann.digital.gui.FileHistory;
10 import de.neemann.digital.gui.Main;
11 import org.slf4j.Logger;
12 import org.slf4j.LoggerFactory;
13 
14 import java.io.File;
15 
16 /**
17  * Helper to find a file if only the filename is known.
18  */
19 public class FileLocator {
20     private static final Logger LOGGER = LoggerFactory.getLogger(FileLocator.class);
21     private static final int MAX_FILE_COUNTER = 5000;
22 
23     private final String filename;
24     private File file;
25     private FileHistory history;
26     private ElementLibrary library;
27     private File baseFile;
28     private int fileCounter;
29 
30 
31     /**
32      * Creates a new instance
33      *
34      * @param file the file to search for
35      */
FileLocator(File file)36     public FileLocator(File file) {
37         this(file == null ? null : file.getName());
38         this.file = file;
39     }
40 
41     /**
42      * Creates a new instance
43      *
44      * @param filename the file name
45      */
FileLocator(String filename)46     public FileLocator(String filename) {
47         this.filename = filename;
48     }
49 
50     /**
51      * Sets the relevant file history
52      *
53      * @param history the file history
54      * @return this for chained calls
55      */
setHistory(FileHistory history)56     public FileLocator setHistory(FileHistory history) {
57         this.history = history;
58         return this;
59     }
60 
61     /**
62      * Sets the used library.
63      * If called the library folder is scanned to locate the file.
64      *
65      * @param library the library
66      * @return this for chained calls
67      */
setLibrary(ElementLibrary library)68     public FileLocator setLibrary(ElementLibrary library) {
69         this.library = library;
70         return this;
71     }
72 
73     /**
74      * The base file from which the specified file name originates.
75      * Often the base file is a file with a different extension,
76      * which is located in the same directory.
77      *
78      * @param baseFile the base file
79      * @return this for chained calls
80      */
setBaseFile(File baseFile)81     public FileLocator setBaseFile(File baseFile) {
82         this.baseFile = baseFile;
83         return this;
84     }
85 
86     /**
87      * Configures the file locator with the given main
88      *
89      * @param main the main class
90      * @return this for chained calls
91      */
setupWithMain(Main main)92     public FileLocator setupWithMain(Main main) {
93         if (main != null) {
94             setBaseFile(main.getBaseFileName());
95             setLibrary(main.getLibrary());
96         }
97         return this;
98     }
99 
100     /**
101      * Tries to locate the given file.
102      *
103      * @return the file or null if not found
104      */
locate()105     public File locate() {
106         if (file != null && file.exists())
107             return file;
108 
109         if (filename == null)
110             return null;
111 
112         if (baseFile != null) {
113             File f = new File(baseFile.getParentFile(), filename);
114             if (f.isFile() && f.exists()) {
115                 LOGGER.debug(filename + " found in base file folder");
116                 return f;
117             }
118         }
119 
120         if (history != null) {
121             for (File h : history.getFiles()) {
122                 if (h.getName().equals(filename) && h.exists()) {
123                     LOGGER.debug(filename + " found in file history");
124                     return h;
125                 }
126             }
127         }
128 
129         if (library != null) {
130             final File rootFilePath = library.getRootFilePath();
131             if (rootFilePath != null) {
132                 LOGGER.debug(filename + ": start library folder lookup");
133                 fileCounter = 0;
134                 File f = search(rootFilePath);
135                 if (f != null) {
136                     LOGGER.debug(filename + " found in library folder");
137                     return f;
138                 }
139             }
140         }
141 
142         LOGGER.debug(filename + " not found");
143         return file;
144     }
145 
search(File path)146     private File search(File path) {
147         if (fileCounter > MAX_FILE_COUNTER)
148             return null;
149 
150         File[] list = path.listFiles();
151         if (list != null) {
152             for (File f : list) {
153                 if (f.isFile() && f.getName().equals(filename))
154                     return f;
155                 fileCounter++;
156             }
157             for (File f : list) {
158                 if (f.isDirectory() && !f.getName().startsWith(".")) {
159                     File af = search(f);
160                     if (af != null)
161                         return af;
162                 }
163             }
164         }
165         return null;
166     }
167 
168 }
169