import { pond } from "protobuf-ts/pond";

// interface properties {
//   exclusion: boolean;
//   field: string;
//   main: boolean;
//   color: string;
// }

interface geoJSONGeometry {
  coordinates: any[];
  type: string;
}

/**
 * GeometryMapping is a geoJSON structure that React-map-gl's map layers needs in order to draw the shape on the map
 */
export class GeometryMapping {
  public type: "Feature" = "Feature";

  public geometry: geoJSONGeometry = {
    coordinates: [],
    type: ""
  };

  public static geoJSON(shape: string, shapes: pond.Shape[], holes?: pond.Shape[]) {
    let gm = new GeometryMapping();
    gm.geometry = getGeometry(shape, shapes, holes);
    return gm;
  }
}

//helper function to build the correct geometry for the desired shape
export function getGeometry(
  shape: string,
  shapes: pond.Shape[],
  holes?: pond.Shape[]
): { coordinates: any[]; type: string } {
  let geo: geoJSONGeometry = {
    coordinates: [],
    type: shape
  };

  switch (shape) {
    case "LineString":
      if (shapes[0]) {
        shapes[0].points.forEach(point => {
          geo.coordinates.push([point.longitude, point.latitude]);
        });
      }
      break;
    case "Polygon":
      if (shapes[0]) {
        let shapeArray: any[] = [];
        shapes[0].points.forEach(point => {
          shapeArray.push([point.longitude, point.latitude]);
        });
        geo.coordinates.push(shapeArray);
      }
      if (holes) {
        holes.forEach(hole => {
          let holeArray: any[] = [];
          hole.points.forEach(point => {
            holeArray.push([point.longitude, point.latitude]);
          });
          geo.coordinates.push(holeArray);
        });
      }
      break;
    case "MultiPolygon":
      //this is an array of polygons (one polygon is an array of shapes, the first being the border, and all subsequent shapes being holes in that border)
      shapes.forEach(shape => {
        let polygon: any[] = [];
        let shapeArray: any[] = [];
        shape.points.forEach(point => {
          shapeArray.push([point.longitude, point.latitude]);
        });
        polygon.push(shapeArray);
        //just note JD and CNH dont do holes in their fields so this part will be UNTESTED until handling drawing multi polygons for our fields
        if (holes) {
          let holeArray: any[] = [];
          holes.forEach(hole => {
            if (hole.key === shape.key) {
              hole.points.forEach(point => {
                holeArray.push([point.longitude, point.latitude]);
              });
            }
            polygon.push(holeArray);
          });
        }
        geo.coordinates.push(polygon);
      });
      break;
    default:
      break;
  }

  return geo;
}

/**
 * takes in a 2D array of numbers an builds then into a shape object that can be added to either the holes or shapes of geoData
 * @param coordinates an array of number pairs
 * @returns pond.shape object using that array
 */
export function shapeFromCoords(coordinates: number[][]): pond.Shape {
  let shape = pond.Shape.create();
  coordinates.forEach(pair => {
    shape.points.push(
      pond.Coordinates.create({
        longitude: pair[0],
        latitude: pair[1]
      })
    );
  });
  return shape;
}

export function coordDistance(lat1: number, long1: number, lat2: number, long2: number) {
  var R = 6371; // Radius of the earth in km
  var dLat = deg2rad(lat2 - lat1); // deg2rad below
  var dLon = deg2rad(long2 - long1);
  var a =
    Math.sin(dLat / 2) * Math.sin(dLat / 2) +
    Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
  var d = R * c; // Distance in km
  return d;
}

function deg2rad(deg: number) {
  return deg * (Math.PI / 180);
}
