package org.openlca.app.editors.lcia_methods;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.FilenameUtils;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
import org.geotools.data.DataStore;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.map.FeatureLayer;
import org.geotools.map.Layer;
import org.geotools.map.MapContent;
import org.geotools.styling.SLD;
import org.geotools.styling.Style;
import org.geotools.swt.SwtMapFrame;
import org.opengis.feature.Property;
import org.opengis.feature.simple.SimpleFeature;
import org.openlca.app.db.Database;
import org.openlca.app.db.DatabaseDir;
import org.openlca.app.util.UI;
import org.openlca.core.database.FileStore;
import org.openlca.core.model.ImpactMethod;
import org.openlca.core.model.descriptors.ImpactMethodDescriptor;
import org.openlca.geo.kml.FeatureType;
import org.openlca.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.io.Files;
import com.google.gson.Gson;
import com.vividsolutions.jts.geom.LineString;
public class ShapeFileUtils {
/**
* Get the folder where the shape-files are stored for the given LCIA,
* method.
*/
public static File getFolder(ImpactMethod method) {
if (method == null || method.getRefId() == null)
return null;
return DatabaseDir.getDir(method);
}
/**
* Get the folder where the shape-files are stored for the given LCIA,
* method.
*/
public static File getFolder(ImpactMethodDescriptor method) {
if (method == null || method.getRefId() == null)
return null;
return new FileStore(Database.get()).getFolder(method);
}
/**
* Check if the mandatory files that define the shape-file are available
* (see http://en.wikipedia.org/wiki/Shapefile).
*/
static boolean isValid(File shapeFile) {
if (shapeFile == null)
return false;
if (!shapeFile.exists())
return false;
String fileName = shapeFile.getName();
if (!FilenameUtils.isExtension(fileName, "shp"))
return false;
String rawName = FilenameUtils.removeExtension(fileName);
File folder = shapeFile.getParentFile();
String[] mandatoryExtensions = { ".shx", ".dbf" };
for (String ext : mandatoryExtensions) {
File file = new File(folder, rawName + ext);
if (!file.exists())
return false;
}
return true;
}
/**
* Returns true if a shape-file with the given name already exists for the
* given method.
*/
static boolean alreadyExists(ImpactMethod method, File shapeFile) {
File folder = getFolder(method);
if (folder == null || !folder.exists())
return false;
File localFile = new File(folder, shapeFile.getName());
return localFile.exists();
}
/**
* Imports the given shape-file and the associated files into the folder for
* the given impact method.
*/
static String importFile(ImpactMethod method, File shapeFile)
throws Exception {
File methodFolder = getFolder(method);
if (!methodFolder.exists())
methodFolder.mkdirs();
List<File> importFiles = getAllFiles(shapeFile);
for (File importFile : importFiles) {
File file = new File(methodFolder, importFile.getName());
Files.copy(importFile, file);
}
String shapeFileName = FilenameUtils.removeExtension(shapeFile
.getName());
DataStore dataStore = openDataStore(method, shapeFileName);
Collection<ShapeFileParameter> params = readParameters(dataStore);
writeParameters(method, shapeFileName, params);
dataStore.dispose();
return shapeFileName;
}
/**
* Get all related files of the given shape-file including the given file
* itself.
*/
private static List<File> getAllFiles(File shapeFile) {
if (shapeFile == null || !shapeFile.exists())
return Collections.emptyList();
String rawName = FilenameUtils.removeExtension(shapeFile.getName());
File folder = shapeFile.getParentFile();
List<File> files = new ArrayList<>();
for (File file : folder.listFiles()) {
String fName = FilenameUtils.removeExtension(file.getName());
if (Strings.nullOrEqual(rawName, fName))
if (!file.isDirectory())
files.add(file);
else {
for (File file2 : file.listFiles())
files.add(file2);
files.add(file);
}
}
return files;
}
/**
* Returns the names of the shape-files of the given method (without file
* extension).
*/
public static List<String> getShapeFiles(ImpactMethod method) {
File folder = getFolder(method);
return getShapeFiles(folder);
}
/**
* Returns the names of the shape-files of the given method (without file
* extension).
*/
public static List<String> getShapeFiles(ImpactMethodDescriptor method) {
File folder = getFolder(method);
return getShapeFiles(folder);
}
private static List<String> getShapeFiles(File folder) {
if (folder == null || !folder.exists())
return Collections.emptyList();
List<String> files = new ArrayList<>();
for (File file : folder.listFiles()) {
String fileName = file.getName();
if (FilenameUtils.isExtension(fileName, "shp"))
files.add(FilenameUtils.removeExtension(fileName));
}
Collections.sort(files);
return files;
}
/**
* Delete the shape-file with the given name (without file extension) from
* the folder of the given LCIA method.
*/
static void deleteFile(ImpactMethod method, String shapeFileName) {
File folder = getFolder(method);
if (folder == null || !folder.exists())
return;
File shapeFile = new File(folder, shapeFileName + ".shp");
List<File> files = getAllFiles(shapeFile);
for (File file : files) {
boolean b = file.delete();
if (!b) {
file.deleteOnExit();
}
}
}
public static List<ShapeFileParameter> getParameters(ImpactMethod method,
String shapeFileName) throws IOException {
File folder = getFolder(method);
File paramFile = new File(folder, shapeFileName + ".gisolca");
if (!paramFile.exists())
return Collections.emptyList();
try (FileInputStream is = new FileInputStream(paramFile);
InputStreamReader reader = new InputStreamReader(is, "utf-8");
BufferedReader buffer = new BufferedReader(reader)) {
Gson gson = new Gson();
ShapeFileParameter[] params = gson.fromJson(buffer,
ShapeFileParameter[].class);
List<ShapeFileParameter> list = Arrays.asList(params);
Collections.sort(list, new Comparator<ShapeFileParameter>() {
@Override
public int compare(ShapeFileParameter o1,
ShapeFileParameter o2) {
return Strings.compare(o1.getName(), o2.getName());
}
});
return list;
}
}
private static void writeParameters(ImpactMethod method,
String shapeFileName, Collection<ShapeFileParameter> parameters)
throws IOException {
File folder = getFolder(method);
if (!folder.exists())
folder.mkdirs();
File paramFile = new File(folder, shapeFileName + ".gisolca");
try (FileOutputStream os = new FileOutputStream(paramFile);
OutputStreamWriter writer = new OutputStreamWriter(os, "utf-8");
BufferedWriter buffer = new BufferedWriter(writer)) {
Gson gson = new Gson();
gson.toJson(parameters, buffer);
}
}
static void openFileInMap(ImpactMethod method, String shapeFileName) {
openFileInMap(method, shapeFileName, null);
}
static void openFileInMap(ImpactMethod method, String shapeFileName,
ShapeFileParameter parameter) {
DataStore dataStore = openDataStore(method, shapeFileName);
if (dataStore == null)
return;
Logger log = LoggerFactory.getLogger(ShapeFileUtils.class);
try {
SimpleFeatureCollection source = dataStore.getFeatureSource(
dataStore.getTypeNames()[0]).getFeatures();
SimpleFeatureIterator it = source.features();
if (it.hasNext()) {
Object type = it.next().getDefaultGeometry();
FeatureType fType = FeatureType.POLYGON;
if (type instanceof com.vividsolutions.jts.geom.Point)
fType = FeatureType.POINT;
else if (type instanceof LineString)
fType = FeatureType.LINE;
Style style = SLD.createSimpleStyle(source.getSchema());
if (parameter != null && fType != FeatureType.POINT)
style = ShapeFileStyle.create(dataStore, parameter, fType);
showMapFrame(shapeFileName, source, style);
}
it.close();
} catch (Exception e) {
log.error("Failed to open shape-file", e);
} finally {
dataStore.dispose();
}
}
private static void showMapFrame(String shapeFileName,
SimpleFeatureCollection source, Style style) {
MapContent mapContent = new MapContent();
mapContent.setTitle("Features of " + shapeFileName);
Layer layer = new FeatureLayer(source, style);
mapContent.addLayer(layer);
SwtMapFrame frame = createMapFrame(mapContent);
frame.setBlockOnOpen(true);
frame.open();
}
private static SwtMapFrame createMapFrame(MapContent mapContent) {
boolean showMenu = false;
boolean showToolBar = true;
boolean showStatusBar = false;
boolean showLayerTable = false;
return new SwtMapFrame(showMenu, showToolBar, showStatusBar,
showLayerTable, mapContent) {
@Override
protected Control createContents(Composite parent) {
Control control = super.createContents(parent);
Shell shell = getShell();
Shell parentShell = UI.shell();
if (shell != null && parentShell != null) {
Point parentSize = parentShell.getSize();
shell.setSize((int) (parentSize.x * 0.7),
(int) (parentSize.y * 0.7));
UI.center(parentShell, shell);
}
return control;
}
};
}
private static DataStore openDataStore(ImpactMethod method,
String shapeFileName) {
File folder = ShapeFileUtils.getFolder(method);
if (folder == null)
return null;
Logger log = LoggerFactory.getLogger(ShapeFileUtils.class);
try {
File file = new File(folder, shapeFileName + ".shp");
log.trace("open shape-file in map: {}", file);
return new ShapefileDataStore(file.toURI().toURL());
} catch (Exception e) {
log.error("Failed to open shape-file", e);
return null;
}
}
private static Collection<ShapeFileParameter> readParameters(
DataStore dataStore) {
if (dataStore == null)
return Collections.emptyList();
Logger log = LoggerFactory.getLogger(ShapeFileUtils.class);
try {
Map<String, ShapeFileParameter> params = new HashMap<>();
String typeName = dataStore.getTypeNames()[0];
SimpleFeatureCollection source = dataStore.getFeatureSource(
typeName).getFeatures();
SimpleFeatureIterator it = source.features();
while (it.hasNext()) {
SimpleFeature feature = it.next();
readParameters(params, feature);
}
it.close();
return params.values();
} catch (Exception e) {
log.error("failed to get parameters from shape file", e);
return Collections.emptyList();
}
}
private static void readParameters(Map<String, ShapeFileParameter> params,
SimpleFeature feature) {
for (Property property : feature.getProperties()) {
if (!(property.getValue() instanceof Number))
continue;
if (property.getName() == null)
continue;
String name = property.getName().toString();
double value = ((Number) property.getValue()).doubleValue();
ShapeFileParameter param = params.get(name);
if (param == null) {
param = new ShapeFileParameter();
param.setName(name);
param.setMax(value);
param.setMin(value);
params.put(name, param);
} else {
param.setMax(Math.max(param.getMax(), value));
param.setMin(Math.min(param.getMin(), value));
}
}
}
}