/*
 * 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 DrawTop.*;
import shape.*;
import menu.*;
import util.*;
import geomExtension.*;

public class CreateShapeLS implements MouseListener, MouseMotionListener{
    ShapeContainer shapeContainer=null;
    ShapeElement shapeElement=null;
    int commandId=0;
    //ConnectionLS connectionPointLS=ObjectTable.getConnectionPointLS();
    boolean isLineFamily=false;
    boolean isPolylineFamily=false;
    boolean isRectangleFamily=false;
    boolean isComponentFamily=false;
    Point2D startPoint=null; 
    Point2D endPoint=null;
    Point2D oldPoint=null;
    Point2D pressedPoint=null;
    Point2D draggedPoint=null;
    boolean clicked=false;
    boolean rightButtonPressed=false;
    int ctrl=0;
    Point2D[] committedNodePoints=new Point2D[0];
    Point2D[] tentativeNodePoints=new Point2D[0];
    
    public static int debug=0;
    int tempShapeNumber=0;
    int idNumber=0;
     
    public CreateShapeLS(){}
    
    public void creatingStart(int commandId){
        this.shapeContainer=new ShapeContainer();
        this.shapeContainer.setMode(Command.CREATING_MODE);
        DrawParameters.MODE=Command.CREATING_MODE;
        this.shapeContainer.setSelected(true);
        this.commandId=commandId;
        if(commandId>=Command.LINE&&commandId<=Command.DOUBLE_ARROW) this.isLineFamily=true;
        if(commandId>=Command.POLYLINE&&commandId<=Command.CUBIC_CURVE) this.isPolylineFamily=true;
        if(commandId>=Command.TEXTBOX&&commandId<=Command.IMAGE) this.isRectangleFamily=true;
        if(commandId==Command.COMPONENT_SHAPE) this.isComponentFamily=true;
        ListenerPanel listenerPanel=ObjectTable.getListenerPanel();
        listenerPanel.addMouseListener(this);
        listenerPanel.addMouseMotionListener(this);
      //---------------------------------------------------------//   
        ObjectTable.getSelectionLS().end();
        ObjectTable.getConnectionLS().activateListener(false);
      //---------------------------------------------------------//   
        ObjectTable.getDrawMain().setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
        if(debug>0) System.out.println("creatingStart" +
                " shapeElementType="+commandId+", "+Command.getCommandString(commandId));
        //ShapeElement shapeElement=null;
        switch(commandId){
            case Command.TEXTBOX : {
                this.shapeElement=new RectangleElement();
                this.shapeContainer.setElement(this.shapeElement);
                this.shapeElement.setShapeContainer(this.shapeContainer);
                break;
            }
            case Command.RECTANGLE : {
                this.shapeElement=new RectangleElement();
                this.shapeContainer.setElement(this.shapeElement);
                this.shapeElement.setShapeContainer(this.shapeContainer);
                break;
            }
            case Command.ROUND_RECTANGLE: {
                this.shapeElement=new RoundRectangleElement();
                this.shapeContainer.setElement(this.shapeElement);
                this.shapeElement.setShapeContainer(this.shapeContainer);
                break;
            }
            case Command.ELLIPSE: {
                this.shapeElement=new EllipseElement();
                this.shapeContainer.setElement(this.shapeElement);
                this.shapeElement.setShapeContainer(this.shapeContainer);
                break;
            }
            case Command.LINE: {
                this.shapeElement=new LineElement();
                this.shapeContainer.setElement(this.shapeElement);
                this.shapeElement.setShapeContainer(this.shapeContainer);
                break;
            }
            case Command.ARROW: {
                this.shapeElement=new LineElement();
                this.shapeContainer.setElement(this.shapeElement);
                this.shapeElement.setShapeContainer(this.shapeContainer);
                this.shapeContainer.setArrowStyle("5");
                break;
            }
            case Command.DOUBLE_ARROW: {
                this.shapeElement=new LineElement();
                this.shapeContainer.setElement(this.shapeElement);
                this.shapeElement.setShapeContainer(this.shapeContainer);
                this.shapeContainer.setArrowStyle("7");
                break;
            }
            case Command.POLYLINE: {
                this.shapeElement=new PolylineElement();
                this.shapeContainer.setElement(this.shapeElement);
                this.shapeElement.setShapeContainer(this.shapeContainer);
                break;
            }
            case Command.CUBIC_CURVE: {
                this.shapeElement=new CubicCurveElement();
                this.shapeContainer.setElement(this.shapeElement);
                this.shapeElement.setShapeContainer(this.shapeContainer);
                break;
            }
            case Command.COMPONENT_SHAPE: {
                this.shapeContainer.setMode(Command.LIB);
                MenuUtil menuUtil=ObjectTable.getMenuUtil();
                Component[] components
                        =menuUtil.getMenuComponents(Command.getCommandString(Command.LIB));
                if(components==null) {
                    System.err.println("*** Error CreateShapeLS.creatingStart:" +
                            "ialogOfComponent not found");
                    return;
                }
                Component targetObject=null;
                for(int i=0;i<components.length;i++){
                    String simpleName=components[i].getClass().getSimpleName();
                    if(simpleName.startsWith("ComponentLibDialog")){
                        targetObject=components[i];
                        break;
                    }
                }
                if(targetObject==null){
                    System.err.println("*** Error CreateShapeLS.creatingStart: " +
                            "ComponentLibDialog not found by MenuUtil.getDrawMenu");
                    this.abort();
                    return;
                }
                ComponentLibDialog dialog=(ComponentLibDialog)targetObject;
                ShapeContainer selectedComponent=dialog.getSelectedComponent();
                if(debug>0) System.out.println("CreateShapeLS.creatingStart selectedComponent="+
                        selectedComponent.toShortString());
                ShapeContainer clone=(ShapeContainer)selectedComponent.clone();
                this.shapeElement=clone.getElement();
                this.shapeContainer.setElement(this.shapeElement);
                this.shapeElement.setShapeContainer(this.shapeContainer);
                if(clone.getTextBox()!=null){
                    this.shapeContainer.setTextBox(clone.getTextBox());
                }
                this.shapeContainer.setPaintStyle(clone.getPaintStyle());
                this.shapeContainer.setVisible(false);
                break;
            }
        } //switch
        ContainerManager containerManager=ObjectTable.getContainerManager();
        this.shapeContainer.setNewShapeId(containerManager, false);
        String original_type = Command.getCommandString(Command.ORIGINAL_TYPE);
        this.shapeContainer.setProperty(original_type, 
                this.shapeElement.getShapeIdString(), "CreateShapeLS");
        containerManager.addContainer(this.shapeContainer);
        if(debug>0) System.out.println("\n*** creatingStart this.shapeContainer="+this.shapeContainer.toString());
      //----------------------------------------------------//
    }

    public void creatingEnd(){
        if(this.commandId>=Command.TEXTBOX&&this.commandId<=Command.ELLIPSE) {
            this.shapeContainer.addTextBox();
            this.shapeContainer.makeTextBoxEditable(true);
        }
        DrawShapeUtil.clearAllTempShapes();
        ObjectTable.getDrawMain().setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
        ListenerPanel listenerPanel=ObjectTable.getListenerPanel();
        listenerPanel.removeMouseListener(this);
        listenerPanel.removeMouseMotionListener(this);
      //------------------------------------//  
        ObjectTable.getSelectionLS().start();
      //------------------------------------//   
        this.shapeContainer.setMode(Command.NORMAL_MODE);
        DrawParameters.MODE=Command.NORMAL_MODE;
        if(debug>0) System.out.println(" -CS("+(idNumber++)+")ShapeContainer create mode end " +
                this.toString());
        ContainerManager containerManager=ObjectTable.getContainerManager();
        containerManager.deleteContainer(this.shapeContainer);
      //------------------------  undo setup  --------------------//
        containerManager.undoSetupStart();
        containerManager.addContainer(this.shapeContainer);
        containerManager.undoSetupEnd();
      //---------------------------------------------------------//
         Command command=new Command(this.commandId, Command.callFromMouseListener, null);
         ExecCommand execCommand=ObjectTable.getExecCommand();
         execCommand.exec(command);
    }

    public int getCommandId(){
        return this.commandId;
    }
    
    public void abort(){
        DrawShapeUtil.clearAllTempShapes();
        ListenerPanel listenerPanel=ObjectTable.getListenerPanel();
        listenerPanel.removeMouseListener(this);
        listenerPanel.removeMouseMotionListener(this);
      //------------------------------------//   
        ObjectTable.getSelectionLS().start();
      //------------------------------------//   
        ContainerManager containerManager=ObjectTable.getContainerManager();
        containerManager.deleteContainer(this.shapeContainer);
        System.out.println("** CreateShapeLS aborted");
        ExecCommand execCommand=ObjectTable.getExecCommand();
        execCommand.activeCreateShapeLS=null;
    }

    public void mousePressed(MouseEvent e) {
        if(debug>0) System.out.println("\nCreatShapeLS.mousePressed");
        this.clicked=false;
        double scale=DrawParameters.getScale();
        double X = e.getX()/scale;
        double Y = e.getY()/scale;
        int key=e.getModifiersEx();
        int ctrl=0;
        this.rightButtonPressed=false;
        if(e.isPopupTrigger()) this.rightButtonPressed=true;
        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;
        if(ctrl!=0) this.ctrl=ctrl;
      //----------------------------------------------------//  
        this.pressedPoint=new Point2D.Double(X,Y);
        this.startPoint=new Point2D.Double(X,Y);
        boolean enable=DrawParameters.ENABLE_CONNECTOR;
        //double Tol=DrawParameters.ConnectionSmallTolerance;
        if(enable){
            ConnectionLS connectionLS=ObjectTable.getConnectionLS();
            CurvePT onlinePT=connectionLS.drawMouseHitPT(0, this.startPoint, null, this.shapeContainer);
            if(onlinePT!=null) this.startPoint=onlinePT.getP();
        }
      //----------------------------------------------------//
        ObjectTable.getDrawPanel().repaint("CreateShapeLS");
    }

    public void mouseDragged(MouseEvent e) {
        if(debug>0) System.out.println("\nCreatShapeLS.mouseDragged");
        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;
        if(ctrl!=0) this.ctrl=ctrl;
        this.draggedPoint=new Point2D.Double(X,Y);
        this.endPoint=new Point2D.Double(X,Y);
        if(ctrl>0){
            if(this.isRectangleFamily||this.isComponentFamily){
                this.endPoint=DiscreteAngledLine.getControlledPT(45d, 90d, this.startPoint, this.endPoint);
            } else if(this.isLineFamily){
                this.endPoint=DiscreteAngledLine.getControlledPT(0d, 45d, this.startPoint, this.endPoint);
            }
        }
        boolean enable=DrawParameters.ENABLE_CONNECTOR;
        if(enable){
            ConnectionLS connectionLS=ObjectTable.getConnectionLS();
            Vector2D vec=Vector2D.sub(this.endPoint, this.startPoint);
            CurvePT onlinePT = connectionLS.drawMouseHitPT(ctrl, this.endPoint, vec,
                    this.shapeContainer);
            if(onlinePT!=null) this.endPoint=(Point2D)onlinePT.getP().clone();
        }
     //output draggedBox
        if(this.isRectangleFamily||this.isComponentFamily){
            Point2D[] points=new Point2D[2];
            points[0]=(Point2D)this.startPoint.clone();
            points[1]=(Point2D)this.endPoint.clone();
            Rectangle2D boundingBox=ShapeElementUtil.getBoundingBox(points);
            if(this.isRectangleFamily) {
                this.shapeElement.create(boundingBox);
            }
            if(this.isComponentFamily) {
                if(boundingBox.getWidth()>5d&&boundingBox.getHeight()>5d){
                    this.shapeContainer.setVisible(true);
                    Rectangle2D oldBox=this.shapeElement.getBoundingBox();
                    this.shapeElement.moveResize(oldBox, boundingBox, true);
                }
            }
        }
      //output draggedLine
        if(this.isLineFamily) {
            this.shapeElement.create(this.startPoint, this.endPoint);
        }
        this.oldPoint=(Point2D)this.endPoint.clone();
        ObjectTable.getDrawPanel().repaint("CreateShapeLS.mouseDragged");
    } //mouseDragged

    public void mouseReleased(MouseEvent e) {
        if(debug>0) System.out.println("\nCreatShapeLS.mouseReleased");
        double scale=DrawParameters.getScale();
        double X = e.getX()/scale;
        double Y = e.getY()/scale;
        Point2D releasedPoint=new Point2D.Double(X,Y);
        if(this.draggedPoint!=null&&isDifferentPoint(this.draggedPoint, releasedPoint))
            System.out.println("CreateShapeLS  the releasedPoint is different from the last dragged point");
        if(!this.rightButtonPressed&&e.isPopupTrigger()) this.rightButtonPressed=true;
        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;
        if(this.isDifferentPoint(this.pressedPoint, releasedPoint)){
            if(this.isLineFamily||this.isRectangleFamily||this.isComponentFamily){
                if(debug>0) System.out.println("-- The mouseReleased calls .creatingEnd");
                this.creatingEnd();
            }
            if(this.isPolylineFamily) {
                double dist=Vector2D.dist(this.pressedPoint, releasedPoint);
                if(debug>0) System.out.println("-- The mouseReleased calls mouseClicked"+
                    "  dist="+dist);
                this.mouseClicked(e);
                this.clicked=true;
            }
        }
        this.startPoint=null;
        this.endPoint=null;
        this.pressedPoint=null;
        this.draggedPoint=null;
        ObjectTable.getDrawPanel().repaint("CreateShapeLS");
    } 

    public void mouseMoved(MouseEvent e) {
        if(debug>0) System.out.println("\nCreatShapeLS.mouseMoved");
        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;
        if(ctrl>0) this.ctrl=ctrl;
        Point2D mousePT=new Point2D.Double(X,Y);
        double range=DrawParameters.ConnectionTolerance;
        boolean enable=DrawParameters.ENABLE_CONNECTOR;
      //-------------------------------------------------------//  
        if(enable) {
            ConnectionLS connectionLS=ObjectTable.getConnectionLS();
            CurvePT onlinePT=connectionLS.drawMouseHitPT(0, mousePT, null, this.shapeContainer);
        }
      //-------------------------------------------------------//   
        if(this.isPolylineFamily){
            this.createNodePoint(ctrl, mousePT);
        }
        ObjectTable.getDrawPanel().repaint("CreateShapeLS.mouseMoved");
    } //mouseMoved


    public void mouseClicked(MouseEvent e) {
        if(debug>0) System.out.println("\nCreateShapeLS.mouseClicked"+
                ",  this.clicked="+this.clicked);
        if(this.clicked) return;
        this.clicked=true;
        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;

        boolean doubleClick=false;
        if (e.getClickCount() >= 2) doubleClick=true;
        
     //create RectangleFamily, ComponentFamily and LineFamily
        final Dimension sizeOfElement=new Dimension(24,24);
        double w=sizeOfElement.getWidth();
        double h=sizeOfElement.getHeight();
        Rectangle2D box=new Rectangle2D.Double(X-0.5*w, Y-0.5*h, w, h);
        if(this.isRectangleFamily) {
            this.shapeElement.create(box);
            this.creatingEnd();
        }
        if(this.isComponentFamily) {
            this.shapeContainer.setVisible(true);
            Rectangle2D oldBox=this.shapeElement.getBoundingBox();
            w=oldBox.getWidth();
            h=oldBox.getHeight();
            Rectangle2D newBox=new Rectangle2D.Double(X-0.5*w, Y-0.5*h, w, h);
            this.shapeElement.moveResize(oldBox, newBox, true);
            this.creatingEnd();
        }
         if(this.isLineFamily) {
            Point2D startP=new Point2D.Double(box.getX(), box.getY());
            Point2D endP=new Point2D.Double(box.getX()+box.getWidth(), 
                        box.getY()+box.getHeight());
            this.shapeElement.create(startP, endP);
            this.creatingEnd();
        }

     //add node point to polyLine
        if(this.isPolylineFamily){
            this.committedNodePoints=this.tentativeNodePoints;
            int size=this.tentativeNodePoints.length;
            if(size>=2) {
                Point2D segEndP=this.tentativeNodePoints[size-1];
                DrawShapeUtil.drawTempShape("Node.point", segEndP,
                        DrawParameters.Mark_SmallSize, "", Color.BLUE);
            }
            if(this.rightButtonPressed||doubleClick) {
                DrawShapeUtil.clearTempShape("Node.point");
                if(this.isPolylineFamily) this.creatingEnd();
                this.ctrl=0;
                this.rightButtonPressed=false;
            }
        }
        ObjectTable.getDrawPanel().repaint("CreateShapeLS");
    } //mouseClicked

    public void mouseEntered(MouseEvent e) {
        ObjectTable.getDrawMain().setCursor(DrawParameters.CROSSHAIR_CURSOR);
    }
    
    public void mouseExited(MouseEvent e) {
        ObjectTable.getDrawMain().setCursor(DrawParameters.DEFAULT_CURSOR);
    }
    
    private boolean isDifferentPoint(Point2D p1, Point2D p2){
        boolean different=true;
        int x1=(int)p1.getX(); int y1=(int)p1.getY();
        int x2=(int)p2.getX(); int y2=(int)p2.getY();
        if(x1==x2&&y1==y2) different=false;
        return different;
    }

    private void createNodePoint(int ctrl, Point2D mousePT){
        boolean enable=DrawParameters.ENABLE_CONNECTOR;
        ConnectionLS connectionLS=ObjectTable.getConnectionLS();
        Point2D segStartP=null;
        Point2D segEndP=null;
        CurvePT onlinePT=null;
        int size=this.committedNodePoints.length;
        if(size==0) {
            segStartP=mousePT;
            //if(enable) {
            //    onlinePT=connectionLS.drawMouseHitPT(mousePT);
            //    segStartP=onlinePT.getP();
            //}
        } else {
            segStartP=this.committedNodePoints[size-1];
            segEndP=mousePT;
        }
      //------------------------------------------------------------//  
        if(size>0&&ctrl>0){
            segEndP=DiscreteAngledLine.getControlledPT(0d, 45d, segStartP, segEndP);
        }
        if(enable){
            //double boundaryTol=DrawParameters.ConnectionTolerance;
            double pointTol=DrawParameters.ConnectionTolerance;
            if(ctrl>0) pointTol=0.0*pointTol;
            if(size==0){
                onlinePT=connectionLS.drawMouseHitPT(0, segStartP, null, this.shapeContainer);
                if(onlinePT!=null) segStartP=onlinePT.getP();
            } else {
                Vector2D vec=Vector2D.sub(segEndP, segStartP);
                onlinePT=connectionLS.drawMouseHitPT(ctrl, segEndP, vec, this.shapeContainer);
                if(onlinePT!=null) segEndP=onlinePT.getP();
            }
        //------------------------------------------------------------//
            this.tentativeNodePoints=new Point2D[size+1];
            for(int i=0;i<size;i++) this.tentativeNodePoints[i]=this.committedNodePoints[i];
            if(size==0) this.tentativeNodePoints[size]=segStartP;
            else this.tentativeNodePoints[size]=segEndP;
            this.shapeElement.create(this.tentativeNodePoints);
        }
    }
}
