package de.hft.stuttgart.citygml.green.osm;

import java.io.IOException;
import java.nio.file.Paths;
import java.util.Iterator;
import java.util.UUID;

import org.citygml4j.core.model.core.AbstractCityObjectProperty;
import org.citygml4j.core.model.core.CityModel;
import org.citygml4j.core.model.vegetation.SolitaryVegetationObject;
import org.locationtech.jts.geom.Coordinate;
import org.xmlobjects.gml.model.basictypes.Code;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurface;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurfaceProperty;

public class TreeUtils {
	
	public static void insertTrees(CityModel cityModel, OsmData osmData) throws IOException {
		TreeKatasterData katasterData = TreeKatasterData.parseTreeKatasterData(Paths.get("data", "Baum.shp"));
		generateTreesFromKataster(cityModel, katasterData);

		// All kataster trees are taken, osm trees are removed
		filterDuplicateTreesFromOSM(osmData, katasterData);
		
		generateTreesFromOSM(cityModel, osmData);

	}
	
	private static void filterDuplicateTreesFromOSM(OsmData osmData, TreeKatasterData katasterData) {
		for (Iterator<TreePoint> iterator = osmData.getTreePoints().iterator(); iterator.hasNext();) {
			TreePoint tp = iterator.next();
			// if another tree from kataster is within 3m ignore it
			for (Tree tree : katasterData.getTrees()) {
				if (tp.getPoint().distance(tree.getPoint()) < 3) {
					iterator.remove();
				}
			}
		}
	}
	
	private static void generateTreesFromOSM(CityModel cityModel, OsmData osmData) {
		for (TreePoint tp : osmData.getTreePoints()) {
			// standard tree
			double trunkRadius = 0.89 / (2 * Math.PI);
			double trunkHeight = TreeKatasterData.TRUNK_PERCENTAGE * 11.46;
			double crownHeight = TreeKatasterData.CROWN_PERCENTAGE * 11.46;
			double crownRadius = 8 / 2d;
			Coordinate coordinate = tp.getPoint().getCoordinate();
			if (Double.isNaN(coordinate.z)) {
				coordinate.z = 0;
			}
			MultiSurface generatedTree = TreeGenerator.generateTree(coordinate, trunkRadius, trunkHeight, crownRadius,
					crownRadius, crownHeight);
			SolitaryVegetationObject cover = new SolitaryVegetationObject();
			cover.setSpecies(new Code("Acer campestre"));
			cover.setId(UUID.randomUUID().toString());
			cover.setLod2MultiSurface(new MultiSurfaceProperty(generatedTree));
			cityModel.getCityObjectMembers().add(new AbstractCityObjectProperty(cover));
		}
	}

	private static void generateTreesFromKataster(CityModel cityModel, TreeKatasterData katasterData) {
		for (Tree tree : katasterData.getTrees()) {
			double trunkRadius = tree.getTrunkRadius();
			double trunkHeight = tree.getTrunkHeight();
			double crownHeight = tree.getCrownHeight();
			double crownRadius = tree.getCrownRadius();

			Coordinate coordinate = tree.getPoint().getCoordinate();
			if (Double.isNaN(coordinate.z)) {
				coordinate.z = 0;
			}
			MultiSurface generatedTree = TreeGenerator.generateTree(coordinate, trunkRadius, trunkHeight, crownRadius,
					crownRadius, crownHeight);
			SolitaryVegetationObject cover = new SolitaryVegetationObject();
			cover.setSpecies(new Code(tree.getType()));
			cover.setId(UUID.randomUUID().toString());
			cover.setLod2MultiSurface(new MultiSurfaceProperty(generatedTree));
			cityModel.getCityObjectMembers().add(new AbstractCityObjectProperty(cover));
		}
	}

}
