package com.persagy.adm.diagram.core.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.CaseInsensitiveMap;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.persagy.adm.diagram.core.model.base.XY;
import org.locationtech.jts.geom.*;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKTReader;

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

public class GeomUtil {

	private static GeometryFactory geometryFactory = new GeometryFactory();

	public static Polygon getPolygon(XY location, XY size) {
		Coordinate[] cs = new Coordinate[5];
		cs[0] = new Coordinate(location.x, location.y);
		cs[1] = new Coordinate(location.x + size.x, location.y);
		cs[2] = new Coordinate(location.x + size.x, location.y + size.y);
		cs[3] = new Coordinate(location.x, location.y + size.y);
		cs[4] = cs[0];
		return geometryFactory.createPolygon(cs);
	}

	public static LineString getLine(XY[] points) {
		Coordinate[] cs = new Coordinate[points.length];
		for (int i = 0; i < cs.length; i++) {
			cs[i] = new Coordinate(points[i].x, points[i].y);
		}
		return geometryFactory.createLineString(cs);
	}

	public Point getPoint(XY xy){
		return geometryFactory.createPoint(new Coordinate(xy.x, xy.y));
	}

	public static Polygon[] getPolygon(ArrayNode arrayNode){
		Polygon[] ps = new Polygon[arrayNode.size()];
		for (int i = 0; i < ps.length; i++) {
			ArrayNode arr = (ArrayNode) arrayNode.get(i);
			ArrayNode shellArrNode = (ArrayNode) arr.get(0);
			LinearRing shell = geometryFactory.createLinearRing(buildCoords(shellArrNode));
			LinearRing[] holes = null;
			if(arr.size() > 1) {
				holes = new LinearRing[arr.size() - 1];
				for (int n = 1; n < arr.size(); n++) {
					holes[n - 1] = geometryFactory.createLinearRing(buildCoords((ArrayNode) arr.get(n)));
				}
			}
			ps[i] = geometryFactory.createPolygon(shell, holes);
		}
		return ps;
	}

	private static Coordinate[] buildCoords(ArrayNode arrayNode){
		Coordinate[] coords = new Coordinate[arrayNode.size()];
		for (int i = 0; i < arrayNode.size(); i++) {
			JsonNode pointNode = arrayNode.get(i);
			coords[i] = new Coordinate(pointNode.get("x").asDouble(), pointNode.get("y").asDouble());
		}
		return coords;
	}

	public static boolean checkPolygon(ArrayList<ArrayList<ArrayList<CaseInsensitiveMap>>> outline){
		if(CollUtil.isEmpty(outline)) {
			return false;
		}

		try {
			Polygon[] ps = new Polygon[outline.size()];
			for (int i = 0; i < ps.length; i++) {
				List space = (List) outline.get(i);
				if(CollUtil.isEmpty(space)) {
					return false;
				}

				List<Map> shellList = (List) space.get(0);
				LinearRing shell = geometryFactory.createLinearRing(buildCoords(shellList));
				LinearRing[] holes = null;
				if(space.size() > 1) {
					holes = new LinearRing[space.size() - 1];
					for (int n = 1; n < space.size(); n++) {
						holes[n - 1] = geometryFactory.createLinearRing(buildCoords((List<Map>) space.get(n)));
					}
				}
				ps[i] = geometryFactory.createPolygon(shell, holes);
			}
		} catch (Exception e) {
			return false;
		}
		return true;
	}

	private static Coordinate[] buildCoords(List<Map> list){
		Coordinate[] coords = new Coordinate[list.size()];
		for (int i = 0; i < list.size(); i++) {
			Map point = list.get(i);
			coords[i] = new Coordinate((Double) point.get("x"), (Double)point.get("y"));
		}
		return coords;
	}

	public static boolean checkPolygon(ArrayNode outline){
		if(outline == null || outline.size() == 0) {
			return false;
		}

		try {
			Polygon[] ps = new Polygon[outline.size()];
			for (int i = 0; i < ps.length; i++) {
				ArrayNode space = (ArrayNode) outline.get(i);
				if(space == null || space.size() == 0) {
					return false;
				}

				ArrayNode shellList = (ArrayNode) space.get(0);
				LinearRing shell = geometryFactory.createLinearRing(buildCoords(shellList));
				LinearRing[] holes = null;
				if(space.size() > 1) {
					holes = new LinearRing[space.size() - 1];
					for (int n = 1; n < space.size(); n++) {
						holes[n - 1] = geometryFactory.createLinearRing(buildCoords((ArrayNode) space.get(n)));
					}
				}
				ps[i] = geometryFactory.createPolygon(shell, holes);
			}
		} catch (Exception e) {
			return false;
		}
		return true;
	}


	/**
	 *  两个几何对象是否是重叠的
	 * @return
	 * @throws ParseException
	 */
	public boolean equalsGeo() throws ParseException {
		WKTReader reader = new WKTReader( geometryFactory );
		LineString geometry1 = (LineString) reader.read("LINESTRING(0 0, 2 0, 5 0)");
		LineString geometry2 = (LineString) reader.read("LINESTRING(5 0, 0 0)");
		//true
		return geometry1.equals(geometry2);
	}

	/**
	 * 几何对象没有交点(相邻)
	 * @return
	 * @throws ParseException
	 */
	public boolean disjointGeo() throws ParseException{
		WKTReader reader = new WKTReader( geometryFactory );
		LineString geometry1 = (LineString) reader.read("LINESTRING(0 0, 2 0, 5 0)");
		LineString geometry2 = (LineString) reader.read("LINESTRING(0 1, 0 2)");
		return geometry1.disjoint(geometry2);
	}

	/**
	 * 至少一个公共点(相交)
	 * @return
	 * @throws ParseException
	 */
	public boolean intersectsGeo() throws ParseException{
		WKTReader reader = new WKTReader( geometryFactory );
		LineString geometry1 = (LineString) reader.read("LINESTRING(0 0, 2 0, 5 0)");
		LineString geometry2 = (LineString) reader.read("LINESTRING(0 0, 0 2)");
		Geometry interPoint = geometry1.intersection(geometry2);//相交点
		System.out.println(interPoint.toText());//输出 POINT (0 0)
		return geometry1.intersects(geometry2);
	}

	/**
	 * 判断以x,y为坐标的点point(x,y)是否在geometry表示的Polygon中
	 * @param x
	 * @param y
	 * @param geometry wkt格式
	 * @return
	 */
	public boolean withinGeo(double x,double y,String geometry) throws ParseException {

		Coordinate coord = new Coordinate(x,y);
		Point point = geometryFactory.createPoint( coord );

		WKTReader reader = new WKTReader( geometryFactory );
		Polygon polygon = (Polygon) reader.read(geometry);
		return point.within(polygon);
	}

	public LinearRing createLinearRing(double[]... xys){
		Coordinate[] coords = new Coordinate[xys.length];
		for(int i=0;i<xys.length;i++){
			coords[i] = new Coordinate(xys[i][0], xys[i][1]);
		}
		return geometryFactory.createLinearRing(coords);
	}

	public Polygon createPolygon(double[]... xys){
		Coordinate[] coords = new Coordinate[xys.length];
		for(int i=0;i<xys.length;i++){
			coords[i] = new Coordinate(xys[i][0], xys[i][1]);
		}
		return geometryFactory.createPolygon(coords);
	}

	public LineString createLine(double[]... xys){
		Coordinate[] coords = new Coordinate[xys.length];
		for(int i=0;i<xys.length;i++){
			coords[i] = new Coordinate(xys[i][0], xys[i][1]);
		}
		return geometryFactory.createLineString(coords);
	}

}
