package org.wikibrain.spatial.loader;
import com.google.common.collect.Sets;
import org.apache.commons.io.FileUtils;
import org.wikibrain.conf.Configuration;
import org.wikibrain.core.WikiBrainException;
import org.wikibrain.spatial.WikiBrainShapeFile;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Convenience class to deal with spatial data folder structure. Structure is as follows:
*
* Each reference system has its own folder (will ignore any reference system that starts with '_'
* Each layerGroup has its own subdirectory
* Shapefiles that are placed in each folder will be loaded for the same layer
*
* For example: baseFolder/earth/country/naturalEarth.shp
*
* @author bjhecht and shilad
*/
public class SpatialDataFolder {
private final File baseFolder;
/**
* Will create the folder if it does not exist. By default, installs an empty "earth" reference system if "earth" reference system does not exist
* @param baseFolder
*/
public SpatialDataFolder(File baseFolder){
this.baseFolder = baseFolder;
if (!baseFolder.exists()){
baseFolder.mkdirs();
}
}
/**
* Returns true of spatial data folder has a given layer
* @param layerGroup
* @param refSysName
* @return
*/
public boolean hasLayerGroup(String refSysName, String layerGroup) {
return !getFilesInLayerGroup(refSysName, layerGroup).isEmpty();
}
public File getRawFolder() {
return FileUtils.getFile(baseFolder, "_raw");
}
public WikiBrainShapeFile getShapeFile(String refSys, String layerGroup, String name) {
return new WikiBrainShapeFile(FileUtils.getFile(baseFolder, refSys, layerGroup, name + ".shp"));
}
public WikiBrainShapeFile getShapeFile(String refSys, String layerGroup, String name, String encoding) {
return new WikiBrainShapeFile(FileUtils.getFile(baseFolder, refSys, layerGroup, name + ".shp"), encoding);
}
/**
* Returns true if the spatial data folder has a reference system
* @param refSysName
* @return
*/
public boolean hasReferenceSystem(String refSysName){
File refFolder = getReferenceSystemFolder(refSysName);
return isImportantFile(refFolder) && !getLayerGroups(refSysName).isEmpty();
}
/**
* Returns the file for the given reference system
* @return
* @param refSysName
*/
public File getReferenceSystemFolder(String refSysName) {
return FileUtils.getFile(baseFolder, refSysName);
}
/**
* Returns the directory for the given reference system and layer
* @param refSys e.g. "earth"
* @param layerGroup e.g. "country"
* @return
*/
public File getLayerGroupFolder(String refSys, String layerGroup) {
return FileUtils.getFile(baseFolder, refSys, layerGroup);
}
/**
* Deletes a reference system. Use with caution!
* @param refSysName
* @throws FileNotFoundException
*/
public void deleteReferenceSystem(String refSysName) throws FileNotFoundException{
FileUtils.deleteQuietly(getReferenceSystemFolder(refSysName));
}
/**
* Gets reference system names
*/
public Set<String> getReferenceSystems(){
Set<String> rVal = Sets.newHashSet();
for (File refFolder : baseFolder.listFiles()){
String refSysName = refFolder.getName();
if (hasReferenceSystem(refSysName)) {
rVal.add(refSysName);
}
}
return rVal;
}
private static boolean isImportantFile(File file) {
return file.exists() && !file.isHidden() && !file.getName().startsWith("_");
}
public Set<String> getLayerGroups(String refSysName) {
Set<String> layerGroups = new HashSet<String>();
for (File file : getReferenceSystemFolder(refSysName).listFiles()) {
String layerGroup = file.getName();
if (isImportantFile(file) && !getFilesInLayerGroup(refSysName, layerGroup).isEmpty()) {
layerGroups.add(layerGroup);
}
}
return layerGroups;
}
/**
* Deletes a layer. Use with caution.
* @param refSysName Reference system of layer to delete
* @param layerGroup Layer to delete
* @throws WikiBrainException
*/
public void deleteLayer(String refSysName, String layerGroup) throws WikiBrainException {
FileUtils.deleteQuietly(FileUtils.getFile(baseFolder, refSysName, layerGroup));
}
public List<WikiBrainShapeFile> getFilesInLayerGroup(String refSysName, String layerName) {
List<WikiBrainShapeFile> shapeFiles = new ArrayList<WikiBrainShapeFile>();
for (File file : getLayerGroupFolder(refSysName, layerName).listFiles()) {
if (isImportantFile(file) && file.toString().toLowerCase().endsWith(".shp")) {
shapeFiles.add(new WikiBrainShapeFile(file));
}
}
return shapeFiles;
}
/**
* Hack: Better to ask the configurator for this!
* @param conf
* @return
*/
public static SpatialDataFolder get(Configuration conf) {
return new SpatialDataFolder(conf.getFile("spatial.dir"));
}
}