initial commit
[meviz.git] / src / main / java / eu / svjatoslav / meviz / htmlindexer / FilesystemIndexer.java
1 /*
2  * Meviz - Various tools collection to work with multimedia.
3  * Copyright (C) 2012, Svjatoslav Agejenko, svjatoslav@svjatoslav.eu
4  * 
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of version 2 of the GNU General Public License
7  * as published by the Free Software Foundation.
8  */
9
10 package eu.svjatoslav.meviz.htmlindexer;
11
12 import java.io.BufferedReader;
13 import java.io.File;
14 import java.io.FileNotFoundException;
15 import java.io.FileReader;
16 import java.io.IOException;
17 import java.io.UnsupportedEncodingException;
18 import java.util.HashSet;
19
20 import org.apache.log4j.Logger;
21
22 import eu.svjatoslav.commons.file.IOHelper;
23 import eu.svjatoslav.meviz.htmlindexer.layouts.MixedLayout;
24 import eu.svjatoslav.meviz.htmlindexer.metadata.Dimension;
25 import eu.svjatoslav.meviz.htmlindexer.metadata.DirectoryMetadata;
26 import eu.svjatoslav.meviz.htmlindexer.metadata.MetadadaHelper;
27 import eu.svjatoslav.meviz.htmlindexer.metadata.fileTypes.AbstractFile;
28 import eu.svjatoslav.meviz.htmlindexer.metadata.fileTypes.DirectoryFile;
29 import eu.svjatoslav.meviz.htmlindexer.metadata.fileTypes.GeneralFile;
30 import eu.svjatoslav.meviz.htmlindexer.metadata.fileTypes.Picture;
31
32 /**
33  * Main class of HTML indexer.
34  */
35
36 public class FilesystemIndexer extends AbstractIndexer {
37
38         public static final Logger logger = Logger
39                         .getLogger(FilesystemIndexer.class);
40
41         private final HashSet<String> validMetadataFiles = new HashSet<String>();
42
43         private final File directoryToIndex;
44
45         private String thumbnailsPath;
46
47         private File metadataFile;
48
49         private DirectoryMetadata metadata;
50
51         private final IndexingOptions indexingOptions;
52
53         private final String[] pathElements;
54
55         private HashSet<Layout> layouts;
56
57         public FilesystemIndexer(final File directoryToIndex,
58                         final IndexingOptions indexingOptions, final String[] pathElements)
59                         throws IOException, ImageFormatError {
60
61                 this.directoryToIndex = directoryToIndex;
62                 this.indexingOptions = indexingOptions;
63                 this.pathElements = pathElements;
64
65                 if (!directoryToIndex.canRead())
66                         return;
67
68                 validMetadataFiles.add(Constants.METADATA_FILE_NAME);
69
70                 initializeThumbnailsDirectory();
71                 loadOrCreateMetadata();
72
73                 initializeLayouts();
74
75                 updateMetadata();
76
77                 metadata.removeUnusedMetadataEntries();
78
79                 generateHtmlFromMetadata(layouts);
80
81                 removeUnusedThumbnailFiles();
82
83                 // save directory metadata
84                 if (metadata.changed)
85                         MetadadaHelper.saveDirectoryMetadata(metadataFile, metadata);
86
87         }
88
89         public boolean canWriteIndexFile(final File indexFile)
90                         throws FileNotFoundException, IOException {
91                 boolean canWriteIndexFile = false;
92
93                 if (indexFile.exists()) {
94                         // if file already exists, make sure that we can overwrite
95                         // it
96                         final FileReader fileReader = new FileReader(indexFile);
97                         final BufferedReader reader = new BufferedReader(fileReader);
98
99                         parseFile: {
100                                 while (true) {
101                                         final String line = reader.readLine();
102
103                                         if (line == null)
104                                                 break parseFile;
105
106                                         if (line.contains(Constants.HTML_MAGIC_STRING)) {
107                                                 canWriteIndexFile = true;
108                                                 break parseFile;
109                                         }
110                                 }
111                         }
112
113                         reader.close();
114                         fileReader.close();
115                 } else
116                         canWriteIndexFile = true;
117                 return canWriteIndexFile;
118         }
119
120         public void cleanupUnusedMetadataFiles() {
121                 final File thumbnailsDirectory = new File(thumbnailsPath);
122
123                 for (final File file : thumbnailsDirectory.listFiles())
124                         if (!validMetadataFiles.contains(file.getName()))
125                                 file.delete();
126         }
127
128         public void generateHtmlFromMetadata(final HashSet<Layout> layouts) {
129                 // Generate HTML from metadata
130                 for (final Layout layout : layouts) {
131
132                         final String indexFilePath = directoryToIndex.getAbsolutePath()
133                                         + "/index" + layout.getFileNameSuffix() + ".html";
134
135                         try {
136
137                                 final File indexFile = new File(indexFilePath);
138                                 if (canWriteIndexFile(indexFile)) {
139
140                                         indexForLayout(layout);
141
142                                         IOHelper.overwriteFileIfContentDiffers(indexFile, layout
143                                                         .getHtml().getBytes());
144                                 }
145                         } catch (final Exception e) {
146                                 logger.error("Error writing index file to:" + indexFilePath, e);
147                         }
148                 }
149         }
150
151         public String[] getSubPath(final File file) {
152
153                 final String[] subPath = new String[pathElements.length + 1];
154
155                 for (int i = 0; i < pathElements.length; i++)
156                         subPath[i] = pathElements[i];
157
158                 subPath[pathElements.length] = file.getName();
159                 return subPath;
160         }
161
162         @Override
163         public String getThumbnailPath(final Picture picture,
164                         final Dimension desiredDimension) {
165
166                 // in case thumbnail size was equal to original, then return original
167                 // file path
168                 if (picture.getDimensions().equals(desiredDimension))
169                         return picture.fileName;
170
171                 final String thumbnailFileName = picture
172                                 .getRelativeThumbnailFileName(desiredDimension);
173
174                 validMetadataFiles.add(thumbnailFileName);
175                 final File thumbnailFile = new File(thumbnailsPath + thumbnailFileName);
176
177                 if (!thumbnailFile.exists()) {
178
179                         final File originalFile = new File(
180                                         directoryToIndex.getAbsolutePath() + "/" + picture.fileName);
181
182                         // generate new thumbnail
183                         Picture.makeThumbnail(originalFile, thumbnailFile,
184                                         desiredDimension.getAwtDimension());
185                 }
186                 return Constants.THUMBNAILS_DIRECTORY_NAME + "/" + thumbnailFileName;
187         }
188
189         public void indexForLayout(final Layout layout)
190                         throws UnsupportedEncodingException {
191
192                 for (final AbstractFile abstractFile : metadata.getFiles())
193                         if (abstractFile instanceof GeneralFile) {
194
195                                 if (isOgv(abstractFile.getFileExtension()))
196                                         layout.enlistOgv(abstractFile);
197                                 else
198                                         layout.enlistFile(abstractFile);
199
200                         } else if (abstractFile instanceof Picture)
201                                 layout.enlistImage(abstractFile);
202                         else if (abstractFile instanceof DirectoryFile)
203                                 layout.enlistDirectory(abstractFile);
204
205         }
206
207         public void initializeLayouts() {
208                 layouts = new HashSet<Layout>();
209                 layouts.add(new MixedLayout());
210
211                 for (final Layout layout : layouts)
212                         layout.init(indexingOptions.galleryTitle, pathElements, this);
213         }
214
215         public void initializeThumbnailsDirectory() {
216                 // initialize thumbnails directory
217                 thumbnailsPath = directoryToIndex.getAbsolutePath() + "/"
218                                 + Constants.THUMBNAILS_DIRECTORY_NAME + "/";
219
220                 // ensure thumbnails directory exists
221                 final File thumbnailsDirectory = new File(thumbnailsPath);
222                 if (!thumbnailsDirectory.exists())
223                         thumbnailsDirectory.mkdirs();
224         }
225
226         public void loadOrCreateMetadata() {
227                 metadataFile = new File(thumbnailsPath + Constants.METADATA_FILE_NAME);
228
229                 metadata = MetadadaHelper.initDirectoryMetadata(metadataFile);
230         }
231
232         private void removeUnusedThumbnailFiles() {
233
234                 final File thumbnailsDirectory = new File(thumbnailsPath);
235
236                 for (final File file : thumbnailsDirectory.listFiles())
237                         if (!validMetadataFiles.contains(file.getName()))
238                                 file.delete();
239
240         }
241
242         public void updateMetadata() throws IOException, ImageFormatError {
243
244                 final File[] directoryContent = directoryToIndex.listFiles();
245
246                 for (final File file : directoryContent)
247                         if (shallFileBeIndexed(file)) {
248
249                                 metadata.ensureFileMetainfoIsUpToDate(directoryToIndex, file);
250
251                                 if (file.isDirectory())
252                                         new FilesystemIndexer(file, indexingOptions,
253                                                         getSubPath(file));
254                         }
255         }
256 }