/* Copyright (c) 2014 Boundless and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Distribution License v1.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/edl-v10.html
*
* Contributors:
* Victor Olaya (Boundless) - initial implementation
*/
package org.locationtech.geogig.cli.plumbing;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import jline.console.ConsoleReader;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.locationtech.geogig.api.GeoGIG;
import org.locationtech.geogig.api.NodeRef;
import org.locationtech.geogig.api.RevFeatureType;
import org.locationtech.geogig.api.plumbing.ResolveFeatureType;
import org.locationtech.geogig.cli.AbstractCommand;
import org.locationtech.geogig.cli.CLICommand;
import org.locationtech.geogig.cli.GeogigCLI;
import org.locationtech.geogig.storage.FieldType;
import org.locationtech.geogig.storage.text.TextValueSerializer;
import org.opengis.feature.Feature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeDescriptor;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.google.common.base.Charsets;
import com.google.common.base.Joiner;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.io.Files;
@Parameters(commandNames = "insert", commandDescription = "Inserts features in the repository")
public class Insert extends AbstractCommand implements CLICommand {
@Parameter(description = "<features_definition>")
private List<String> inputs = new ArrayList<String>();
@Parameter(names = "-f", description = "File with definition of features to insert")
private String filepath;
private GeoGIG geogig;
@Override
public void runInternal(GeogigCLI cli) throws IOException {
ConsoleReader console = cli.getConsole();
geogig = cli.getGeogig();
Iterable<String> lines = null;
if (filepath != null) {
File file = new File(filepath);
checkParameter(file.exists(), "Insert file cannot be found");
lines = Files.readLines(file, Charsets.UTF_8);
} else {
String featuresText = Joiner.on("\n").join(inputs);
lines = Splitter.on("\n").split(featuresText);
}
Map<String, List<Feature>> features = readFeatures(lines);
long count = 0;
for (String key : features.keySet()) {
List<Feature> treeFeatures = features.get(key);
geogig.getRepository()
.workingTree()
.insert(key, treeFeatures.iterator(), cli.getProgressListener(), null,
treeFeatures.size());
count += treeFeatures.size();
}
console.print(Long.toString(count) + " features successfully inserted.");
}
public Map<String, List<Feature>> readFeatures(Iterable<String> lines) {
Map<String, List<Feature>> features = Maps.newHashMap();
List<String> featureChanges = Lists.newArrayList();
Map<String, SimpleFeatureBuilder> featureTypes = Maps.newHashMap(); //
String line;
Iterator<String> iter = lines.iterator();
while (iter.hasNext()) {
line = iter.next().trim();
if (line.isEmpty() && !featureChanges.isEmpty()) {
String path = featureChanges.get(0);
String tree = NodeRef.parentPath(path);
if (!features.containsKey(tree)) {
features.put(tree, new ArrayList<Feature>());
}
features.get(tree).add(createFeature(featureChanges, featureTypes));
featureChanges.clear();
} else if (!line.isEmpty()) {
featureChanges.add(line);
}
}
if (!featureChanges.isEmpty()) {
String path = featureChanges.get(0);
String tree = NodeRef.parentPath(path);
if (!features.containsKey(tree)) {
features.put(tree, new ArrayList<Feature>());
}
features.get(tree).add(createFeature(featureChanges, featureTypes));
featureChanges.clear();
}
return features;
}
private Feature createFeature(List<String> featureChanges,
Map<String, SimpleFeatureBuilder> featureTypes) {
String path = featureChanges.get(0);
String tree = NodeRef.parentPath(path);
String featureId = NodeRef.nodeFromPath(path);
if (!featureTypes.containsKey(tree)) {
Optional<RevFeatureType> opt = geogig.command(ResolveFeatureType.class)
.setRefSpec("WORK_HEAD:" + tree).call();
checkParameter(opt.isPresent(), "The parent tree does not exist: " + tree);
SimpleFeatureBuilder builder = new SimpleFeatureBuilder((SimpleFeatureType) opt.get()
.type());
featureTypes.put(tree, builder);
}
SimpleFeatureBuilder ftb = featureTypes.get(tree);
SimpleFeatureType ft = ftb.getFeatureType();
for (int i = 1; i < featureChanges.size(); i++) {
String[] tokens = featureChanges.get(i).split("\t");
Preconditions.checkArgument(tokens.length == 2, "Wrong attribute definition: "
+ featureChanges.get(i));
String fieldName = tokens[0];
AttributeDescriptor desc = ft.getDescriptor(fieldName);
Preconditions.checkNotNull(desc, "Wrong attribute in feature description");
FieldType type = FieldType.forBinding(desc.getType().getBinding());
Object value = TextValueSerializer.fromString(type, tokens[1]);
ftb.set(tokens[0], value);
}
return ftb.buildFeature(featureId);
}
}