/*-
 *  Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
 * 
 *  This file is part of CityDoctor2.
 *
 *  CityDoctor2 is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  CityDoctor2 is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with CityDoctor2.  If not, see <https://www.gnu.org/licenses/>.
 */
package de.hft.stuttgart.citydoctor2.datastructure;

import java.util.List;
import java.util.Map;

import de.hft.stuttgart.citydoctor2.check.Check;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.check.CheckResult;
import de.hft.stuttgart.citydoctor2.math.Vector3d;
import de.hft.stuttgart.citydoctor2.tesselation.TesselatedPolygon;
import de.hft.stuttgart.citydoctor2.utils.CopyHandler;
import de.hft.stuttgart.citydoctor2.utils.Copyable;

/**
 * A polygon that does not contain the geometry but is only a link to an actual
 * polygon. Created when href in CityGML are used.
 * 
 * @author Matthias Betz
 *
 */
public class LinkedPolygon extends Polygon {

	private static final long serialVersionUID = -4897578390280277931L;

	private Geometry parent;
	private ConcretePolygon poly;
	
	private LinkedPolygon() {
	}
	
	/**
	 * 
	 * @param poly   polygon this is linked to
	 * @param parent the parent of the linked polygon
	 */
	public LinkedPolygon(ConcretePolygon poly, Geometry parent) {
		this.parent = parent;
		this.poly = poly;
		poly.setLinkedTo(this);
		for (Vertex v : poly.getExteriorRing().getVertices()) {
			v.addAdjacentRing(poly.getExteriorRing(), parent);
		}
		for (LinearRing lr : poly.getInnerRings()) {
			for (Vertex v : lr.getVertices()) {
				v.addAdjacentRing(lr, parent);
			}
		}
	}

	@Override
	public CheckResult getCheckResult(Check c) {
		return poly.getCheckResult(c);
	}

	@Override
	public Map<CheckId, CheckResult> getAllCheckResults() {
		return poly.getAllCheckResults();
	}

	@Override
	public boolean hasAnyError() {
		return poly.hasAnyError();
	}

	@Override
	public boolean hasDependencyNotMetError(CheckId id) {
		return poly.hasDependencyNotMetError(id);
	}

	@Override
	public CheckResult getCheckResult(CheckId id) {
		return poly.getCheckResult(id);
	}

	@Override
	public boolean hasCheckResults() {
		return poly.hasCheckResults();
	}

	@Override
	public void setGmlId(GmlId id) {
		poly.setGmlId(id);
	}

	@Override
	public GmlId getGmlId() {
		return poly.getGmlId();
	}

	@Override
	public void accept(Check c) {
		// linked polygons are not checked
		setValidated(true);
	}

	@Override
	public void addCheckResult(CheckResult cr) {
		poly.addCheckResult(cr);
	}

	@Override
	public void collectContainedErrors(List<CheckError> errors) {
		poly.collectContainedErrors(errors);
	}

	@Override
	public boolean containsAnyError() {
		return poly.containsAnyError();
	}

	@Override
	public boolean containsError(CheckId checkIdentifier) {
		return poly.containsError(checkIdentifier);
	}

	@Override
	public void clearCheckResults() {
		poly.clearCheckResults();
	}

	@Override
	public Vector3d calculateNormalNormalized() {
		return poly.calculateNormalNormalized();
	}
	
	@Override
	public Vector3d calculateNormal() {
		return poly.calculateNormal();
	}

	@Override
	public TesselatedPolygon tesselate() {
		return poly.tesselate();
	}

	@Override
	public LinearRing getExteriorRing() {
		return poly.getExteriorRing();
	}

	@Override
	public List<LinearRing> getInnerRings() {
		return poly.getInnerRings();
	}

	@Override
	public boolean isPointInsideExteriorRing(Vector3d v) {
		return poly.isPointInsideExteriorRing(v);
	}

	@Override
	public Geometry getParent() {
		return parent;
	}

	@Override
	public void setParent(Geometry geometry) {
		this.parent = geometry;
	}

	@Override
	public void setExteriorRing(LinearRing extRing) {
		poly.setExteriorRing(extRing);
	}

	@Override
	public boolean isPolygonConnectedViaPoint(Polygon other) {
		return poly.isPolygonConnectedViaPoint(other);
	}

	@Override
	public String toString() {
		return "LinkedPolygon [" + poly.getGmlId() + "]";
	}

	@Override
	public void addInteriorRing(LinearRing inter) {
		poly.addInteriorRing(inter);
	}

	@Override
	public BoundarySurface getPartOfSurface() {
		return poly.getPartOfSurface();
	}

	@Override
	public void setPartOfSurface(BoundarySurface bs) {
		poly.setPartOfSurface(bs);
	}

	@Override
	public void removeInnerRing(LinearRing ring) {
		poly.removeInnerRing(ring);
	}

	@Override
	public void setPartOfInstallation(BuildingInstallation bi) {
		poly.setPartOfInstallation(bi);
	}

	@Override
	public BuildingInstallation getPartOfInstallation() {
		return poly.getPartOfInstallation();
	}

	@Override
	public boolean hasPointAsCorner(Vertex v) {
		return poly.hasPointAsCorner(v);
	}

	@Override
	public void removeRings() {
		poly.removeRings();
	}

	@Override
	public boolean isLink() {
		return true;
	}

	@Override
	public LinkedPolygon getLinkedFromPolygon() {
		return this;
	}

	@Override
	void anonymize() {
		poly.anonymize();
	}

	@Override
	public void clearAllContainedCheckResults() {
		poly.clearAllContainedCheckResults();
	}

	@Override
	public ConcretePolygon getOriginal() {
		return poly;
	}

	@Override
	public void prepareForChecking() {
		poly.prepareForChecking();
	}

	@Override
	public void clearMetaInformation() {
		poly.clearMetaInformation();
	}

	@Override
	public boolean isLinkedTo() {
		return false;
	}

	@Override
	public void collectInstances(CopyHandler handler) {
		handler.addInstance(parent);
		handler.addInstance(poly);
	}

	@Override
	public Copyable createCopyInstance() {
		return new LinkedPolygon();
	}
	
	@Override
	public void fillValues(Copyable original, CopyHandler handler) {
		LinkedPolygon linkedOriginal = (LinkedPolygon) original;
		parent = handler.getCopyInstance(linkedOriginal.parent);
		poly = handler.getCopyInstance(linkedOriginal.poly);
	}

	@Override
	public void remove() {
		poly.remove();
	}

}
