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 LineSegEditorCutMode implements LineSegEditorMode{
	
	private static LineSegEditorCutMode singleton = new LineSegEditorCutMode();
	
	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;
	
	
	private LineSegEditorCutMode() {
//		this.tempPoints = new ArrayList<Point2D>();
	}
	public static LineSegEditorCutMode getInstance(){
		return singleton;
	}

	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();
		
//		this.tempPoints.add(this.tempEnd);
//		this.start = this.end
	}
	
	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;
			LineSegEditorCutModePostProcess(cutLine,canvas);
		}
	}
	
	private void LineSegEditorCutModePostProcess(ExLine2D cutLine,
			LineSegEditorCanvas canvas) {
		Point2D firstCutPoint=null;
		int firstCutSegmentIndex = 0;
		Point2D secondCutPoint=null;
		int secondCutSegmentIndex = 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 (firstCutPoint==null) {
					firstCutSegmentIndex = i;
					firstCutPoint = Intersection2D.getIntersection(cutLine,tmpLine);
					if (firstCutPoint==null){
						JOptionPane.showMessageDialog(null,"Failed to compute the first crossing point for " + i + "-th segment. Try again!");
						return;
					}
				} else if (secondCutPoint==null){
					secondCutSegmentIndex = i;
					secondCutPoint = Intersection2D.getIntersection(cutLine,tmpLine);
					if (firstCutPoint==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 (firstCutPoint == null || secondCutPoint == null ) {
			System.out.println("Reset");
			return;
		}
		
		
		List<Point2D> firstPoints = new ArrayList<Point2D>();
		List<Point2D> secondPoints = new ArrayList<Point2D>();
		for (int i=0;i<=firstCutSegmentIndex;i++) {
			firstPoints.add(points.get(i));
		}
		firstPoints.add(firstCutPoint);
		firstPoints.add(secondCutPoint);
		for (int i=secondCutSegmentIndex+1;i<size;i++) {
			firstPoints.add(points.get(i));
		}
		secondPoints.add(firstCutPoint);
		for (int i=firstCutSegmentIndex+1;i<=secondCutSegmentIndex;i++) {
			secondPoints.add(points.get(i));
		}
		secondPoints.add(secondCutPoint);
		
		if (firstPoints.size()==0 || secondPoints.size()==0) {
			JOptionPane.showMessageDialog(null,"Illegal cut line. Try again!");
			return;
		}

		originalLines.remove(selectedLineSegIndex);
		originalLines.add(selectedLineSegIndex,new LineSegmentForEdit(secondPoints,this.editor.getSpread().getLineDirection()));
		originalLines.add(selectedLineSegIndex,new LineSegmentForEdit(firstPoints,this.editor.getSpread().getLineDirection()));	
		editor.setLinesForEdit(originalLines);
		LineSegEditorDefaultMode mode = LineSegEditorDefaultMode.getInstance();
		editor.setMode(mode);
		toolbar.initializeButtonGroup();
		editor.rewriteLineSegIndexes();
		editor.repaint();
		editor.getLineSegEditorCanvas().getLineSegEditorImageLabel().setCursor(DefaultState.getInstance().getCursor());		
	}
	
	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;
	}

}
