/* $Id: UniSelectedState.java 1071 2016-02-26 13:01:55Z shayashi $ */
package smart_gs.drawing_tool.state;

import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.geom.Point2D;

import javax.swing.JPopupMenu;

import smart_gs.drawing_tool.ImageLabel;
import smart_gs.drawing_tool.RightClickMenu;
import smart_gs.drawing_tool.SpreadCanvas;
import smart_gs.drawing_tool.action.CloseUpViewerAction;
import smart_gs.drawing_tool.action.DeleteRegionAction;
import smart_gs.drawing_tool.action.MemoPadTextAction;
import smart_gs.drawing_tool.drawing_mode.DefaultDrawingMode;
import smart_gs.drawing_tool.drawing_mode.DeleteMode;
import smart_gs.drawing_tool.view.MemoPadView;
import smart_gs.drawing_tool.view.MemoPadView.Arrow;
import smart_gs.drawing_tool.view.View;
import smart_gs.logical.Region;
import smart_gs.logical.RegionOperation;
import smart_gs.logical.Spread;
import smart_gs.logical.region.MemoPadRegion;
import smart_gs.reasoning_web.swingui.RWGlobalViewPanel;
import smart_gs.reasoning_web.swingui.ReasoningWebFrame;
import smart_gs.swingui.GSMouseEvent;
import smart_gs.swingui.WorkspaceWindow;
import smart_gs.swingui.toolbar.ImageToolBar;
import smart_gs.util.ImageToolBarSetModeByMouseEvent;
import smart_gs.util.Pair;
import smart_gs.util.Triple;

public class UniSelectedState implements State{
	
	private static UniSelectedState singleton = new UniSelectedState();
	
	private boolean markupMovable = false;
	
	private Point2D start,end;

	private Region selectedRegion;
	
	private boolean selectedRegionMoving;

	private boolean createArrowPointMode = false;
	private boolean deleteArrowPointMode = false;
	private boolean moveArrowPointMode = false;
	
	
	private Point2D memoPadStartingPointForUndoRedo = null;
	private Point2D memoPadArrowHeadStartingPointForUndoRedo = null;
	private Point2D memoPadLowerRightCornerOriginalPointForUndoRedo = null;
	
	private int pressed_button = -1;
	
	private UniSelectedState(){
		
	}
	public static UniSelectedState getInstance(){
		return singleton;
	}
	
	//20080715 shimizu wrote
	public boolean getMarkupMovability(){
		return this.markupMovable;
	}
	public void setMarkupMovability(boolean b){
		this.markupMovable = b;
	}
	
	public void mouseClicked(GSMouseEvent e, SpreadCanvas canvas) {
		/* this works only when a region is selected and exclusively on it */
		if(this.selectedRegion == null){
			return;
		}
//		boolean ctrlPressed = WorkspaceWindow.getInstance().isCtrl();
//		boolean altPressed = WorkspaceWindow.getInstance().isAlt();
		boolean shiftPressed = WorkspaceWindow.getInstance().isShift();
		int clickCount = e.getClickCount();
		int button = e.getButton();
		
		View view = this.selectedRegion.getView();
		
		if(button == MouseEvent.BUTTON3){
			rightButtonClickAction(e,canvas,shiftPressed);
		}else if(button == MouseEvent.BUTTON1){
			if (clickCount == 2 && 
					(view.getType() == View.MEMOPAD) && 
					(view.contains(e.getPoint2D()))) {
				new MemoPadTextAction(this.selectedRegion).actionPerformed(e);
			} else {
				if(WorkspaceWindow.getInstance().isAlt() && ! WorkspaceWindow.getInstance().isCtrl() ){
					/* alternative for right button click */
					rightButtonClickAction(e,canvas,WorkspaceWindow.getInstance().isShift());
				} else if(WorkspaceWindow.getInstance().isCtrl()){
					DefaultState.getInstance()
					.setMode(DefaultDrawingMode.getInstance());
					new ImageToolBarSetModeByMouseEvent().setMode(e,ImageToolBar.modeNone);
				}
			}
		}
		canvas.getImageLabel().setCursor(DefaultState.getInstance().getCursor());
	}

	
	private void rightButtonClickAction(GSMouseEvent e, SpreadCanvas canvas, boolean isShift) {
		boolean isTemporary = this.selectedRegion.isTemporary();
		if (isTemporary && isShift) {
			new DeleteRegionAction(this.selectedRegion, this).execute();
		} else {
			JPopupMenu menu = new RightClickMenu(this.selectedRegion, canvas, this, isTemporary);
			menu.show(e.getComponent(),e.getOriginalPoint().x,e.getOriginalPoint().y);
			RWGlobalViewPanel.getInstance().repaint();
		}
	}
	
	public void mouseDragged(GSMouseEvent e, SpreadCanvas canvas) {
		if (this.pressed_button != MouseEvent.BUTTON1) return;
		Point2D point = e.getPoint();
		double x = point.getX();
		double y = point.getY();
		double w = canvas.getImageLabel().getImageWidth();
		double h = canvas.getImageLabel().getImageHeight();
		double xx = (x <= 2?2: (x >= w-2? w-2: x));
		double yy = y <= 2?2: (y >= h-2? h-2: y);
		Point2D d = new Point2D.Double(xx, yy);
		if (this.selectedRegion != null) {
			View view = this.selectedRegion.getView();
			if (view.isResizable()) {
				this.selectedRegionMoving = true;
				view.resize(d);
				WorkspaceWindow.setUpdated(true);
			} else if (view.getType() == View.MEMOPAD && this.moveArrowPointMode) {
				int index = ((MemoPadView)view).getIndexOfMovingArrow();
				((MemoPadView)view).arrowMoveBy(index, d);
				WorkspaceWindow.setUpdated(true);
			} else {
				this.end = new Point((int)xx, (int)yy);		
				if((markupMovable ==true && !this.selectedRegion.getView().isProtected())
						|| ((this.selectedRegion.getView().getType() == View.MEMOPAD)
							&& !this.selectedRegion.getView().isProtected())
						|| (this.selectedRegion.getView().getType() == View.BOOKMARK)
							&& !this.selectedRegion.getView().isProtected()
						|| (this.selectedRegion.getView().getType() == View.ANCHOR)
							&& !this.selectedRegion.getView().isProtected()) {
					Point2D p = new Point2D.Double(this.end.getX()-this.start.getX(),this.end.getY()-this.start.getY());
					this.selectedRegionMoving = true;
					this.selectedRegion.getView().moveBy(p);
					WorkspaceWindow.setUpdated(true);
				}
				this.start = this.end;
			}
		}
		canvas.getImageLabel().setCursor(DefaultState.getInstance().getCursor());
	}

	public void mouseEntered(GSMouseEvent e, SpreadCanvas canvas) {
		canvas.getImageLabel().setCursor(DefaultState.getInstance().getCursor());
	}

	public void mouseExited(GSMouseEvent e, SpreadCanvas canvas) {
		canvas.getImageLabel().setCursor(DefaultState.getInstance().getCursor());
	}

	public void mouseMoved(GSMouseEvent e, SpreadCanvas canvas) {
		canvas.getImageLabel().setCursor(DefaultState.getInstance().getCursor());
	}

	public void mousePressed(GSMouseEvent e, SpreadCanvas canvas) {
		this.pressed_button = e.getButton();
		this.start = e.getPoint();
		this.memoPadStartingPointForUndoRedo = this.start;
		// 2011/01/08 kukita
		if (createArrowPointMode) {
			this.memoPadStartingPointForUndoRedo = null;
			MemoPadView view = (MemoPadView)this.selectedRegion.getView();
			Spread spread = canvas.getSpread();
			Region region = this.selectedRegion;
			Arrow new_arrow = view.arrowTo(e.getPoint2D());
			spread.pushRegionUndoStack(new RegionOperation(RegionOperation.CHANGE_MEMOPAD_DRAW_ARROW, region, new_arrow,spread));
			view.addArrow(new_arrow);
			this.createArrowPointMode = false;
			WorkspaceWindow.setUpdated(true);
			return;
		}
		if (deleteArrowPointMode) {
			this.memoPadStartingPointForUndoRedo = null;
			MemoPadView view = ((MemoPadView)this.selectedRegion.getView());
			Spread spread = canvas.getSpread();
			Region region = this.selectedRegion;
			Point2D point = e.getPoint2D();
			spread.pushRegionUndoStack(new RegionOperation(RegionOperation.CHANGE_MEMOPAD_DELETE_ARROW, region, point,spread));
			view.deleteArrow(point);
			this.deleteArrowPointMode = false;
			((MemoPadRegion)this.selectedRegion).setDeleteArrowPointMode(false);
			return;
		}
		
		// begin assignment
		boolean contains = false;
		boolean contains_in_arrow_head = false;
		View view;
		int length = canvas.getCurrentSpread().getRegions().size();
		int indexR = -1;// the index of the region containing the event point
		int indexA = -1;// the index of the region containing the event point in an arrow head
		for (int i = length - 1; i >= 0; i--) {
			view = canvas.getCurrentSpread().getRegions().get(i).getView();
			if (view.contains(e.getPoint())) {
				contains = true;
				indexR = i;
				break;
			} else if (view.getType() == View.MEMOPAD) {
				if (((MemoPadView)view).containsInArrowHead(e.getPoint())) {
					if (this.memoPadArrowHeadStartingPointForUndoRedo == null) {
						this.memoPadArrowHeadStartingPointForUndoRedo = e.getPoint2D();
					}
					this.memoPadStartingPointForUndoRedo = null;
					contains_in_arrow_head = true;
					indexA = i;
					break;
				} else if (((MemoPadView)view).containsInArrow(e.getPoint())) {
					this.memoPadStartingPointForUndoRedo = null;
					contains = true;
					indexR = i;
					break;
				}
			}
		}
		boolean regionIsSelected = (this.selectedRegion != null);
		boolean containsInCloseUpIcon = false;
		if (regionIsSelected) {
			containsInCloseUpIcon = (this.selectedRegion.getView().containsInCloseUpIcon(e.getPoint2D()));
		}
		boolean buttonOne = e.getButton() == MouseEvent.BUTTON1;
		boolean buttonThree = e.getButton() == MouseEvent.BUTTON3;
		// end assignment


		if (buttonOne) {
			if (containsInCloseUpIcon) {
				this.memoPadStartingPointForUndoRedo = null;
				new CloseUpViewerAction(this.selectedRegion);
				return;
			}
			// 2011/01/20 kukita
			// If control and alt are down, ignore regions which contain the event point,
			// enabling you to draw a region within regions
			if (contains && WorkspaceWindow.getInstance().isAlt() && e.isControlDown()
					|| (contains && DefaultState.getInstance().addingMarkup())
				) {
				this.memoPadStartingPointForUndoRedo = null;
				if(regionIsSelected){
					this.selectedRegion.getView().setIsSelected(false);
					ReasoningWebFrame.getInstance().getElementsPanel().setElement(null);
					RWGlobalViewPanel.getInstance().setSelectedElement(null);
					RWGlobalViewPanel.getInstance().repaint();

					this.selectedRegion = null;
					State state = DefaultState.getInstance();
				    ImageLabel.setState(state);
				    state.mousePressed(e, canvas);
				    return;
				}
				State state = DefaultState.getInstance();
			    ImageLabel.setState(state);
			    state.mousePressed(e, canvas);
			} else

			if (regionIsSelected && contains && e.isControlDown() && e.isShiftDown()) {
				this.memoPadStartingPointForUndoRedo = null;
				MultiSelectedState state = MultiSelectedState.getInstance();
				ImageLabel.setState(state);
				state.addSelectedRegion(this.selectedRegion);
				state.addSelectedRegion(canvas.getRegion(e.getPoint()));		
			}
			//		Region???d????????????Shift?L?[???????N???b?N???膩???I???????
			else if (buttonOne && contains && e.isShiftDown()){
				this.memoPadStartingPointForUndoRedo = null;
				if(regionIsSelected){
					this.selectedRegion.getView().setIsSelected(false);
					//2007/10/30 kazuhiro kobayashi
					ReasoningWebFrame.getInstance().getElementsPanel().setElement(null);
					RWGlobalViewPanel.getInstance().setSelectedElement(null);
					RWGlobalViewPanel.getInstance().repaint();
				}
				this.selectedRegion = canvas.getAnotherRegion(e.getPoint());
				this.selectedRegion.getView().setIsSelected(true);
				//2007/10/30 kazuhiro kobayashi
				ReasoningWebFrame.getInstance().getElementsPanel().setElement(this.selectedRegion);
				RWGlobalViewPanel.getInstance().setSelectedElement(this.selectedRegion);
				RWGlobalViewPanel.getInstance().repaint();
			}
			

			else if (contains) {   //?N???b?N????????region????????????
				if(regionIsSelected){ // cancel selection
					this.selectedRegion.getView().setIsSelected(false);
					//2007/10/30 kazuhiro kobayashi
					
					ReasoningWebFrame.getInstance().getElementsPanel().setElement(null);
					RWGlobalViewPanel.getInstance().setSelectedElement(null);
					RWGlobalViewPanel.getInstance().repaint();
				}
				
				// select the region which contains the event point
//				this.selectedRegion = canvas.getRegion(e.getPoint());
				this.selectedRegion = canvas.getRegionByIndex(indexR);//2011/01/08 kukita
				this.selectedRegion.getView().setIsSelected(true);
				//2007/10/30 kazuhiro kobayashi
				
				
				if (DefaultState.getInstance().getMode() == DeleteMode.getInstance()) {
					this.memoPadStartingPointForUndoRedo = null;
					DeleteMode.getInstance().mousePressed(e,canvas);
					return;
				}
				
				if (this.getSelectedRegion().getView().getType() == View.MEMOPAD) {
					MemoPadView mview = (MemoPadView)this.selectedRegion.getView();
//					ImageLabel imageLabel = WorkspaceWindow.getInstance().getSpreadCanvas().getImageLabel();
//					double ratio = imageLabel.getRatio();
//					double gapX = imageLabel.getGapWidth();
//					double gapY = imageLabel.getGapHeight();
					if (mview.containsInCorner(e.getPoint())) {
						if (this.memoPadLowerRightCornerOriginalPointForUndoRedo == null) {
							this.memoPadLowerRightCornerOriginalPointForUndoRedo = mview.getLowerRightCornerPoint();
						}
						this.memoPadStartingPointForUndoRedo = null;
						mview.setResizeMode(true);
					}
					/* if the event point is contained in the corner of the memopad,
					 * set the memopad to be resizable.
					 * 2010/11 kukita 
					 */

					ReasoningWebFrame.getInstance().getElementsPanel().setElement(this.selectedRegion);
					RWGlobalViewPanel.getInstance().setSelectedElement(this.selectedRegion);
					RWGlobalViewPanel.getInstance().repaint();
				}				
			}
			else if (contains_in_arrow_head) {
				this.memoPadStartingPointForUndoRedo = null;
				if (regionIsSelected) { // cancel selection
					this.selectedRegion.getView().setIsSelected(false);
					//2007/10/30 kazuhiro kobayashi
					
					ReasoningWebFrame.getInstance().getElementsPanel().setElement(null);
					RWGlobalViewPanel.getInstance().setSelectedElement(null);
					RWGlobalViewPanel.getInstance().repaint();
				}
				this.setMoveArrowPointMode(true);
				this.selectedRegion = canvas.getRegionByIndex(indexA);
				MemoPadView mview = ((MemoPadView)this.selectedRegion.getView());
				mview.setIsSelected(true);
				mview.setIndexOfMovingArrow(e.getPoint2D());
			}
			
			else if(regionIsSelected){
				this.selectedRegion.getView().setIsSelected(false);
				ReasoningWebFrame.getInstance().getElementsPanel().setElement(null);
				RWGlobalViewPanel.getInstance().setSelectedElement(null);
				RWGlobalViewPanel.getInstance().repaint();

				this.selectedRegion = null;
				State state = DefaultState.getInstance();
			    ImageLabel.setState(state);
			    state.mousePressed(e, canvas);
			} else {
				this.memoPadStartingPointForUndoRedo = null;
				this.selectedRegion = null;
				State state = DefaultState.getInstance();
			    ImageLabel.setState(state);
//			    state.mousePressed(e, canvas);				
			}
		} else if (buttonThree) {			
			this.memoPadStartingPointForUndoRedo = null;
			// select the region which contains the event point
			if (contains) {
				if(regionIsSelected){ // cancel selection
					this.selectedRegion.getView().setIsSelected(false);
					ReasoningWebFrame.getInstance().getElementsPanel().setElement(null);
					RWGlobalViewPanel.getInstance().setSelectedElement(null);
					RWGlobalViewPanel.getInstance().repaint();
				}
				this.selectedRegion = canvas.getRegionByIndex(indexR);//2011/01/08 kukita
				this.selectedRegion.getView().setIsSelected(true);

			} else if (contains_in_arrow_head) {
				if(regionIsSelected){ // cancel selection
					this.selectedRegion.getView().setIsSelected(false);
					ReasoningWebFrame.getInstance().getElementsPanel().setElement(null);
					RWGlobalViewPanel.getInstance().setSelectedElement(null);
					RWGlobalViewPanel.getInstance().repaint();
				}
				this.selectedRegion = canvas.getRegionByIndex(indexA);
				this.setMoveArrowPointMode(true);
				MemoPadView mview = ((MemoPadView)this.selectedRegion.getView());
				mview.setIsSelected(true);
				mview.setIndexOfMovingArrow(e.getPoint2D());
			}
		} // 2010/11/28 kukita
		canvas.getImageLabel().setCursor(DefaultState.getInstance().getCursor());
	}


	public void mouseReleased(GSMouseEvent e, SpreadCanvas canvas) {
		int index = -1;
		this.selectedRegionMoving = true;
		Region region = this.selectedRegion;
		Spread spread = canvas.getSpread();
		if (region != null) {
			View view = region.getView();
			if (view instanceof MemoPadView) {
				if (((MemoPadView)view).isResizable()) {
					if (memoPadLowerRightCornerOriginalPointForUndoRedo != null){
						spread.pushRegionUndoStack(new RegionOperation(
								RegionOperation.CHANGE_MEMOPAD_RESIZE, 
								region, 
								new Pair<Point2D,Point2D>(memoPadLowerRightCornerOriginalPointForUndoRedo,((MemoPadView)view).getLowerRightCornerPoint()),
								spread));
					}
					memoPadLowerRightCornerOriginalPointForUndoRedo = null;
					((MemoPadView)view).setResizeMode(false);
				} else if ((index = ((MemoPadView)view).getIndexOfMovingArrow()) >= 0) {
					Point2D start_point = this.memoPadArrowHeadStartingPointForUndoRedo;
					Point2D end_point = e.getPoint2D();
					spread.pushRegionUndoStack(new RegionOperation(RegionOperation.CHANGE_MEMOPAD_MOVE_ARROW, 
							region, new Triple<Integer,Point2D, Point2D>(index,start_point,end_point),spread));
					((MemoPadView)view).setIndexOfMovingArrow(-1);
					this.memoPadArrowHeadStartingPointForUndoRedo = null;
					this.moveArrowPointMode = false;
				} 
			}
			if (this.memoPadStartingPointForUndoRedo != null) {
				Point2D endPoint = e.getPoint();
				if (endPoint.equals(this.memoPadStartingPointForUndoRedo)) {
					this.memoPadStartingPointForUndoRedo = null;
					this.memoPadArrowHeadStartingPointForUndoRedo = null;
					this.moveArrowPointMode = false;
					return;
				}
				spread.pushRegionUndoStack(new RegionOperation(RegionOperation.CHANGE_LOCATION,
						region,
						new Point2D.Double(endPoint.getX()-this.memoPadStartingPointForUndoRedo.getX(),endPoint.getY()-this.memoPadStartingPointForUndoRedo.getY()),
						spread)); 
			}
		}
		this.memoPadArrowHeadStartingPointForUndoRedo = null;
		this.moveArrowPointMode = false;
		// 2010/11 kukita
		canvas.getImageLabel().setCursor(DefaultState.getInstance().getCursor());

	}
	


	public void paint(Graphics g, SpreadCanvas canvas) {

	}
	public Region getSelectedRegion() {
		return this.selectedRegion;
	}
	public boolean isSelectedRegionMoving() {
		return this.selectedRegionMoving;
	}
	public void setCreateArrowPointMode(boolean b) {
		this.createArrowPointMode = b;
	}
	public void setDeleteArrowPointMode(boolean b) {
		this.deleteArrowPointMode = b;
		if (this.getSelectedRegion().getView().getType() == View.MEMOPAD) {
			((MemoPadRegion)this.getSelectedRegion()).setDeleteArrowPointMode(b);
		}
	}
	public void setMoveArrowPointMode(boolean b) {
		this.moveArrowPointMode = b;
	}
	
	//2011/01/21 kukita
	public void setSelectedRegion(Region region) {
		this.selectedRegion = region;
	}
	@Override
	public int getType() {
		return State.UNISELECTED;
	}
	
	
	public void changeSelectedRegions(Region reg) {
		ImageLabel.setState(this);
		boolean regionIsSelected = (this.getSelectedRegion() != null);
		if(regionIsSelected){ // cancel selection
			this.getSelectedRegion().getView().setIsSelected(false);
			ReasoningWebFrame.getInstance().getElementsPanel().setElement(null);
			RWGlobalViewPanel.getInstance().setSelectedElement(null);
			RWGlobalViewPanel.getInstance().repaint();
		}
		
		this.setSelectedRegion(reg);
		reg.getView().setIsSelected(true);
	}
	
}