package shape;

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


public class GeneralCurveElement extends ShapeElement {
    SegmentModifier[] segmentModifiers=null;
    SegmentModifier hitSegmentModifier=null;
    boolean topologyChanged=false;
    
    public GeneralCurveElement(){
        super();
    }

//ShapeElement
    public int getTypeE(){
        return Command.GENERAL_CURVE;
    }
    
     public String getShapeIdString(){
         return "GeneralCurve";
     }

    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 ShapeElement[] getSimpleShapeElements(){
        GeneralCurve2DE gcurve=(GeneralCurve2DE)this.getCurve2D();
        Curve2D[] curves=gcurve.getSimpleCurve2Ds();
        ShapeElement[] newElements=new ShapeElement[curves.length];
        for(int i=0;i<curves.length;i++){
            int type=curves[i].getType2DE();
            if(type==Command.LINE) newElements[i]=new LineElement();
            if(type==Command.POLYLINE) newElements[i]=new PolylineElement();
            if(type==Command.CUBIC_CURVE) newElements[i]=new CubicCurveElement();
            if(type==Command.GENERAL_CURVE) newElements[i]=new GeneralCurveElement();
            newElements[i].setCurve2D(curves[i]);
        }
        if(debug>0){
            String str="GeneralCurveElement.getSimpleShapeElements";
            for(int i=0;i<newElements.length;i++){
                str+="\n newElements["+i+"]: "+newElements[i].toString();
            }
            System.out.println(str);
        }
        return newElements;
    }
    public SegmentModifier[] getSegmentModifiers(){
        return SegmentModifier.getSegmentModifiers(this.curve2D);
    }

    public Point2D[] getModifierPTs(){
        SegmentModifier[] modifiers=this.getSegmentModifiers();
        this.workVector.clear();
        Point2D PT=null;
        for(int i=0;i<modifiers.length;i++){
            PT=modifiers[i].getP();
            if(PT!=null) this.workVector.add(PT);
            PT=modifiers[i].getTinP1();
            if(PT!=null) this.workVector.add(PT);
            PT=modifiers[i].getTinP2();
            if(PT!=null) this.workVector.add(PT);
            PT=modifiers[i].getToutP1();
            if(PT!=null) this.workVector.add(PT);
            PT=modifiers[i].getToutP2();
            if(PT!=null) this.workVector.add(PT);
        }
        Point2D[] PTs=new Point2D[workVector.size()];
        for(int i=0;i<workVector.size();i++) PTs[i]=(Point2D)this.workVector.get(i);
        return PTs;
    }
//ShapeElement
    public void mouseStart(int ctrl, Point2D startPoint){
        super.mouseStart(ctrl, startPoint);
        this.segmentModifiers = this.getSegmentModifiers();
        this.hitSegmentModifier=SegmentModifier.getHitSegmentModifier(this.segmentModifiers, startPoint);
        this.topologyChanged=false;
        if(this.hitSegmentModifier==null) System.out.println("modify hit=null");
        else if(debug>0) System.out.println("modify hit:"+this.hitSegmentModifier.toString());
    }
//ShapeElement
    public void mouseEnd(){
        ObjectTable.getTempShapeManager("GeneralCurveElement").clearTempShape("modify_close");
        ObjectTable.getTempShapeManager("GeneralCurveElement").clearTempShape("modify_connect");
    }
//ShapeElement
    public void creationStart(int ctrl, Point2D point){}
    public void create(Rectangle2D boundingBox){}
    public void create(Point2D startPoint, Point2D currentPoint){}
    public void create(Point2D[] points){}
    public void creationEnd(){}

    public void moveEndPoint(int ctrl, int movePtIndex, Point2D currentPoint){};

    public void moveEndPoint(int ctrl, int movingPoint, Point2D oldPoint, Point2D currentPoint){
        if(ctrl>=3) return;
        this.getShapeContainer().setChangeCode(UndoConstants.SHAPE);
        Point2D newPT=currentPoint;
        Point2D oldPT=oldPoint;
        if(ctrl>0) {
            newPT=DiscreteAngledLine.getControlledPT(0, 90, oldPoint, newPT);
            oldPT=DiscreteAngledLine.getControlledPT(0, 90, oldPoint, oldPT);
        }
        Point2D anchorP=null;
        int numseg=this.curve2D.getNumOfSegments();
        if(movingPoint==0) anchorP=this.curve2D.getP(numseg);
        else anchorP=this.curve2D.getP(0);
        Vector2D r0=Vector2D.sub(oldPT,anchorP);
        Vector2D r=Vector2D.sub(newPT,anchorP);
        Matrix2D rotationMatrix=Matrix2D.getRotationMatrix(anchorP, r0, r);
        if(debug>0)System.out.println("  moveEndPoint movingPoint="+movingPoint+
                "  r0,r1="+r0.toString()+" ,"+r.toString());
        Segment2D[]segments=new Segment2D[numseg];
        for(int i=0;i<numseg;i++) {
            segments[i]=(Segment2D)this.curve2D.getSegment2D(i);
            segments[i]=segments[i].transformSegment(rotationMatrix);
        }
        this.curve2D.setData(segments);
    }

    public  void modify(int ctrl, Point2D oldPoint, Point2D currentPoint){
        if(this.topologyChanged) return;
        this.topologyChanged=SegmentModifier.modify(this.curve2D, this.hitSegmentModifier, ctrl, 
                this.startPoint, oldPoint, currentPoint);
    }

    public void modifyPoint(Point2D point, String command){
        if(debug>0) System.out.println("modifyPoint command="+command);
        if(command.equals("add_point")) 
            SegmentModifier.addPoint(this.curve2D, this.hitSegmentModifier, point);
        if(command.equals("delete_point")) 
            SegmentModifier.deletePoint(this.curve2D, this.hitSegmentModifier);
        if(command.equals("smooth")) 
            SegmentModifier.smoothPoint(this.curve2D, this.hitSegmentModifier);
        if(command.equals("cusp")) 
            SegmentModifier.cuspPoint(this.curve2D, this.hitSegmentModifier);
        if(command.equals("disconnect")) 
            SegmentModifier.disconnectPoint(this.curve2D, this.hitSegmentModifier);
    }

//ShapeElement
    public Object clone(){
        GeneralCurveElement shapeElement=new GeneralCurveElement();
        GeneralCurve2DE generalCurve=(GeneralCurve2DE)curve2D.clone();
        shapeElement.setCurve2D(generalCurve);
        return shapeElement;
    }
    
//ShapeElement
    public String toString(){
        String str="";
        if (this.curve2D == null) {
            str += "GeneralCurve: not defined";
            return str;
        }
        return this.curve2D.toString();
    }

} //end of GeneralCurveElement
