package es.axios.so.extension.copy;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import net.refractions.udig.catalog.ICatalog;
import net.refractions.udig.catalog.IGeoResource;
import net.refractions.udig.project.ILayer;
import net.refractions.udig.project.IMap;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.geotools.data.DataUtilities;
import org.geotools.data.FeatureStore;
import org.geotools.data.Transaction;
import org.geotools.feature.Feature;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.geotools.feature.FeatureType;
import org.geotools.feature.GeometryAttributeType;
import org.geotools.feature.IllegalAttributeException;
import org.geotools.feature.SchemaException;
import org.geotools.filter.Filter;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.OperationNotFoundException;
import org.opengis.referencing.operation.TransformException;
import com.vividsolutions.jts.geom.Geometry;
import es.axios.udig.spatialoperations.tasks.SpatialOperationException;
import es.axios.udig.spatialoperations.ui.taskmanager.SOFeatureStore;
import es.axios.udig.ui.commons.mediator.AppGISMediator;
import es.axios.udig.ui.commons.util.FeatureUtil;
import es.axios.udig.ui.commons.util.GeoToolsUtils;
import es.axios.udig.ui.commons.util.GeometryUtil;
import es.axios.udig.ui.commons.util.LayerUtil;
public class CopyTask {
private Filter filter = null;
private CoordinateReferenceSystem mapCrs = null;
private ILayer sourceLayer = null;
private String targetLayerName = null;
private Class<? extends Geometry> targetGeom = null;
private ILayer targetLayer = null;
private FeatureStore targetStore = null;
private FeatureCollection featuresFromSource = null;
private CoordinateReferenceSystem sourceLayerCrs = null;
private String oldfidAttributeName = "OLDFID";
private int count = 0;
/**
* set parameters
*
* @param filter
* @param mapCrs
* @param sourceLayer
* @param targetLayerName
* @param targetGeometryClass
* @throws IOException
*/
public void setParameters( Filter filter,
CoordinateReferenceSystem mapCrs,
ILayer sourceLayer,
String targetLayerName,
Class<? extends Geometry> targetGeometryClass) throws IOException {
this.filter = filter;
this.mapCrs = mapCrs;
this.sourceLayer = sourceLayer;
this.targetLayerName = targetLayerName;
this.targetGeom = targetGeometryClass;
}
/**
* set parameters
*
* @param filter
* @param mapCrs
* @param sourceLayer
* @param targetLayer
* @throws IOException
*/
public void setParameters(Filter filter, CoordinateReferenceSystem mapCrs, ILayer sourceLayer, ILayer targetLayer)
throws IOException {
this.filter = filter;
this.mapCrs = mapCrs;
this.sourceLayer = sourceLayer;
this.targetLayer = targetLayer;
}
/**
* Convert the object into geotools objects. This will go on the monitor.
*
* @throws IOException
* @throws SchemaException
*/
public void convertToGeotools() throws IOException, SchemaException {
this.sourceLayerCrs = LayerUtil.getCrs(this.sourceLayer);
this.featuresFromSource = LayerUtil.getSelectedFeatures(sourceLayer, filter);
targetStore = getTargetStore();
}
/**
* Method copied from a Monitor.
*
* @return
* @throws SchemaException
* @throws IOException
*/
private FeatureStore getTargetStore() throws SchemaException, IOException {
FeatureStore targetStore = null;
if (this.targetLayer != null) {
targetStore = getFeatureStore(targetLayer);
} else {
FeatureType type = FeatureUtil.createFeatureType(this.sourceLayer.getSchema(), targetLayerName, mapCrs,
targetGeom);
oldfidAttributeName = "OLDFID";
// By default the attribute will be of the String class.
type = FeatureUtil.addAttributeToFeatureType(type, oldfidAttributeName, String.class);
IGeoResource targetGeoResource = AppGISMediator.createTempGeoResource(type);
assert targetGeoResource != null;
NullProgressMonitor progress = new NullProgressMonitor();
targetStore = targetGeoResource.resolve(FeatureStore.class, progress);
this.targetLayer = addLayerToMap(getMap(), targetGeoResource);
}
return targetStore;
}
/**
* * Method copied from a Monitor.
*
* @return
*/
private IMap getMap() {
IMap map = this.sourceLayer.getMap();
assert map != null;
return map;
}
/**
* * Method copied from a Monitor.
*
* @param map
* @param geoResource
* @return
*/
protected ILayer addLayerToMap(IMap map, IGeoResource geoResource) {
int index = map.getMapLayers().size();
List<? extends ILayer> listLayer = AppGISMediator.addLayersToMap(map, Collections.singletonList(geoResource),
index);
assert listLayer.size() == 1; // creates only one layer
ILayer layer = listLayer.get(0);
return layer;
}
private FeatureStore getFeatureStore(ILayer layer) throws IOException {
assert layer != null;
FeatureType featureType = layer.getSchema();
IGeoResource resource = layer.getGeoResource();
if (resource == null) {
// new resource is required because new layer was selected
final ICatalog catalog = AppGISMediator.getCatalog();
assert catalog != null;
resource = catalog.createTemporaryResource(featureType);
}
final FeatureStore targetStore;
targetStore = resource.resolve(FeatureStore.class, new NullProgressMonitor());
SOFeatureStore store = new SOFeatureStore(targetStore, targetStore.getTransaction());
return store;
}
public void refreshTargetLayer() {
targetLayer.refresh(null);
}
/***************************************************************************
*
* <pre>
* Code before this goes to CopyMonitor
* Code after that goes to CopyTask
* </pre>
*
*
*
*
*/
public void execute() {
FeatureIterator iter = null;
Feature featureToCopy = null;
try {
count = 0;
iter = featuresFromSource.features();
FeatureType featureType = this.targetStore.getSchema();
CoordinateReferenceSystem targetLayerCrs = featureType.getDefaultGeometry().getCoordinateSystem();
if (targetLayerCrs == null) {
targetLayerCrs = mapCrs;
}
while (iter.hasNext() && count < 110) {
featureToCopy = iter.next();
long ini = System.currentTimeMillis();
copyFeature(featureToCopy, targetLayerCrs, featureType);
long end = System.currentTimeMillis();
System.out.println("Total: " + (end - ini)); //$NON-NLS-1$
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (iter != null) {
featuresFromSource.close(iter);
}
}
}
private void copyFeature(Feature featureToCopy, CoordinateReferenceSystem targetLayerCrs, FeatureType featureType)
throws OperationNotFoundException, TransformException, IllegalAttributeException, SpatialOperationException {
Geometry baseGeometry = featureToCopy.getDefaultGeometry();
Geometry baseGeomOnMapCrs = GeoToolsUtils.reproject(baseGeometry, sourceLayerCrs, targetLayerCrs);
Feature copiedFeature = copyFeature(featureToCopy, featureType, baseGeomOnMapCrs,
oldfidAttributeName);
insert(copiedFeature);
}
private void insert(Feature copiedFeature) throws SpatialOperationException {
Transaction transaction = targetStore.getTransaction();
try {
Set<?> newIds = targetStore.addFeatures(DataUtilities.collection(new Feature[] { copiedFeature }));
if (newIds.size() != 1) {
final String msg = "failed inserting.";
throw new SpatialOperationException(msg);
}
System.out.println(newIds.toString());
transaction.commit();
}
catch (IOException e) {
try {
transaction.rollback();
}
catch (IOException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}
finally {
try {
transaction.close();
count++;
}
catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* Function to copy a feature and add the field "oldfid" that will contain
* the ID of the original feature.
*
* @param sourceFeature
* @param targetType
* @param newGeometry
* @param oldfidAtt
* @return a New Feature
* @throws IllegalAttributeException
*/
public Feature copyFeature( final Feature sourceFeature,
final FeatureType targetType,
final Geometry newGeometry,
final String oldfidAtt) throws IllegalAttributeException {
try {
Feature newFeature = DataUtilities.template(targetType);
final GeometryAttributeType sourceGeometryType = sourceFeature.getFeatureType().getDefaultGeometry();
final String geoAttName = sourceGeometryType.getName();
List<String> omitAttr = new ArrayList<String>(1);
omitAttr.add(geoAttName);
//FIXME name
newFeature = FeatureUtil.copyAttributesCheater(sourceFeature, newFeature, omitAttr);
final Class geomClass = sourceGeometryType.getType();
final Geometry adaptedGeometry = GeometryUtil.adapt(newGeometry, geomClass);
final GeometryAttributeType targetGeometryType = targetType.getDefaultGeometry();
final String targetGeoAttName = targetGeometryType.getName();
newFeature.setAttribute(targetGeoAttName, adaptedGeometry);
String id = sourceFeature.getID();
String newString = id.substring(id.indexOf(".") + 1);//$NON-NLS-1$
newFeature.setAttribute(oldfidAtt, newString);
return newFeature;
}
catch (IllegalAttributeException e) {
throw new IllegalAttributeException(e.getMessage());
}
}
}