package shapeUtil;

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


public class MoveResizeShapeLS implements MouseListener, MouseMotionListener{
    MousePositionInfo mousePositionInfo=null;
	ShapeContainer[] selectedContainers;
	int auto_tracking_option;
	boolean connected=false;
	boolean guided=false;
	
    ConnectionUtil connectionUtil=new ConnectionUtil();
    AutoAlign autoAlign=new AutoAlign(this);
    
    int mode=0;
    int mousePositionCode=0;
    int movePtIndex=0;
    Point2D startPoint=null; 
    Point2D newPoint=null;
    Point2D oldPoint=null;
    Rectangle2D startBox=null;
    Rectangle2D newBox=null;
    Rectangle2D oldBox=null;
    static final double Limit=5d;
    public static int debug=0;
    boolean test=true;

     
    public MoveResizeShapeLS(){}
    
    public void start(MousePositionInfo info, MouseEvent e){
        //------------------------------//
        int result = this.init(info, e);
        //-----------------------------//
        if (result != 0) {
            System.err.println("*** Error  MoveResizeShapeLS.init info:"+info.toString());
            return;
        }
        double scale=DrawParameters.getScale();
        double X = e.getX()/scale;
        double Y = e.getY()/scale;
        if(debug>0) System.out.println(" - MoveResizeShapeLS start");
        ListenerPanel listenerPanel=ObjectTable.getListenerPanel();
        listenerPanel.addMouseListener(this);
        listenerPanel.addMouseMotionListener(this);;
        ObjectTable.getSelectionLS().end();
        ShapeContainer[] containers=this.connectionUtil.getTargetsAndConnectors();
      //----------------------- undo setup--------------------------------------//  
        ContainerManager containerManager=ObjectTable.getContainerManager("");
        containerManager.undoSetupStart(containers);
      //-----------------------------------------------------------------------//   
        for(int i=0;i<containers.length;i++){
            containers[i].setConnectorPermission(true);
            containers[i].setConnectorTargetPermission(true);
        }
     }

    public int init(MousePositionInfo mousePositionInfo, MouseEvent e) {
        double scale=DrawParameters.getScale();
        double X = e.getX()/scale;
        double Y = e.getY()/scale;
        int key=e.getModifiersEx();
        int ctrl=0;
        if((key&InputEvent.SHIFT_DOWN_MASK)!=0) ctrl=1;
        if((key&InputEvent.CTRL_DOWN_MASK)!=0) ctrl=2;
        if((key&InputEvent.ALT_DOWN_MASK)!=0) ctrl=3;
        this.mousePositionInfo=mousePositionInfo;
        this.mousePositionCode=mousePositionInfo.getPosition();
        this.movePtIndex=mousePositionInfo.getEndPTindex();
       //set mode
        if(mousePositionInfo.onResizeMark()) this.mode=Command.RESIZING_MODE;
        else if(mousePositionInfo.onEndPoint()) this.mode=Command.MOVING_ENDPT_MODE;
        else this.mode=Command.MOVING_MODE;
        DrawParameters.MODE=Command.MOVING_MODE;
      //reselect containers for move endPT
        ContainerManager containerManager=ObjectTable.getContainerManager("");
        ShapeContainer[] selectedContainers=containerManager.getSelectedContainers();
        if(selectedContainers==null||selectedContainers.length==0){
            return -1;
        }
        
        if(this.mode==Command.MOVING_MODE||this.mode==Command.RESIZING_MODE){
            this.selectedContainers=selectedContainers;
        } else if(this.mode==Command.MOVING_ENDPT_MODE){
            ShapeContainer targetContainer=null;
            this.connected=false;
            targetContainer=this.mousePositionInfo.getContainer();
            if(this.isSuitableForMoveEndPT(targetContainer)) {
                this.selectedContainers=new ShapeContainer[1];
                this.selectedContainers[0]=targetContainer;
            }
        }
		
        if(DrawParameters.ENABLE_CONNECTOR){
            this.connectionUtil.setTargets(this.selectedContainers);   
        }
      //set data for MoveResize
        this.startPoint=new Point2D.Double(X,Y);
        this.oldPoint=new Point2D.Double(X,Y);
        this.startBox=ShapeElementUtil.getBoundingBox(this.selectedContainers);
        this.oldBox=(Rectangle2D)this.startBox.clone();
        for(int i=0;i<this.selectedContainers.length;i++){
            this.selectedContainers[i].getElement().mouseStart(ctrl, this.startPoint);
            this.selectedContainers[i].setMode(this.mode);
        }

        for(int i=0;i<this.selectedContainers.length;i++){
            this.selectedContainers[i].setConnectorPermission(true);
            this.selectedContainers[i].setConnectorTargetPermission(true);
        }
		
      // Auto_Align
        if(test){
            this.autoAlign.start(this.mode, this.mousePositionInfo, this.selectedContainers);
        } else{
            this.auto_tracking_option=DrawParameters.AUTO_TRACKING_OPTION;
            if(DrawParameters.AUTO_ALIGN){
                this.autoAlign.start(this.mode, this.mousePositionInfo,this.selectedContainers);
            }
        }
     //Connector
        if(test){
            this.connectionUtil.start(this.mode, this.mousePositionInfo,
                this.selectedContainers);
        }else{
            if(DrawParameters.ENABLE_CONNECTOR){
                this.connectionUtil.setTargets(this.selectedContainers);   
            }
        }
        
        return 0;
    }

     public void end(){
        if(debug>0) System.out.println(" -  MoveResizeShapeLS end");
        ListenerPanel listenerPanel=ObjectTable.getListenerPanel("AutoAlignLS");
        listenerPanel.removeMouseListener(this);
        listenerPanel.removeMouseMotionListener(this);
       // ObjectTable.moveResizeShapeLS=null;
        ObjectTable.getSelectionLS().start();
        for(int i=0;i<this.selectedContainers.length;i++){
            this.selectedContainers[i].setMode(Command.NORMAL_MODE);
        }  
        DrawParameters.MODE=Command.NORMAL_MODE;
        this.connectionUtil.end();
        ContainerManager containerManager=ObjectTable.getContainerManager("");
      //----------undo setup------------//
        containerManager.undoSetupEnd();
      //--------------------------------// 
        DrawShapeUtil.clearTempShape("Connection.pt");
        DrawShapeUtil.clearTempShape("Guide.pt");
        DrawShapeUtil.clearTempShape("ConnectionMark");
        ObjectTable.getDrawPanel().repaint();
    }

    public boolean isSuitableForMoveEndPT(ShapeContainer container){
        int containerType=container.getContainerType();
        int type=container.getElement().getTypeE();
        if(containerType==ShapeContainer.GROUP) return false;
        if(type<Command.LINE||type>Command.GENERAL_CURVE) return false;
        if(container.getElement().isClosed()) return false;
        return true;
    }

    public void mousePressed(MouseEvent e){}
    
    public void mouseDragged(MouseEvent e) {
        double scale=DrawParameters.getScale();
        double X = e.getX()/scale;
        double Y = e.getY()/scale;
        int key=e.getModifiersEx();
        int ctrl=0;
        if((key&InputEvent.SHIFT_DOWN_MASK)!=0) ctrl=1;
        if((key&InputEvent.CTRL_DOWN_MASK)!=0) ctrl=2;
        if((key&InputEvent.ALT_DOWN_MASK)!=0) ctrl=3;
        this.newPoint=new Point2D.Double(X,Y);

       //move 
        if(this.mode==Command.MOVING_MODE){
            for(int i=0;i<this.selectedContainers.length;i++){
                this.selectedContainers[i].getElement().move(ctrl, this.newPoint, true);
            }
            if(DrawParameters.ENABLE_CONNECTOR&&ctrl>0){
                this.guided=this.connectionUtil.resizeTargetsByGuideLines();
            }
        }
      //resize 
        if(this.mode==Command.RESIZING_MODE){
            for(int i=0;i<this.selectedContainers.length;i++){
                String mousePosition=MousePositionInfo.getPositionString(mousePositionCode);
                this.selectedContainers[i].getElement().resize(ctrl, this.newPoint, mousePosition, true);
            }
        }

      //move endPT  
        if(this.mode==Command.MOVING_ENDPT_MODE){
            if(this.isSuitableForMoveEndPT(this.selectedContainers[0])){
                ShapeElement shapeElement=this.selectedContainers[0].getElement();
                shapeElement.moveEndPoint(ctrl, this.movePtIndex, this.newPoint);
                ObjectTable.getDrawPanel().repaint("MoveRsize");
            }
          //Replaced by ConnectionUtil.mouseDragged
            if(DrawParameters.ENABLE_CONNECTOR&&!test){
                ConnectionLS connectionLS=ObjectTable.getConnectionLS();
                boolean lineDir=false;
                //boolean lineDir=this.selectedContainers[0].getLineDirectionProperty();
                Curve2D curve=this.selectedContainers[0].getElement().getCurve2D();
                int endIndex=curve.getCloseEndpointIndex(this.newPoint);
                Point2D endPT=curve.getP(endIndex);
                Vector2D vec=curve.getTangent(endIndex);
                CurvePT connectionPT=null;
                if(ctrl>0||lineDir) {
                    connectionPT = connectionLS.drawMouseHitPT(1, endPT, vec,
                            this.selectedContainers[0]);
                } else {
                    connectionPT = connectionLS.drawMouseHitPT(0, endPT, null,
                            this.selectedContainers[0]);
                }
                if(connectionPT!=null){
                    ShapeElement shapeElement=this.selectedContainers[0].getElement();
                    Point2D replacedPT=connectionPT.getP();
                    shapeElement.moveEndPoint(ctrl, this.movePtIndex, replacedPT);
                    this.connected=true;
                    if(debug>0) System.out.println("mouseDragged  endPT="+
                            Util.Pt(endPT)+", replacedPT="+Util.Pt(replacedPT));
                }
            }
        }
      //Auto_Align, Connector  
        if(test){
            this.autoAlign.mouseDragged(e);
            this.connectionUtil.mouseDragged(e);
        } else{
            if(DrawParameters.AUTO_ALIGN) {
                this.autoAlign.drawHitAligns();
            }
            this.connectionUtil.resizeConnectors(this.auto_tracking_option);
        }
        
        this.oldPoint=this.newPoint;
        this.oldBox=this.newBox;
        ObjectTable.getDrawPanel().repaint("MoveRsize");
 
    } //mouseDragged

    public void mouseReleased(MouseEvent e) {
        int ctrl=0;
        int key=e.getModifiersEx();
        if((key&InputEvent.SHIFT_DOWN_MASK)!=0) ctrl=1;
        if((key&InputEvent.CTRL_DOWN_MASK)!=0) ctrl=2;
        if((key&InputEvent.ALT_DOWN_MASK)!=0) ctrl=3;
      //connect mouseHitContainer to target
        if(this.mode==Command.MOVING_ENDPT_MODE&&DrawParameters.ENABLE_CONNECTOR){}
      //Auto_align, Connector
        if(test){
            this.autoAlign.mouseReleased(e);
            this.connectionUtil.mouseReleased(e);
        } else {
            if(DrawParameters.AUTO_ALIGN){
                if(this.mode==Command.MOVING_ENDPT_MODE){
                    if(!this.connected){
                        this.autoAlign.ajustAlignment(ctrl);
                        this.connectionUtil.resizeConnectors(this.auto_tracking_option);
                    }
                } else {
                    if(!this.guided) this.autoAlign.ajustAlignment(ctrl);
                    this.connectionUtil.resizeConnectors(this.auto_tracking_option);
                }
            }
        }
        this.startPoint=null;
        this.newPoint=null;
        ObjectTable.getDrawPanel().repaint("MoveRsize");
        this.end();
    } //mouseReleased

    public void mouseClicked(MouseEvent e) {} 
    public void mouseEntered(MouseEvent e) {}
    public void mouseExited(MouseEvent e) {}
    public void mouseMoved(MouseEvent e) {}

/*  
//Move the followings to ShapeElementUtil
    public static Rectangle2D resizeRectangle(int ctrl, Rectangle2D startBox, Point2D startPoint, 
            Point2D currentPoint, int mousePosition) {
        Vector2D moveVec=Vector2D.sub(currentPoint, startPoint);
        Rectangle2D newBox=resizeRectangle(ctrl, startBox, moveVec, mousePosition);
        return newBox;
    }

    public static Rectangle2D resizeRectangle(int ctrl, Rectangle2D startBox, Vector2D moveVec, int mousePosition) {
        Vector2D startBoxP=new Vector2D(startBox.getX(), startBox.getY());
        double W=startBox.getWidth();
        double H=startBox.getHeight();
        Vector2D anchorP=null;
        Vector2D movingP=null;
        Rectangle2D newBox=null;
        //NW
        if(mousePosition==MousePositionInfo.NW_RESIZE) {
            movingP=new Vector2D(startBoxP.getX(), startBox.getY());
            anchorP=Vector2D.add(startBoxP, new Vector2D(W,H));
            newBox=resizeDiagonally(ctrl, anchorP, movingP, moveVec);
        }
        //NE
        if(mousePosition==MousePositionInfo.NE_RESIZE) {
            movingP=Vector2D.add(startBoxP, new Vector2D(W,0d));
            anchorP=Vector2D.add(startBoxP, new Vector2D(0d,H));
            newBox=resizeDiagonally(ctrl, anchorP, movingP, moveVec);
        }
        //SE
        if(mousePosition==MousePositionInfo.SE_RESIZE) {
            movingP=Vector2D.add(startBoxP, new Vector2D(W,H));
            anchorP=startBoxP;
            newBox=resizeDiagonally(ctrl, anchorP, movingP, moveVec);
        }
        //SW
        if(mousePosition==MousePositionInfo.SW_RESIZE) {
            movingP=Vector2D.add(startBoxP, new Vector2D(0d,H));
            anchorP=Vector2D.add(startBoxP, new Vector2D(W,0d));
            newBox=resizeDiagonally(ctrl, anchorP, movingP, moveVec);
        }
        //N
        if(mousePosition==MousePositionInfo.N_RESIZE) {
            movingP=Vector2D.add(startBoxP, new Vector2D(0.5*W,0));
            anchorP=Vector2D.add(startBoxP, new Vector2D(0.5*W,H));
            newBox=resizeOrthogonally(ctrl, 1, anchorP, movingP, moveVec, W);
        }
        //E
        if(mousePosition==MousePositionInfo.E_RESIZE) {
            movingP=Vector2D.add(startBoxP, new Vector2D(W,0.5*H));
            anchorP=Vector2D.add(startBoxP, new Vector2D(0,0.5*H));
            newBox=resizeOrthogonally(ctrl, 0, anchorP, movingP, moveVec, H);
        }
        //S
        if(mousePosition==MousePositionInfo.S_RESIZE) {

            movingP=Vector2D.add(startBoxP, new Vector2D(0.5*W,H));
            anchorP=Vector2D.add(startBoxP, new Vector2D(0.5*W,0));
            newBox=resizeOrthogonally(ctrl, 1, anchorP, movingP, moveVec, W);
        }
        //W
        if(mousePosition==MousePositionInfo.W_RESIZE) {
            movingP=Vector2D.add(startBoxP, new Vector2D(0,0.5*H));
            anchorP=Vector2D.add(startBoxP, new Vector2D(W,0.5*H));
            newBox=resizeOrthogonally(ctrl, 0, anchorP, movingP, moveVec, H);
        }
        return newBox;
    }

    private static Rectangle2D resizeDiagonally(int ctrl, Vector2D anchorP, Vector2D movingP, 
            Vector2D moveVec){

        Vector2D boxDiagonal=Vector2D.sub(movingP, anchorP);     
        double startW=boxDiagonal.getX();
        double startH=boxDiagonal.getY();
        double signW=Math.signum(startW);
        double signH=Math.signum(startH);
        
        Vector2D newP=Vector2D.add(movingP,moveVec);
        double newW=newP.getX()-anchorP.getX();
        double newH=newP.getY()-anchorP.getY();
        double newSignW=Math.signum(newW);
        double newSignH=Math.signum(newH);
        
        if(Math.abs(newW)<Limit||newSignW!=signW) newW=Limit*signW;
        if(Math.abs(newH)<Limit||newSignH!=signH) newH=Limit*signH;
      
        if(ctrl==1||ctrl==2){
            if(startW>startH) newH=newW*startH/startW;
            else newW=newH*startW/startH;
        }
        if(ctrl==3){
            double dir=Vector2D.sproduct(boxDiagonal, moveVec);
            double newWH=Math.min(Math.abs(newW), Math.abs(newH));
            if(dir>0) newWH=Math.max(Math.abs(newW), Math.abs(newH));
            newW=newWH*signW;
            newH=newWH*signH;
        }
        newP=Vector2D.add(anchorP, new Vector2D(newW, newH));
        double x=Math.min(anchorP.getX(), newP.getX());
        double y=Math.min(anchorP.getY(), newP.getY());
        Rectangle2D newBox=new Rectangle2D.Double(x, y, Math.abs(newW), Math.abs(newH));
        return newBox;
    }

    private static Rectangle2D resizeOrthogonally(int ctrl, int dir, Vector2D anchorP, Vector2D movingP, 
            Vector2D draggedVec, double fixedWH){
        Vector2D[] unitV=new Vector2D[2];
        unitV[0]=new Vector2D(1,0);
        unitV[1]=new Vector2D(0,1);
        Vector2D draggedV=Vector2D.multiply(Vector2D.sproduct(unitV[dir], draggedVec),unitV[dir]);
        
        double signedWorH=Vector2D.sproduct(Vector2D.sub(movingP, anchorP), unitV[dir]);
        double sign=Math.signum(signedWorH);
        
        Vector2D newP=Vector2D.add(movingP, draggedV);
        double newSignedWorH=Vector2D.sproduct(Vector2D.sub(newP, anchorP), unitV[dir]);
        double newSign=Math.signum(newSignedWorH);
        
        if(Math.abs(newSignedWorH)<Limit||newSign!=sign) newSignedWorH=Limit*sign;
        double newW=fixedWH;
      // Currently ctrl=1,2, and 3 is disable
        if(ctrl==-1||ctrl==-2) newW=Math.abs(newSignedWorH)*fixedWH/signedWorH; 
        if(ctrl==-3) newW=Math.abs(newSignedWorH);
        Vector2D[] P=new Vector2D[4];
        Vector2D wingP=Vector2D.multiply(0.5*newW, unitV[1-dir]);
        P[0]=Vector2D.add(anchorP, wingP);
        P[1]=Vector2D.sub(anchorP, wingP);
        P[2]=Vector2D.add(newP, wingP);
        P[3]=Vector2D.sub(newP, wingP);
        double x=1.0e+5;
        double y=1.0e+5;
        for(int i=0;i<4;i++){
            if(P[i].getX()<x) x=P[i].getX();
            if(P[i].getY()<y) y=P[i].getY();
        }
        Rectangle2D newBox=null;
        if(dir==0) newBox=new Rectangle2D.Double(x, y, Math.abs(newSignedWorH), Math.abs(newW));
        else newBox=new Rectangle2D.Double(x, y, Math.abs(newW), Math.abs(newSignedWorH));
        return newBox;
    }
*/
} //end of MoveResizeShapeLS
