package shape;

import java.awt.*;
import java.awt.geom.*;
import java.util.*;
import javax.swing.*;
import DrawTop.*;
import geomExtension.*;
import util.*;
import util.UndoConstants;

public class PolylineElement extends ShapeElement {

    int debug = 0;

    public PolylineElement() {
        super();
    }

//ShapeElement
    public int getTypeE() {
        return Command.POLYLINE;
    }
    //ShapeElement

    public String getShapeIdString() {
        return "Polyline";
    }

    public Rectangle2D createTextArea() {
        if (!this.isClosed()) {
            return null;
        }
        Shape shape = this.getShape();
        double sqrt2 = Math.sqrt(2);
        //------------------------------------------------------------------------//
        Rectangle2D textArea=ShapeElementUtil.getInscribedBox(shape, false);
        //------------------------------------------------------------------------//
        return textArea;
    }

    public Point2D[] getEndPTs() {
        Point2D[] PTs = new Point2D[2];
        int numseg = this.curve2D.getNumOfSegments();
        PTs[0] = this.curve2D.getP(0);
        PTs[1] = this.curve2D.getP(numseg);
        return PTs;
    }

//ShapeElement
    public SegmentModifier[] getSegmentModifiers(){
        SegmentModifier[] modifiers=new SegmentModifier[0];
        return modifiers;
    }
//ShapeElement
    public Point2D[] getModifierPTs(){
        Point2D[] PTs=new Point2D[0];
        return PTs;
    }

//ShapeElement
    public void mouseStart(int ctrl, Point2D startPoint) {
        super.mouseStart(ctrl, startPoint);
    }

//ShapeElement

    public void create(Rectangle2D boundingBox) {
    }

    public void create(Point2D startPoint, Point2D currentPoint) {
    }

    public void create(Point2D[] points) {
        if (points.length > 1) {
            this.curve2D = new Polyline2DE(points);
        }
    }
    
//moveEndPoint method is called from mouseDragged of AutoAlignLS
    
//moveEndPoint method is called from mouseDragged of AutoAlignLS
    public void moveEndPoint(int ctrl, int movePtIndex, Point2D currentPoint){
        boolean resizable=this.shapeContainer.getBooleanProperty("Enable_Resizing", "LineElemrent");
        if(!resizable) return;
        boolean keep_line_direction=this.shapeContainer.getBooleanProperty("Keep_Line_Direction", 
                "PolylineElemrent");
        if(keep_line_direction) ctrl=3;

        this.getShapeContainer().setChangeCode(UndoConstants.SHAPE);
        Point2D newP=currentPoint;
        if (ctrl==1||ctrl==2) {
            newP = DiscreteAngledLine.getControlledPT(0d, 90d, this.startPoint, currentPoint);
        }
        Polyline2DE polyLine = (Polyline2DE) this.curve2D;

        //--------------------------------------//
        Point2D[] points = polyLine.getPoints();
        //--------------------------------------//
      int size = 0;
        if (points != null) {
            size = points.length;
        }
        Point2D oldP=points[0];
        if(movePtIndex>0) oldP=points[size - 1];
        double moveX=newP.getX()-oldP.getX();
        double moveY=newP.getY()-oldP.getY();
  
        if (movePtIndex == 0) {
            if (size == 2) {
                points[0] = newP;
            } else if (size >= 3) {
                Line2D line = new Line2D.Double(points[0], points[1]);
                Line2D newLine = this.moveLineSegment(line, moveX, moveY);
                points[0] = newLine.getP1();
                points[1] = newLine.getP2();
            }
            this.curve2D = new Polyline2DE(points);
        } else {
            if (size == 2) {
                points[size - 1] = newP;
            } else if (size >= 3) {
                Line2D line = new Line2D.Double(points[size - 1], points[size - 2]);
                Line2D newLine = this.moveLineSegment(line, moveX, moveY);
                points[size - 1] = newLine.getP1();
                points[size - 2] = newLine.getP2();
            }
            polyLine.setData(points);
        }
    }

    public void moveEndPoint(int ctrl, int movePtIndex, Point2D oldPoint, Point2D currentPoint) {
        if(ctrl>=3) return;
        this.getShapeContainer().setChangeCode(UndoConstants.SHAPE);
        Vector2D moveVec = Vector2D.sub(currentPoint, oldPoint);
        if (ctrl==1||ctrl==2) {
            Point2D newP = DiscreteAngledLine.getControlledPT(0d, 90d, oldPoint, currentPoint);
            Vector2D unitVec = Vector2D.unitVector(Vector2D.sub(newP, oldPoint));
            moveVec = Vector2D.multiply(Vector2D.sproduct(moveVec, unitVec), unitVec);
        }
        double moveX = moveVec.getX();
        double moveY = moveVec.getY();
        Polyline2DE polyLine = (Polyline2DE) this.curve2D;
        //--------------------------------------//
        Point2D[] points = polyLine.getPoints();
        //--------------------------------------//
        int size = 0;
        if (points != null) {
            size = points.length;
        }
        if (movePtIndex == 0) {
            if (size == 2) {
                points[0] = new Point2D.Double(points[0].getX() + moveX,
                        points[0].getY() + moveY);
            } else if (size >= 3) {
                Line2D line = new Line2D.Double(points[0], points[1]);
                Line2D newLine = this.moveLineSegment(line, moveX, moveY);
                points[0] = newLine.getP1();
                points[1] = newLine.getP2();
            }
            this.curve2D = new Polyline2DE(points);
        } else {
            if (size == 2) {
                points[size - 1] = new Point2D.Double(points[size - 1].getX() + moveX,
                        points[size - 1].getY() + moveY);
            } else if (size >= 3) {
                Line2D line = new Line2D.Double(points[size - 1], points[size - 2]);
                Line2D newLine = this.moveLineSegment(line, moveX, moveY);
                points[size - 1] = newLine.getP1();
                points[size - 2] = newLine.getP2();
            }
            polyLine.setData(points);
        }
    }

    private Line2D moveLineSegment(Line2D line, double moveX, double moveY) {
        this.getShapeContainer().setChangeCode(UndoConstants.SHAPE);
        Vector2D newPt0=null;
        Vector2D newPt1=null;
        int imax=10;
        for(int i=0;i<imax;i++){
            double delta=1-(double)i/(double)imax;
            double mX=moveX*delta;
            double mY=moveY*delta;
            Vector2D moveVec = new Vector2D(mX, mY);
            Vector2D pt0 = new Vector2D(line.getP1());
            Vector2D pt1 = new Vector2D(line.getP2());
            Vector2D unitVec = Vector2D.unitVector(Vector2D.sub(pt1, pt0));
            Vector2D normalVec = Vector2D.normalVector(unitVec);
            double sprodN = Vector2D.sproduct(normalVec, moveVec);
            Vector2D moveN = Vector2D.multiply(sprodN, normalVec);
            newPt0 = Vector2D.add(pt0, moveVec);
            newPt1 = Vector2D.add(pt1, moveN);
            double dist=Vector2D.dist(newPt0, newPt1);
            if(dist>0.1) break;
        }
        Line2D newLine = new Line2D.Double(newPt0.getX(), newPt0.getY(), newPt1.getX(), newPt1.getY());
        return newLine;
    }
    
    public void modify(int ctrl, Point2D oldPoint, Point2D currentPoint){};
    public void modifyPoint(Point2D point, String command){};

//ShapeElement
    public Object clone() {
        PolylineElement shapeElement = new PolylineElement();
        Polyline2DE curve = (Polyline2DE) curve2D.clone();
        shapeElement.setCurve2D(curve);
        return shapeElement;
    }
//ShapeElement

    public String toString() {
        String str="";
        if (this.curve2D == null) {
            str += "Polyline: not defined";
            return str;
        }
        return this.curve2D.toString();
    }
}
