/*
* Copyright (C) 2011 Jan Pokorsky
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package cz.cas.lib.proarc.common.imports;
import cz.cas.lib.proarc.common.imports.FileSet.FileEntry;
import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.text.Collator;
import java.text.ParseException;
import java.text.RuleBasedCollator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.TreeMap;
/**
*
* @author Jan Pokorsky
*/
public final class ImportFileScanner {
public enum State {
IMPORTED, NEW, EMPTY;
}
public static final String IMPORT_STATE_FILENAME = "proarc_import_status.log";
/** system filenames to exclude from digital content list */
private static final Set<String> EXCLUDE_FILENAMES = new HashSet<String>(Arrays.asList(
IMPORT_STATE_FILENAME,
ImportProcess.TMP_DIR_NAME
));
private static final FileFilter FOLDER_FILTER = new FileFilter() {
@Override
public boolean accept(File f) {
return f.isDirectory() && f.canRead() && f.canWrite() && !ImportProcess.TMP_DIR_NAME.equals(f.getName());
}
};
private static RuleBasedCollator createCzechCollator() {
RuleBasedCollator czechDefault = (RuleBasedCollator) Collator.getInstance(new Locale("cs"));
try {
return new RuleBasedCollator(
// Space before 0 results to "on", "on board", "online"
// instead of "on", "online", "on board"
// '&' to reset definition does not work for space
"'\u0020' < 0"
+ czechDefault.getRules());
} catch (ParseException ex) {
throw new IllegalStateException(ex);
}
}
/**
* File name comparator. It delegates to extended Czech collator implementation.
* @see <a href='http://www.docjar.com/html/api/sun/text/resources/CollationData_cs.java.html'>CollationData_cs.java</a>
* @see java.text.CollationRules
*/
private static final Comparator<File> FILE_COMPARATOR = new Comparator<File>() {
private final Comparator<Object> czech = createCzechCollator();
@Override
public int compare(File o1, File o2) {
return czech.compare(o1.getName(), o2.getName());
}
};
private static final Comparator<FileSet> FILESET_COMPARATOR = new Comparator<FileSet>() {
private final Comparator<Object> czech = createCzechCollator();
@Override
public int compare(FileSet o1, FileSet o2) {
return czech.compare(o1.getName(), o2.getName());
}
};
/**
* Finds subfolders.
*
* @param folder folder to scan
* @return list of direct subfolders
*/
public List<Folder> findSubfolders(File folder, ImportHandler importer) throws FileNotFoundException, IllegalArgumentException {
validateImportFolder(folder);
File[] listFiles = folder.listFiles(FOLDER_FILTER);
Arrays.sort(listFiles, FILE_COMPARATOR);
List<Folder> content = new ArrayList<Folder>(listFiles.length);
for (File file : listFiles) {
content.add(new Folder(file, importer));
}
return content;
}
public List<File> findDigitalContent(File folder) throws IllegalArgumentException, FileNotFoundException {
validateImportFolder(folder);
File[] files = folder.listFiles();
List<File> contents = new ArrayList<File>(files.length);
for (File file : files) {
if (file.isFile()&& file.canRead() && !EXCLUDE_FILENAMES.contains(file.getName())) {
contents.add(file);
}
}
Collections.sort(contents, FILE_COMPARATOR);
return contents;
}
public static List<FileSet> getFileSets(List<File> files) {
TreeMap<String, FileSet> items = new TreeMap<String, FileSet>(createCzechCollator());
for (File file : files) {
String filename = getName(file);
FileSet itemFiles = items.get(filename);
if (itemFiles == null) {
itemFiles = new FileSet(filename);
items.put(filename, itemFiles);
}
itemFiles.getFiles().add(new FileEntry(file));
}
return new ArrayList<FileSet>(items.values());
}
static String getName(File f) {
String fname = f.getName();
int index = fname.indexOf('.');
return index > 0 ? fname.substring(0, index) : fname;
}
static void validateImportFolder(File folder) throws FileNotFoundException, IllegalArgumentException {
if (!folder.exists()) {
throw new FileNotFoundException(folder.toString());
}
if (!folder.isDirectory()) {
throw new IllegalArgumentException("FILE_IS_NOT_DIRECTORY");
}
if (!(folder.canRead() && folder.canWrite())) {
throw new IllegalArgumentException("FILE_INSUFFICIENT_ACCESS_PERMISSIONS");
}
}
static State folderImportState(File folder, ImportHandler importer) {
State state = isImported(folder) ? State.IMPORTED : State.NEW;
// check file content for more details
if (state == State.NEW) {
state = importer.isImportable(folder) ? State.NEW : State.EMPTY;
}
return state;
}
static boolean isImported(File folder) {
File stateFile = new File(folder, IMPORT_STATE_FILENAME);
return stateFile.exists();
}
static void rollback(File folder) {
File stateFile = new File(folder, IMPORT_STATE_FILENAME);
stateFile.delete();
}
public static final class Folder {
private File handle;
private State status;
private transient ImportHandler importer;
private Folder(File handle, ImportHandler importer) {
this.handle = handle;
this.importer = importer;
}
public File getHandle() {
return handle;
}
public State getStatus() {
if (status == null) {
status = folderImportState(handle, importer);
}
return status;
}
}
}