/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package shapeUtil;

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import geomExtension.*;
import util.*;
import DrawTop.*;
import java.util.Vector;
import shape.*;
//****++++--------//
// GeometricTestLS
//----------------//
public class GeometricTestLS implements MouseListener, MouseMotionListener{
    int mode=NormalLinesFromMouse_Mode;
	boolean autoAlign=false;
    public static int NormalLinesFromMouse_Mode=1;
    public static int ShortestLineFromMouse_Mode=2;
    public static int ProjectionLinesFromMouse_Mode=3;
    public static int IntersectionPts_Mode=4;
	public static int NormalLinesBetweenShapes_Mode=5;
	public static int ShortestLineBetweenShapes_Mode=6;
    //public static int debug=0;
	public static int GeometricTestLS_debug=0;
	public static int drawNormalLines_debug=0;
	public static int drawShortestLine_debug=0;
	public static int drawProjectionLines_debug=0;
	public static int drawIntersectionPts_debug=0;
	public static int drawNormalLinesBetweenShapes_debug=0;
	public static int drawShortestLinesBetweenShapes_debug=1;
	

    public GeometricTestLS(){}
    
    public void start(){
		int debug=GeometricTestLS_debug;
        if(debug>0) System.out.println(" - GeometricTestLS start");
        ListenerPanel listenerPanel=ObjectTable.getListenerPanel();
        listenerPanel.addMouseListener(this);
        listenerPanel.addMouseMotionListener(this);
		this.autoAlign = DrawParameters.AUTO_ALIGN;
		DrawParameters.AUTO_ALIGN = false;
     }
     public void end(){
		 int debug=GeometricTestLS_debug;
        if(debug>0) System.out.println(" - GeometricTestLS end");
        ListenerPanel listenerPanel=ObjectTable.getListenerPanel();
        listenerPanel.removeMouseListener(this);
        listenerPanel.removeMouseMotionListener(this);
		DrawParameters.AUTO_ALIGN=this.autoAlign;
    }

    public void setMode(int mode){
        this.mode=mode;
    }

    public void mousePressed(MouseEvent e) {
		int debug=GeometricTestLS_debug;
        if(debug>0) System.out.println("** GeometricTestLS mousePressed");
        if(this.mode==IntersectionPts_Mode) this.drawIntersectionPTs();
		if(this.mode==NormalLinesBetweenShapes_Mode) this.drawNormalLinesBetweenShapes();
		if(this.mode==ShortestLineBetweenShapes_Mode) this.drawShortestLinesBetweenShapes();
        ObjectTable.getDrawPanel().repaint("GeometricTestLS");
     }
     
    public void mouseDragged(MouseEvent e) {
		int debug=GeometricTestLS_debug;
        if(debug>0) System.out.println("** GeometricTestLS mouseDragged");
        if(this.mode==IntersectionPts_Mode) this.drawIntersectionPTs();
		if(this.mode==NormalLinesBetweenShapes_Mode) this.drawNormalLinesBetweenShapes();
		if(this.mode==ShortestLineBetweenShapes_Mode) this.drawShortestLinesBetweenShapes();
        ObjectTable.getDrawPanel().repaint("GeometricTestLS");
    } //mouseDragged

    public void mouseMoved(MouseEvent e) {
		int debug=GeometricTestLS_debug;
        if(debug>0) System.out.println("** GeometricTestLS mouseMoved mode="+this.mode);
        double scale=DrawParameters.getScale();
        double X = e.getX()/scale;
        double Y = e.getY()/scale;
        Point2D point=new Point2D.Double(X,Y);
        if(this.mode==NormalLinesFromMouse_Mode) this.drawNormalPTs(point);
        if(this.mode==ShortestLineFromMouse_Mode) this.drawNearestPT(point);
        if(this.mode==ProjectionLinesFromMouse_Mode) this.drawProjectionPTs(point);
        ObjectTable.getDrawPanel().repaint("GeometricTestLS");
    } //mouseMoved

    public void mouseReleased(MouseEvent e) {
		int debug=GeometricTestLS_debug;
        if(debug>0) System.out.println("** GeometricTestLS mouseMoved mode="+this.mode);
        if(this.mode==IntersectionPts_Mode) this.drawIntersectionPTs();
        ObjectTable.getDrawPanel().repaint("GeometricTestLS");
    } 
    public void mouseClicked(MouseEvent e) {} 
    public void mouseEntered(MouseEvent e) {}
    public void mouseExited(MouseEvent e) {}
//****++++--------//
// drawNormalPTs
//----------------//
    protected void drawNormalPTs(Point2D point){
        DrawShapeUtil.clearTempShape("geomTest");
        ObjectTable.getDrawPanel().repaint();
        ContainerManager containerManager=ObjectTable.getContainerManager();
        ShapeContainer[] shapeContainers=containerManager.getAllSigleShapeContainers(true);
        for(int i=0;i<shapeContainers.length;i++){
            Curve2D curve2D=shapeContainers[i].getElement().getCurve2D();
            CurvePT[] curvePTs=Curve2DUtil.getNormalLines(point, curve2D);
            for(int j=0;j<curvePTs.length;j++){
                Line2D line=new Line2D.Double(point, curvePTs[j].getP());
                DrawShapeUtil.drawTempShape("geomTest", curvePTs[j].getP(),
                        DrawParameters.Mark_SmallSize, "", Color.RED);
                DrawShapeUtil.drawTempShape("geomTest", line, null, Color.RED,
                        null,"", null, Color.RED);
            }
        }
    }
//****+++----------//
// drawNearestPT
//-----------------//
    protected void drawNearestPT(Point2D point){
        DrawShapeUtil.clearTempShape("geomTest");
        ObjectTable.getDrawPanel().repaint();
        ContainerManager containerManager=ObjectTable.getContainerManager();
        ShapeContainer[] shapeContainers=containerManager.getAllSigleShapeContainers(true);
        for(int i=0;i<shapeContainers.length;i++){
            Curve2D curve2D=shapeContainers[i].getElement().getCurve2D();
            CurvePT curvePT=Curve2DUtil.getShortestLine(point, curve2D);
            Line2D line=new Line2D.Double(point, curvePT.getP());
            DrawShapeUtil.drawTempShape("geomTest", curvePT.getP(),
                    DrawParameters.Mark_SmallSize,"", Color.RED);
            DrawShapeUtil.drawTempShape("geomTest", line, null, Color.RED, null,"", null, Color.RED);
        }
    }
//****++++------------//
// drawProjectionPTs
//--------------------//
    protected void drawProjectionPTs(Point2D point){
        DrawShapeUtil.clearTempShape("geomTest");
        ObjectTable.getDrawPanel().repaint();
        ContainerManager containerManager=ObjectTable.getContainerManager();
        ShapeContainer[] shapeContainers=containerManager.getAllSigleShapeContainers(true);
        Vector2D[] unitVec=new Vector2D[4];
        unitVec[0]=new Vector2D(1d, 0d);
        unitVec[1]=Vector2D.unitVector(new Vector2D(1d, 1d));
        unitVec[2]=new Vector2D(0d, 1d);
        unitVec[3]=Vector2D.unitVector(new Vector2D(-1d, 1d));
        for(int i=0;i<shapeContainers.length;i++){
            Curve2D curve2D=shapeContainers[i].getElement().getCurve2D();
            for(int j=0;j<unitVec.length;j++){
                CurvePT[] curvePTs=Curve2DUtil.getProjectionLines(point, unitVec[j], curve2D);
                for(int k=0;k<curvePTs.length;k++){
                    Line2D line=new Line2D.Double(point, curvePTs[k].getP());
                    DrawShapeUtil.drawTempShape("geomTest", curvePTs[k].getP(),
                        DrawParameters.Mark_SmallSize, "", Color.RED);
                    DrawShapeUtil.drawTempShape("geomTest", line, null, Color.RED,
                        null,"", null, Color.RED);
                }
            }
        }
    }
//****++++-----------------//
// drawIntersectionPTs
//-------------------------//
    protected void drawIntersectionPTs(){
		int debug=drawIntersectionPts_debug;
        DrawShapeUtil.clearTempShape("geomTest");
        ObjectTable.getDrawPanel().repaint();
        ContainerManager containerManager=ObjectTable.getContainerManager();
        ShapeContainer[] selectedContainers=containerManager.getSelectedContainers();
        ShapeContainer[] containers=containerManager.getContainers();
        for(int i=0;i<selectedContainers.length;i++){
			for(int j=0;j<containers.length;j++){
				if(selectedContainers[i].getShapeId().equals(containers[j].getShapeId())) continue;
				ShapeContainer[] selectedShapes=selectedContainers[i].getGroupedSingleShapeContainers();
				ShapeContainer[] shapes=containers[j].getGroupedSingleShapeContainers();
				for(int k=0;k<selectedShapes.length;k++){
					for(int l=0;l<shapes.length;l++){
						if(debug>1) System.out.println("**GeometricTestLS.drawIntersectionPTs"+
							",Curve1="+selectedShapes[k].getShapeId()+
							",Curve2="+shapes[l].getShapeId());
						if(selectedShapes[k].getShapeId().equals(shapes[l].getShapeId())) continue;
						Rectangle2D box1=selectedShapes[k].getBoundingBox();
						Rectangle2D box2=shapes[l].getBoundingBox();
						if(!ShapeElementUtil.boxIntersectionCheck(box1, box2)) continue;
						Curve2D curve1=selectedShapes[k].getElement().getCurve2D();
						Curve2D curve2=shapes[l].getElement().getCurve2D();
						CrossCurvePT[] crossPTs=Curve2DUtil.getIntersectionPts(curve1, curve2);
						for(int n=0;n<crossPTs.length;n++){
							DrawShapeUtil.drawTempShape("geomTest", crossPTs[n].getP1(),
									DrawParameters.Mark_SmallSize,"", Color.RED);
						}
					}
				}
			}
        }
    }
//****++++--------------------//
// drawNormalLinesBetweenShapes
//----------------------------//
	protected void drawNormalLinesBetweenShapes(){
		int debug=drawNormalLinesBetweenShapes_debug;
		//boolean autoAlign=DrawParameters.AUTO_ALIGN;
		//DrawParameters.AUTO_ALIGN=false;
		String methodName="GeometricTestLS.drawNormalsBetweenShapes";
        DrawShapeUtil.clearTempShape("geomTest");
        ObjectTable.getDrawPanel().repaint();
	//-----------------------------------------------------//
		ShapeContainer[] containers=this.getClosestShapes();
	//-----------------------------------------------------//
		if(containers==null) return;
		ShapeContainer[] selectedShapes=containers[0].getGroupedSingleShapeContainers();
		ShapeContainer[] targetShapes=containers[1].getGroupedSingleShapeContainers();	
	  //--------------------------------------------------------//
		Vector normals=this.getNormalLinesBetweenSelectedCouple();
	  //--------------------------------------------------------//
		int size=normals.size();
		int id=0;
		Vector normalLines=new Vector();
		for(int i=0;i<size;i++){
			Curve2DUtil.NormalsInfo solution = (Curve2DUtil.NormalsInfo) normals.get(i);
			String shapeId1=solution.shapeIds[0];
			String shapeId2=solution.shapeIds[1];
			Curve2D selectedCurve=null;
			Curve2D targetCurve=null;
			for(int j=0;j<selectedShapes.length;j++){
				if(shapeId1.equals(selectedShapes[j].getShapeId())) 
					selectedCurve=selectedShapes[j].getElement().getCurve2D();
			}
			for(int j=0;j<targetShapes.length;j++){
				if(shapeId2.equals(targetShapes[j].getShapeId())) 
					targetCurve=targetShapes[j].getElement().getCurve2D();
			}
			if(selectedCurve==null||targetCurve==null){
				System.out.println("*** "+ methodName+ " Error"
						+ " selectedCurve or targetCurve equals null");
				return;
			}
			if (solution.type == Curve2DUtil.NormalsInfo.Solution) {
				double[] T = new double[2];
				T = solution.t;
				Point2D p1 = selectedCurve.getP(solution.t[0]);
				Point2D p2 = targetCurve.getP(solution.t[1]);
				Line2D line = new Line2D.Double(p1, p2);
				normalLines.add(line);
				id++;
			}
			if (solution.type == Curve2DUtil.NormalsInfo.IntervalSolution) {
				double[] t1 = new double[3];
				double[] t2 = new double[3];
				t1[0] = solution.interval[0];
				t1[1] = 0.5 * (solution.interval[0] + solution.interval[1]);
				t1[2] = solution.interval[1];
				t2[0] = solution.interval[2];
				t2[1] = 0.5 * (solution.interval[2] + solution.interval[3]);
				t2[2] = solution.interval[3];
				for (int n = 1; n < 2; n++) {
				//for (int n = 0; n <3; n++) {	
					Point2D p1 = selectedCurve.getP(t1[n]);
					Point2D p2 = targetCurve.getP(t2[n]);
					Line2D line = new Line2D.Double(p1, p2);
					normalLines.add(line);
					id++;
				}
			}
		}//for i
		int linesSize=normalLines.size();
		if(debug>0) System.out.println("**"+methodName+ " Vector normalLines  linesSize="+linesSize);
		for(int i=0;i<linesSize;i++){
			Line2D line=(Line2D)normalLines.get(i);
			double len=Vector2D.dist(line.getP1(), line.getP2());
			if(len>1.0e-4){
				DrawShapeUtil.drawTempShape("geomTest", line, null, Color.red,
                        null,"", null, Color.red);
			} else{
				DrawShapeUtil.drawTempShape("geomTest", line.getP1(),
									DrawParameters.Mark_SmallSize,"", Color.RED);
			}
		}
		//DrawParameters.AUTO_ALIGN=autoAlign;
	}
//++++-------------------------------//
// getNormalLinesBetweenSelectedCouple
//-----------------------------------//
	protected Vector getNormalLinesBetweenSelectedCouple(){
		int debug=drawNormalLinesBetweenShapes_debug;
		String methodName="GeometricTestLS.getNormalsBetweenShapes";
		if(debug>0) System.out.println("\n*** "+ methodName+ "-1 start ***");
		Vector normals=new Vector();
		Vector normalLines=new Vector();
	//-----------------------------------------------------//
		ShapeContainer[] containers=this.getClosestShapes();
	//-----------------------------------------------------//

		if(containers==null) return normalLines;
		ShapeContainer[] selectedShapes=containers[0].getGroupedSingleShapeContainers();
		ShapeContainer[] targetShapes=containers[1].getGroupedSingleShapeContainers();	
		for(int i=0;i<selectedShapes.length;i++){
			for(int j=0;j<targetShapes.length;j++){
				Curve2D selectedCurve=selectedShapes[i].getElement().getCurve2D();
				Curve2D targetCurve=targetShapes[j].getElement().getCurve2D();
				//-------------------------------------------------------------------------------//
				Vector vector=Curve2DUtil.getNormalLinesBetweenShapes(selectedCurve, targetCurve, 
				selectedShapes[i].getShapeId(), targetShapes[j].getShapeId());
				//-------------------------------------------------------------------------------//
				for(int k=0;k<vector.size();k++){
					normals.add(vector.get(k));
				}
			}
		}
		if(debug>0){
			int size=normals.size();
			String str="** "+ methodName+ "-2 normals size="+size+"\n";
			for(int i=0;i<size;i++){
				Curve2DUtil.NormalsInfo info=(Curve2DUtil.NormalsInfo)normals.get(i);
				str+=" - "+info.toString()+"\n";
			}
			System.out.println(str);
		}

		return normals;
	}

//++++--------------//
// getClosestShapes
//------------------//
	protected ShapeContainer[] getClosestShapes(){
		String methodName="GeometricTestLS.getClosestShapes";
		int debug=0;
        ContainerManager containerManager=ObjectTable.getContainerManager();
        ShapeContainer[] selectedContainers=containerManager.getSelectedContainers();
        ShapeContainer[] containers=containerManager.getContainers();
		if(selectedContainers==null||selectedContainers.length==0
				||containers==null||containers.length==0) return null;
		ShapeContainer selectedContainer=selectedContainers[0];
		Rectangle2D[] containerBoxes=new Rectangle2D[containers.length];
		for(int i=0;i<containers.length;i++){
			containerBoxes[i]=containers[i].getBoundingBox();
		}
		int selectedIndex=-1;
		String selectedShapeId=selectedContainer.getShapeId();
		for(int i=0;i<containers.length;i++){
			if(selectedShapeId.equals(containers[i].getShapeId())) selectedIndex=i;
		}
		if(selectedIndex<0) return null;

		int nearestIndex=-1;
		double X=containerBoxes[selectedIndex].getCenterX();
		double Y=containerBoxes[selectedIndex].getCenterY();
		
		double distMin=1.0e+4;
		for(int i=0;i<containers.length;i++){
			if(i==selectedIndex) continue;
			double dist=Curve2DUtil.distanceBetweenBoxes(containerBoxes[selectedIndex], containerBoxes[i]);
			if(dist<distMin){
				distMin=dist;
				nearestIndex=i;
			}
		}
		if(nearestIndex<0) {
			System.out.println("** "+ methodName+ " not found");
			return null;
		}
		if(debug>0) System.out.println("** "+ methodName
				+", Selected Shape="+containers[selectedIndex].getShapeId()
				+", Target Shape="+containers[nearestIndex].getShapeId()
				+", distMin="+Util.Num(distMin));
		ShapeContainer[] nearestContainers=new ShapeContainer[2];
		nearestContainers[0]=containers[selectedIndex];
		nearestContainers[1]=containers[nearestIndex];
		return nearestContainers;
	}

//****++++-------------------------//
// drawShortestLinesBetweenShapes
//---------------------------------//
	protected void drawShortestLinesBetweenShapes(){
		int debug=drawShortestLinesBetweenShapes_debug;
		String methodName="GeometricTestLS.drawShortestLinesBetweenShapes";
        DrawShapeUtil.clearTempShape("geomTest");
        ObjectTable.getDrawPanel().repaint();
		//------------------------------------------------------------------------//
		Vector shortestLinesInfos=this.getShortestLinesBetweenSelectedCouple();
		//-----------------------------------------------------------------------//
		int size=shortestLinesInfos.size();
		String str="";
		if(debug>0){
			str="** "+ methodName+ " shortestLinesInfos size="+size+"\n";
			for(int i=0;i<size;i++){
				Curve2DUtil.NormalsInfo info;
				info = (Curve2DUtil.NormalsInfo)shortestLinesInfos.get(i);
				str+=" - "+info.toString()+"\n";
			}
			System.out.println(str);
		}
		for(int i=0;i<size;i++){
			Curve2DUtil.NormalsInfo info;
			Line2D line=null;
			info = (Curve2DUtil.NormalsInfo)shortestLinesInfos.get(i);
			if (info.type == Curve2DUtil.NormalsInfo.Solution||
					info.type == Curve2DUtil.NormalsInfo.SegmentPtSolution) {
				double[] T = new double[2];
				T = info.t;
				Curve2D curve1=info.curves[0];
				Curve2D curve2=info.curves[1];
				Point2D p1 = curve1.getP(info.t[0]);
				Point2D p2 = curve2.getP(info.t[1]);
				line = new Line2D.Double(p1, p2);

			}
			if (info.type == Curve2DUtil.NormalsInfo.IntervalSolution) {
				Curve2D curve1=info.curves[0];
				Curve2D curve2=info.curves[1];
				double t1 = 0.5 * (info.interval[0] + info.interval[1]);
				double t2 = 0.5 * (info.interval[2] + info.interval[3]);
				Point2D p1 = curve1.getP(t1);
				Point2D p2 = curve2.getP(t2);
				line = new Line2D.Double(p1, p2);
			}

		    Color color=Color.red;
			if(info.type == Curve2DUtil.NormalsInfo.SegmentPtSolution){
				color=Color.blue;
			}
			double len=Vector2D.dist(line.getP1(), line.getP2());
			if(len<1.0e-4){
				DrawShapeUtil.drawTempShape("geomTest", line.getP1(),
									DrawParameters.Mark_SmallSize,"", Color.RED);
			} else{
				DrawShapeUtil.drawTempShape("geomTest", line, null, color,
                        null,"", null, Color.red);
				//System.out.println(" -- draw line");
			}
		}

	}

//++++----------------------------------//
// getShortestLinesBetweenSelectedCouple
//--------------------------------------//
	protected Vector getShortestLinesBetweenSelectedCouple(){
		int debug=drawShortestLinesBetweenShapes_debug;
		

		//Vector infos=new Vector();
		//Vector shortestLinesInfos=new Vector();
		Vector shortestLines=new Vector();
	//--------------------------------------------------------//
		ShapeContainer[] containers=this.getClosestShapes();
	//--------------------------------------------------------//
		if(containers==null) return shortestLines;
		ShapeContainer[] selectedShapes=containers[0].getGroupedSingleShapeContainers();
		ShapeContainer[] targetShapes=containers[1].getGroupedSingleShapeContainers();

		for(int i=0;i<selectedShapes.length;i++){
			for(int j=0;j<targetShapes.length;j++){
				Curve2D selectedCurve=selectedShapes[i].getElement().getCurve2D();
				Curve2D targetCurve=targetShapes[j].getElement().getCurve2D();
				//-------------------------------------------------------------------------//
				Vector output=Curve2DUtil.getShortestLineBetweenShapes(selectedCurve, targetCurve,
							selectedShapes[i].getShapeId(), targetShapes[j].getShapeId());
				//-------------------------------------------------------------------------//
				for(int k=0;k<output.size();k++){
					shortestLines.add(output.get(k));
				}
			}//for j
		}//for i

		if(debug>0){
			String methodName="GeometricTestLS.getShortestLinesBetweenSelectedCouple";
			int size=shortestLines.size();
			String str="** "+ methodName+ " - shortestLines size="+size+" **\n";
			for(int i=0;i<size;i++){
				Curve2DUtil.NormalsInfo info=(Curve2DUtil.NormalsInfo)shortestLines.get(i);
				str+=" - "+info.toString()+"\n";
			}
			System.out.println(str);
		}
		return shortestLines;
	}

} //end of ckass