/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package eu.dnetlib.espas.spatial;

import eu.dnetlib.espas.spatial.QShape;
import eu.dnetlib.espas.spatial.QueryCRS;
import eu.dnetlib.espas.util.GeometryMetadataHandler;
import eu.dnetlib.espas.util.MetadataHandler;
import eu.dnetlib.espas.util.PointCoordinateEditor;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

/**
 *
 * @author gathanas
 */
public class BBoxQShape extends QShape{

   protected BBoxQShape(List<Point> points){
      super(points);
   }
   
   public BBoxQShape(Point lowerLeft, Point upperRight) {
      this(Arrays.asList(lowerLeft,upperRight));
   }

   @Override
   public String getQueryString() {
        int sridCode = GeometryMetadataHandler.getSupportedCRSMapping(this.espasCRS).getSrid();
            boolean inverted = GeometryMetadataHandler.getSupportedCRSMapping(this.espasCRS).isInvertedXY();
            String queryConstraint = "st_SetSRID(location::geometry, "+sridCode+") && ";
        double maxZ=0.0 , minZ=Double.MAX_VALUE;
      String constraintShape= "st_3DMakeBox(";
      for(Point p:shapePoints){
        constraintShape+="st_SetSRID(st_MakePoint(";
        if(!inverted){
            constraintShape+= ""+(p.getCoordinate(Point.PolarCoord.LON_Cord.name())==null? p.getCoordinate(Point.CartesianCoord.X_Cord.name()): p.getCoordinate(Point.PolarCoord.LON_Cord.name()))+", ";
            constraintShape+= ""+(p.getCoordinate(Point.PolarCoord.LAT_Cord.name())==null?p.getCoordinate(Point.CartesianCoord.Y_Cord.name()):p.getCoordinate(Point.PolarCoord.LAT_Cord.name()))+", ";
        }
        else {
            constraintShape+= ""+(p.getCoordinate(Point.PolarCoord.LAT_Cord.name())==null?p.getCoordinate(Point.CartesianCoord.Y_Cord.name()):p.getCoordinate(Point.PolarCoord.LAT_Cord.name()))+", ";
            constraintShape+= ""+(p.getCoordinate(Point.PolarCoord.LON_Cord.name())==null? p.getCoordinate(Point.CartesianCoord.X_Cord.name()): p.getCoordinate(Point.PolarCoord.LON_Cord.name()))+", ";
        }   
        
        constraintShape+= ""+(p.getCoordinate(Point.PolarCoord.R_Cord.name())==null?p.getCoordinate(Point.CartesianCoord.Z_Cord.name()):p.getCoordinate(Point.PolarCoord.R_Cord.name()))+"),"+sridCode+"),";
        Double hZ = ((p.getCoordinate(Point.PolarCoord.R_Cord.name())==null)?p.getCoordinate(Point.CartesianCoord.Z_Cord.name()):p.getCoordinate(Point.PolarCoord.R_Cord.name()));
        maxZ = Math.max(maxZ, hZ.doubleValue());
        minZ = Math.min(minZ, hZ);
      }
      constraintShape=constraintShape.substring(0, constraintShape.lastIndexOf(","))+")::geometry";
      
       queryConstraint=queryConstraint+ constraintShape  + " and st_zmax(location::geometry) >="+minZ+" and st_zmin(location::geometry)<="+maxZ+"";
      return queryConstraint;
   }

   @Override
   public void transformToCRS(QueryCRS toCRS) {
       if (!this.espasCRS.equalsIgnoreCase(toCRS.espasValue())) {
           List<Point> transformedPoints = new LinkedList<Point>();
           PointCoordinateEditor pEditor = new PointCoordinateEditor(GeometryMetadataHandler.getSupportedCRSMapping(this.espasCRS), PointCoordinateEditor.SUPPORTED_GEOMETRY._3D);
           for (Point p : this.shapePoints) {
               double[] coordinates = new double[]{
                  p.getCoordinate(Point.PolarCoord.LAT_Cord.name()), 
                  p.getCoordinate(Point.PolarCoord.LON_Cord.name()), 
                  p.getCoordinate(Point.PolarCoord.R_Cord.name())};

               coordinates = pEditor.transformCRS(new Date(), coordinates,
                       GeometryMetadataHandler.getSupportedCRSMapping(this.espasCRS),
                       GeometryMetadataHandler.getSupportedCRSMapping(toCRS.espasValue()));
               Point tPoint = new Point();
               tPoint.setCoordinate(Point.PolarCoord.LAT_Cord.name(), coordinates[0]);
               tPoint.setCoordinate(Point.PolarCoord.LON_Cord.name(), coordinates[1]);
               tPoint.setCoordinate(Point.PolarCoord.R_Cord.name(), coordinates[2]);
               transformedPoints.add(tPoint);
           }
           this.espasCRS = toCRS.espasValue();
           this.shapePoints = transformedPoints;
       }
   }
   
}
