package smart_gs.drawing_tool.drawing_mode;

import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JOptionPane;

import smart_gs.drawing_tool.ExLine2D;
import smart_gs.drawing_tool.LineSegEditorCanvas;
import smart_gs.drawing_tool.state.DefaultState;
import smart_gs.drawing_tool.view.LineView;
import smart_gs.logical.LineSegmentForEdit;
import smart_gs.logical.Spread;
import smart_gs.smleditor.swingui.LineSegEditor;
import smart_gs.swingui.GSMouseEvent;
import smart_gs.swingui.toolbar.LineSegEditorToolBar;
import smart_gs.util.Intersection2D;
import sml_editor.logical.LineDirection;

public class LineSegEditorDivideMode implements LineSegEditorMode{
	
	private Point2D start=null;
	private Point2D end=null;
	
	private ExLine2D cutLine;
	private List<LineSegmentForEdit> selectedLineSingletonList;
	private List<LineSegmentForEdit> originalLines;
	private int selectedLineSegIndex;
	private LineSegEditor editor;
	private LineSegEditorToolBar toolbar;
	
	
	public LineSegEditor getEditor() {
		return this.editor;
	}

	public LineSegEditorDivideMode(LineSegEditor editor2) {
		this.editor = editor2;
	}

	public void mousePressed(GSMouseEvent e, LineSegEditorCanvas canvas) {
		setCursor(canvas);
		if (e.getButton() != MouseEvent.BUTTON1) {
			this.cancel();
			return;
		}
		if(this.start == null){
			this.start = e.getPoint();
			return;
		}
		this.end = e.getPoint();
	}
	
	public void mouseClicked(GSMouseEvent e,LineSegEditorCanvas canvas) {
		if (e.getButton() != MouseEvent.BUTTON1) {
			this.cancel();
			return;
		}
		setCursor(canvas);
		
		if(e.getClickCount() == 2){
			cutLine = new ExLine2D(start,end);
			this.start = null;
			this.end = null;
			LineSegEditorDivideModePostProcess(cutLine,canvas);
		}
	}
	
	private void LineSegEditorDivideModePostProcess(ExLine2D cutLine,
			LineSegEditorCanvas canvas) {
		Point2D firstDividePoint=null;
		int firstDivideSegmentIndex = 0;
		Point2D secondDividePoint=null;
		int secondDivideSegmentIndex = 0;
		List<Point2D> points = selectedLineSingletonList.get(0).getPoints();
		int size = points.size();
		
		for (int i=0;i<size;i++){
			Line2D tmpLine = new Line2D.Double(points.get(i), points.get((i+1)%size));
			boolean intsects =	this.cutLine.intersectsLine(tmpLine);
			if (intsects) {
				if (firstDividePoint==null) {
					firstDivideSegmentIndex = i;
					firstDividePoint = Intersection2D.getIntersection(cutLine,tmpLine);
					if (firstDividePoint==null){
						JOptionPane.showMessageDialog(null,"Failed to compute the first crossing point for " + i + "-th segment. Try again!");
						return;
					}
				} else if (secondDividePoint==null){
					secondDivideSegmentIndex = i;
					secondDividePoint = Intersection2D.getIntersection(cutLine,tmpLine);
					if (firstDividePoint==null){
						JOptionPane.showMessageDialog(null,"Failed to compute the second crossing point for " + i + "-th segment. Try again!");
						return;
					}
				} else {
					JOptionPane.showMessageDialog(null,"Too many crossings. Try again!");
					return;
				}
			}
		}
		
		if (firstDividePoint == null || secondDividePoint == null ) {
			System.out.println("Reset");
			return;
		}
		
		
		List<Point2D> firstPoints = new ArrayList<Point2D>();
		List<Point2D> secondPoints = new ArrayList<Point2D>();
		for (int i=0;i<=firstDivideSegmentIndex;i++) {
			firstPoints.add(points.get(i));
		}
		firstPoints.add(firstDividePoint);
		firstPoints.add(secondDividePoint);
		for (int i=secondDivideSegmentIndex+1;i<size;i++) {
			firstPoints.add(points.get(i));
		}
		secondPoints.add(firstDividePoint);
		for (int i=firstDivideSegmentIndex+1;i<=secondDivideSegmentIndex;i++) {
			secondPoints.add(points.get(i));
		}
		secondPoints.add(secondDividePoint);
		
		int firstPointsSize = firstPoints.size();
		int secondPointsSize = secondPoints.size();
		
		if (firstPointsSize == 0 || secondPointsSize == 0) {
			JOptionPane.showMessageDialog(null,"Illegal cut line. Try again!");
			return;
		}

		originalLines.remove(selectedLineSegIndex);
		Spread spread = editor.getSpread();
		
		if (spread.getLineDirection() != LineDirection.VERTICAL)
		{
			Point2D firstPointsLeftest = firstPoints.get(0);
			Point2D secondPointsLeftest  = secondPoints.get(0);
			for (int i=1; i<firstPointsSize; i++) {
				Point2D cp = firstPoints.get(i);
				if (firstPointsLeftest.getX() > cp.getX()) {
					firstPointsLeftest = cp;
				}
			}
			for (int i=1; i<secondPointsSize; i++) {
				Point2D cp = secondPoints.get(i);
				if (secondPointsLeftest.getX() > cp.getX()) {
					secondPointsLeftest = cp;
				}
			}
			if (firstPointsLeftest.getX() <= secondPointsLeftest.getX()) {
				originalLines.add(selectedLineSegIndex,createLineSegmentForEdit(firstPoints,this.editor.getSpread().getLineDirection()));	
				originalLines.add(selectedLineSegIndex+1,createLineSegmentForEdit(secondPoints,this.editor.getSpread().getLineDirection()));
			} else {
				originalLines.add(selectedLineSegIndex,createLineSegmentForEdit(secondPoints,this.editor.getSpread().getLineDirection()));
				originalLines.add(selectedLineSegIndex+1,createLineSegmentForEdit(firstPoints,this.editor.getSpread().getLineDirection()));	
			}
		} else {
			Point2D firstPointsTopmost = firstPoints.get(0);
			Point2D secondPointsTopmost  = secondPoints.get(0);
			for (int i=1; i<firstPointsSize; i++) {
				Point2D cp = firstPoints.get(i);
				if (firstPointsTopmost.getY() > cp.getY()) {
					firstPointsTopmost = cp;
				}
			}
			for (int i=1; i<secondPointsSize; i++) {
				Point2D cp = secondPoints.get(i);
				if (secondPointsTopmost.getY() > cp.getY()) {
					secondPointsTopmost = cp;
				}
			}
			if (firstPointsTopmost.getY() <= secondPointsTopmost.getY()) {
				originalLines.add(selectedLineSegIndex,createLineSegmentForEdit(firstPoints,this.editor.getSpread().getLineDirection()));	
				originalLines.add(selectedLineSegIndex+1,createLineSegmentForEdit(secondPoints,this.editor.getSpread().getLineDirection()));
			} else {
				originalLines.add(selectedLineSegIndex,createLineSegmentForEdit(secondPoints,this.editor.getSpread().getLineDirection()));
				originalLines.add(selectedLineSegIndex+1,createLineSegmentForEdit(firstPoints,this.editor.getSpread().getLineDirection()));	
			}
		}
		editor.setLinesForEdit(originalLines);
		LineSegEditorDrawMode mode = editor.getLineSegEditorDrawMode();
		editor.setMode(mode);
//		toolbar.initializeButtonGroup();
		editor.rewriteLineSegIndexes();
		editor.repaint();
		editor.getLineSegEditorCanvas().getLineSegEditorImageLabel().setCursor(DefaultState.getInstance().getCursor());		
	}
	
	private LineSegmentForEdit createLineSegmentForEdit(List<Point2D> firstPoints, LineDirection lineDirection) {
		return new LineSegmentForEdit(this.editor, firstPoints, lineDirection);
	}

	public void mouseMoved(GSMouseEvent e,LineSegEditorCanvas canvas) {
		setCursor(canvas);
		this.end = e.getPoint();
		setCursor(canvas);
	}

	@Override
	public void paint(Graphics g,LineSegEditorCanvas canvas) {	
		if(this.start == null || this.end == null){
			return ;
		}
		double ratio = canvas.getLineSegEditorImageLabel().getRatio();
		double gapX = canvas.getLineSegEditorImageLabel().getGapWidth();
		double gapY = canvas.getLineSegEditorImageLabel().getGapHeight();

		new LineView(new ExLine2D(start,end)).enlargedView(ratio,gapX,gapY).draw((Graphics2D)g);

		setCursor(canvas);
	}
	
	public void cancel() {
		// TODO Auto-generated method stub
		
	}
	
	public void mouseDragged(GSMouseEvent e, LineSegEditorCanvas canvas) {
		setCursor(canvas);		
	}
	
	public void mouseEntered(GSMouseEvent e, LineSegEditorCanvas canvas) {
		setCursor(canvas);		
	}
	
	public void mouseExited(GSMouseEvent e, LineSegEditorCanvas canvas) {
		setCursor(canvas);
		
	}
	
	public void mouseReleased(GSMouseEvent e, LineSegEditorCanvas canvas) {
		setCursor(canvas);		
	}
	
	public void setCursor(LineSegEditorCanvas canvas) {
		canvas.getLineSegEditorImageLabel().setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));		
	}
//	selectedLine is a singleton list
	public void giveSelectedLine(List<LineSegmentForEdit> selectedLineSingletonList) {
		this.selectedLineSingletonList = selectedLineSingletonList;
	}
	public void giveOriginalLines(List<LineSegmentForEdit> originalLines) {
		this.originalLines = originalLines;
	}
	public void giveSelectedLineSegIndex(int index) {
		this.selectedLineSegIndex = index;
		
	}
	public void giveLineSegEditor(LineSegEditor editor) {
		this.editor = editor;
	}
	public void giveLineSegEditorToolBar(LineSegEditorToolBar toolbar) {
		this.toolbar = toolbar;
	}
	@Override
	public LineSegEditor getParentLinesegEditor() {
		// TODO Auto-generated method stub
		return null;
	}
	@Override
	public void setParentLinesegEditor() {
		// TODO Auto-generated method stub
		
	}

}
