ea6489ec15e4b872d755226518a5dbb5c4bc54fc
[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         @Override
152         public String getDirectoryUrl(final AbstractFile directory) {
153                 return directory.fileName + "/index.html";
154         }
155
156         public String[] getSubPath(final File file) {
157
158                 final String[] subPath = new String[pathElements.length + 1];
159
160                 for (int i = 0; i < pathElements.length; i++)
161                         subPath[i] = pathElements[i];
162
163                 subPath[pathElements.length] = file.getName();
164                 return subPath;
165         }
166
167         @Override
168         public String getThumbnailPath(final Picture picture,
169                         final Dimension desiredDimension) {
170
171                 // in case thumbnail size was equal to original, then return original
172                 // file path
173                 if (picture.getDimensions().equals(desiredDimension))
174                         return picture.fileName;
175
176                 final String thumbnailFileName = picture
177                                 .getRelativeThumbnailFileName(desiredDimension);
178
179                 validMetadataFiles.add(thumbnailFileName);
180                 final File thumbnailFile = new File(thumbnailsPath + thumbnailFileName);
181
182                 if (!thumbnailFile.exists()) {
183
184                         final File originalFile = new File(
185                                         directoryToIndex.getAbsolutePath() + "/" + picture.fileName);
186
187                         // generate new thumbnail
188                         Picture.makeThumbnail(originalFile, thumbnailFile,
189                                         desiredDimension.getAwtDimension());
190                 }
191                 return Constants.THUMBNAILS_DIRECTORY_NAME + "/" + thumbnailFileName;
192         }
193
194         public void indexForLayout(final Layout layout)
195                         throws UnsupportedEncodingException {
196
197                 for (final AbstractFile abstractFile : metadata.getFiles())
198                         if (abstractFile instanceof GeneralFile) {
199
200                                 if (isOgv(abstractFile.getFileExtension()))
201                                         layout.enlistOgv(abstractFile);
202                                 else
203                                         layout.enlistFile(abstractFile);
204
205                         } else if (abstractFile instanceof Picture)
206                                 layout.enlistImage(abstractFile);
207                         else if (abstractFile instanceof DirectoryFile)
208                                 layout.enlistDirectory(abstractFile);
209
210         }
211
212         public void initializeLayouts() {
213                 layouts = new HashSet<Layout>();
214                 layouts.add(new MixedLayout());
215
216                 for (final Layout layout : layouts)
217                         layout.init(indexingOptions.galleryTitle, pathElements, this, "");
218         }
219
220         public void initializeThumbnailsDirectory() {
221                 // initialize thumbnails directory
222                 thumbnailsPath = directoryToIndex.getAbsolutePath() + "/"
223                                 + Constants.THUMBNAILS_DIRECTORY_NAME + "/";
224
225                 // ensure thumbnails directory exists
226                 final File thumbnailsDirectory = new File(thumbnailsPath);
227                 if (!thumbnailsDirectory.exists())
228                         thumbnailsDirectory.mkdirs();
229         }
230
231         public void loadOrCreateMetadata() {
232                 metadataFile = new File(thumbnailsPath + Constants.METADATA_FILE_NAME);
233
234                 metadata = MetadadaHelper.initDirectoryMetadata(metadataFile);
235         }
236
237         private void removeUnusedThumbnailFiles() {
238
239                 final File thumbnailsDirectory = new File(thumbnailsPath);
240
241                 for (final File file : thumbnailsDirectory.listFiles())
242                         if (!validMetadataFiles.contains(file.getName()))
243                                 file.delete();
244
245         }
246
247         public void updateMetadata() throws IOException, ImageFormatError {
248
249                 final File[] directoryContent = directoryToIndex.listFiles();
250
251                 for (final File file : directoryContent)
252                         if (shallFileBeIndexed(file)) {
253
254                                 metadata.ensureFileMetainfoIsUpToDate(directoryToIndex, file);
255
256                                 if (file.isDirectory())
257                                         new FilesystemIndexer(file, indexingOptions,
258                                                         getSubPath(file));
259                         }
260         }
261 }