/*-
 *  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.reporting.pdf;

import java.util.Collection;

import org.locationtech.proj4j.ProjCoordinate;

import de.hft.stuttgart.citydoctor2.check.ErrorReport;
import de.hft.stuttgart.citydoctor2.datastructure.BoundarySurface;
import de.hft.stuttgart.citydoctor2.datastructure.Edge;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.GmlElement;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
import de.hft.stuttgart.citydoctor2.math.Vector3d;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;

/**
 * Handler for the information given by the errors. The information is formatted
 * and written out in the PDF report. Most information is formatted into code
 * blocks with a border for more overview.
 * 
 * @author Matthias Betz
 *
 */
public class PdfErrorHandler implements ErrorReport {

	private static final String VERTEX_FORMAT = "%f %f %f";
	private static final String TAG_COLOR = "#3F7F7F";
	private static final String ATTRIBUTE_KEY_COLOR = "#7F007F";
	private static final String ATTRIBUTE_VALUE_COLOR = "#2A00FF";

	private Section section;
	private ParserConfiguration config;

	public PdfErrorHandler(Section section, ParserConfiguration config) {
		this.config = config;
		this.section = section;
	}

	@Override
	public void add(Polygon p) {
		CodeBlock block = new CodeBlock();
		section.addCodeBlock(block);
		block.addText("<Polygon", TAG_COLOR);
		addGmlId(p, block);
		block.addText(">", TAG_COLOR);
		block.newLine(10);
		block.addText("<Exterior Ring", TAG_COLOR);
		addGmlId(p.getExteriorRing(), block);
		block.addText(">", TAG_COLOR);
		for (Vertex v : p.getExteriorRing().getVertices()) {
			block.newLine(20);
			addVertexToBlock(block, v);
		}
		block.newLine(10);
		block.addText("</Exterior Ring>", TAG_COLOR);
		if (p.getInnerRings().isEmpty()) {
			return;
		}
		block.newLine(10);
		block.addText("<Interior Rings>", TAG_COLOR);
		for (LinearRing ring : p.getInnerRings()) {
			block.newLine(20);
			block.addText("<Interior Ring", TAG_COLOR);
			addGmlId(ring, block);
			block.addText(">", TAG_COLOR);
			for (Vertex v : p.getExteriorRing().getVertices()) {
				block.newLine(30);
				addVertexToBlock(block, v);
			}
			block.newLine(20);
			block.addText("</Interior Ring>", TAG_COLOR);
		}
		block.newLine(10);
		block.addText("</Interior Rings>", TAG_COLOR);

	}

	private void addVertexToBlock(CodeBlock block, Vertex v) {
		double x = v.getX();
		double y = v.getY();
		double z = v.getZ();
		if (config.getOriginalTransform() != null) {
			ProjCoordinate p1 = new ProjCoordinate();
			ProjCoordinate p2 = new ProjCoordinate();
			p1.x = v.getX();
			p1.y = v.getY();
			config.getOriginalTransform().transform(p1, p2);
			x = p2.x;
			y = p2.y;
		}
		block.addText(String.format(VERTEX_FORMAT, x, y, z));
	}

	private void addGmlId(GmlElement e, CodeBlock block) {
		if (!e.getGmlId().isGenerated()) {
			block.addText(" gml:id", ATTRIBUTE_KEY_COLOR);
			block.addText("=");
			block.addText(e.getGmlId().getGmlString(), ATTRIBUTE_VALUE_COLOR);
		}
	}

	@Override
	public void add(LinearRing lr) {
		CodeBlock block = new CodeBlock();
		section.addCodeBlock(block);
		block.addText("<LinearRing", TAG_COLOR);
		addGmlId(lr, block);
		block.addText(" type", ATTRIBUTE_KEY_COLOR);
		block.addText("=");
		block.addText(lr.getType().toString(), ATTRIBUTE_VALUE_COLOR);
		block.addText(">", TAG_COLOR);
		for (Vertex v : lr.getVertices()) {
			block.newLine(10);
			addVertexToBlock(block, v);
		}
		block.newLine();
		block.addText("</LinearRing>", TAG_COLOR);
	}

	@Override
	public void add(Geometry geom) {
		CodeBlock block = new CodeBlock();
		section.addCodeBlock(block);
		block.addText("<Geometry", TAG_COLOR);
		addGmlId(geom, block);
		block.addText(" type", ATTRIBUTE_KEY_COLOR);
		block.addText("=");
		block.addText(geom.getType().toString(), ATTRIBUTE_VALUE_COLOR);
		block.addText(" lod", ATTRIBUTE_KEY_COLOR);
		block.addText("=");
		block.addText(geom.getLod().toString(), ATTRIBUTE_VALUE_COLOR);

		block.addText(">", TAG_COLOR);
		for (Polygon p : geom.getPolygons()) {
			block.newLine(10);
			block.addText("<Polygon", TAG_COLOR);
			block.addText(" gml:id", ATTRIBUTE_KEY_COLOR);
			block.addText("=");
			block.addText(p.getGmlId().getGmlString(), ATTRIBUTE_VALUE_COLOR);
			block.addText(">", TAG_COLOR);
		}
		block.newLine();
		block.addText("</Geometry>", TAG_COLOR);
	}

	@Override
	public void add(Vertex v) {
		addVector(v);
	}

	private void addVector(Vector3d v) {
		CodeBlock block = new CodeBlock();
		section.addCodeBlock(block);
		block.addText("<Vertex>", TAG_COLOR);
		block.addText(String.format(VERTEX_FORMAT, v.getX(), v.getY(), v.getZ()));
		block.addText("</Vertex>", TAG_COLOR);
	}

	@Override
	public void add(String name, Vertex v) {
		section.add10PtTextElement(name, 5);
		add(v);
	}

	@Override
	public void add(Edge e) {
		CodeBlock block = new CodeBlock();
		section.addCodeBlock(block);
		addEdgeToBlock(e, block);

	}

	private void addEdgeToBlock(Edge e, CodeBlock block) {
		block.addText("<Edge>", TAG_COLOR);
		block.newLine(10);
		block.addText("<From>", TAG_COLOR);
		block.addText(String.format(VERTEX_FORMAT, e.getFrom().getX(), e.getFrom().getY(), e.getFrom().getZ()));
		block.addText("</From>", TAG_COLOR);
		block.newLine(10);
		block.addText("<To>", TAG_COLOR);
		block.addText(String.format(VERTEX_FORMAT, e.getTo().getX(), e.getTo().getY(), e.getTo().getZ()));
		block.addText("</To>", TAG_COLOR);
		block.newLine();
		block.addText("</Edge>", TAG_COLOR);
		block.newLine();
	}

	@Override
	public void add(BoundarySurface bs) {
		section.add10PtTextElement("In BoundarySurface " + bs.getType().toString() + " id=" + bs.getGmlId(), 5);
	}

	@Override
	public void add(String name, Edge e) {
		section.add10PtTextElement(name, 5);
		add(e);
	}

	@Override
	public void add(String name, int value) {
		add(name, "" + value);
	}

	@Override
	public void add(String name, double value) {
		add(name, "" + value);
	}

	@Override
	public void add(String name, String value) {
		section.add10PtTextElement(String.join(": ", name, value), 5);
	}

	@Override
	public void add(String name, Vector3d point) {
		section.add10PtTextElement(name, 5);
		addVector(point);
	}

	@Override
	public void addPolygons(String name, Collection<Polygon> polygons) {
		section.add10PtTextElement(name, 5);
		for (Polygon p : polygons) {
			section.add10PtTextElement(p.getGmlId().getGmlString(), 10);
		}
	}

	@Override
	public void addEdges(String name, Collection<Edge> edges) {
		section.add10PtTextElement(name, 5);
		CodeBlock block = new CodeBlock();
		section.addCodeBlock(block);
		for (Edge e : edges) {
			addEdgeToBlock(e, block);
		}
	}

}
