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

import java.text.NumberFormat;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

public class DebugUtils {
	
	private static AtomicInteger polygon3dCounter = new AtomicInteger(1);
	private static AtomicInteger coordListCounter = new AtomicInteger(1);
	
	private DebugUtils() {
	}

	public static void printPolyLineSegment2dList(List<PolyLineSegment2d> rSegments) {
		Locale.setDefault(Locale.US);
		for (PolyLineSegment2d seg : rSegments) {
			Point2d start = seg.getStart().getPoint();
			Point2d end = seg.getEnd().getPoint();
			System.out.println(String.format(
					"segmentList.push_back(new PolyLineSegment2d(new Coordinate2d(%f, %f), new Coordinate2d(%f, %f)));",
					start.getX(), start.getY(), end.getX(), end.getY()));
		}
	}

	public static void printPolygon2d(Polygon2d mcpPolygon1) {
		Locale.setDefault(Locale.US);
		System.out.println("Coordinate2dList coords;");
		HalfEdge2d firstHalfEdge = mcpPolygon1.getFirstHalfEdge();
		Point2d start = firstHalfEdge.getStart().getPoint();
		System.out.println(String.format("coords.push_back(new Coordinate2d(%f, %f));", start.getX(), start.getY()));
		HalfEdge2d next = firstHalfEdge.getNext();
		while (next != null && next != firstHalfEdge) {
			start = next.getStart().getPoint();
			System.out.println(String.format("coords.push_back(new Coordinate2d(%f, %f));", start.getX(), start.getY()));
			next = next.getNext();
		}
		System.out.println("Polygon2d* mcpPolygon1 = new Polygon2dNs(coords);");
	}

	public static void printPolygon3d(EdgePolygon p) {
		Locale.setDefault(Locale.US);
		int counter = polygon3dCounter.getAndIncrement();
		System.out.println("Coordinate3dList coords" + counter + ";");
		HalfEdge firstHalfEdge = p.getFirstHalfEdge();
		Point3d start = firstHalfEdge.getStart().getPoint();
		System.out.println(String.format("coords%d.push_back(new Coordinate3d(%f, %f, %f));", counter, start.getX(), start.getY(), start.getZ()));
		HalfEdge next = firstHalfEdge.getNext();
		while (next != null && next != firstHalfEdge) {
			start = next.getStart().getPoint();
			System.out.println(String.format("coords%d.push_back(new Coordinate3d(%f, %f, %f));", counter, start.getX(), start.getY(), start.getZ()));
			next = next.getNext();
		}
		System.out.println("PolygonNs* p" + counter + " = new PolygonNs(coords" + counter+ ");");
	}

	public static void printPolygon3d(CDPolygonNs edgePoly1, CDPolygonNs edgePoly2) {
		Locale.setDefault(Locale.US);
		Map<Point3d, String> pointMap = new IdentityHashMap<>();
		int startCounter = 1;
		startCounter = printPolygon3d(edgePoly1, pointMap, startCounter);
		printPolygon3d(edgePoly2, pointMap, startCounter);
	}
	
	public static void printGeoknechtPolygon(CDPolygonNs... polys) {
		Locale.setDefault(Locale.US);
		NumberFormat nf = NumberFormat.getNumberInstance();
		nf.setMaximumFractionDigits(30);
		for (CDPolygonNs poly : polys) {
			List<Coordinate3d> coordinates = poly.getCoordinates();
			System.out.print("polygon(");
			for (Coordinate3d coord : coordinates) {
				Point3d point = coord.getPoint();
				writeGeoknechtPoint(nf, point);
			}
			writeGeoknechtPoint(nf, coordinates.get(0).getPoint());
			System.out.println(")");
			for (List<HalfEdge> innerRing : poly.getInnerHalfEdges()) {
				System.out.print("polygon(");
				for (HalfEdge he : innerRing) {
					Point3d point = he.getStart().getPoint();
					writeGeoknechtPoint(nf, point);
				}
				writeGeoknechtPoint(nf, innerRing.get(innerRing.size() - 1).getEnd().getPoint());
				System.out.println(")");
			}
		}
	}

	private static void writeGeoknechtPoint(NumberFormat nf, Point3d point) {
		System.out.print(nf.format(point.getX()));
		System.out.print("|");
		System.out.print(nf.format(point.getY()));
		System.out.print("|");
		System.out.print(nf.format(point.getZ()));
		System.out.print(" ");
	}

	private static int printPolygon3d(CDPolygonNs p, Map<Point3d, String> pointMap, int startCounter) {
		NumberFormat nf = NumberFormat.getNumberInstance();
		nf.setMaximumFractionDigits(30);
		int counter = polygon3dCounter.getAndIncrement();
		int listCounter = coordListCounter.getAndIncrement();
		int firstListCounter = listCounter;
		HalfEdge firstHalfEdge = p.getFirstHalfEdge();
		int[] counterArr = new int[] {startCounter};
		System.out.println("Coordinate3dList coords" + firstListCounter + ";");
		writeRing(pointMap, nf, listCounter, firstHalfEdge, counterArr);
		for (List<HalfEdge> innerRing : p.getInnerHalfEdges()) {
			listCounter = coordListCounter.getAndIncrement();
			System.out.println("Coordinate3dList coords" + listCounter + ";");
			writeRing(pointMap, nf, listCounter, innerRing.get(0), counterArr);
		}
		int lastListCounter = coordListCounter.get();
		System.out.println("std::list<Coordinate3dList> coordLists" + counter + ";");
		for (int i = firstListCounter; i < lastListCounter; i++) {
			System.out.println("coordLists" + counter + ".push_back(coords" + i +");");
		}
		System.out.println("CDPolygonNs* p" + counter + " = new CDPolygonNs(coordLists" + counter+ ");");
		return counterArr[0];
	}

	private static void writeRing(Map<Point3d, String> pointMap, NumberFormat nf, int counter, HalfEdge firstHalfEdge,
			int[] counterArr) {
		final Point3d start = firstHalfEdge.getStart().getPoint();
		String coordVarName = getCoordName(pointMap, nf, start, counterArr);
		System.out.println(String.format("coords%d.push_back(%s);", counter, coordVarName));
		HalfEdge next = firstHalfEdge.getNext();
		while (next != null && next != firstHalfEdge) {
			Point3d nextPoint = next.getStart().getPoint();
			coordVarName = getCoordName(pointMap, nf, nextPoint, counterArr);

			System.out.println(String.format("coords%d.push_back(%s);", counter, coordVarName));
			next = next.getNext();
		}
	}

	private static String getCoordName(Map<Point3d, String> pointMap, NumberFormat nf, final Point3d start,
			int[] counterArr) {
		String coordVarName = pointMap.computeIfAbsent(start, k -> {
			System.out.println(String.format("Coordinate3d* c%d = new Coordinate3d(%s, %s, %s);", counterArr[0], nf.format(start.getX()), nf.format(start.getY()), nf.format(start.getZ())));
			String name = "c" + counterArr[0];
			counterArr[0]++;
			return name;
		});
		return coordVarName;
	}

}
