package smart_gs.drawing_tool;

import java.awt.Cursor;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

import javax.swing.ImageIcon;
import javax.swing.JLabel;

import smart_gs.drawing_tool.drawing_mode.LineSegEditorDefaultMode;
import smart_gs.drawing_tool.drawing_mode.LineSegEditorMode;
import smart_gs.drawing_tool.state.LineSegEditorDefaultState;
import smart_gs.drawing_tool.state.LineSegEditorState;
import smart_gs.drawing_tool.view.LineSegView;
import smart_gs.drawing_tool.view.View;
import smart_gs.logical.LineSegmentForEdit;
import smart_gs.logical.Preference;
import smart_gs.logical.Spread;
import smart_gs.swingui.GSMouseEvent;
import smart_gs.swingui.WorkspaceWindow;
import smart_gs.util.XMLToLineConverter;

@SuppressWarnings("serial")
public class LineSegEditorImageLabel 
	extends JLabel 
	implements MouseListener, MouseMotionListener {

	private final int DEFAULT_WIDTH = 1200;
	private final int ZOOM_VALUE = 200;
	//20080617 shimizu wrote
	//private final int ZOOM_VALUE = 400;

	public int scale = 0;

	private List<LineSegmentForEdit> lines = new ArrayList<LineSegmentForEdit>();


	private LineSegEditorState state;
	private LineSegEditorMode mode;
	private Cursor cursor = Cursor.getDefaultCursor();
	
	public enum Show{LINE_AND_INDEX,LINE};
	public Show lineSegShowingMode = Show.LINE_AND_INDEX;

	private LineSegEditorCanvas canvas;
	private ImageIcon imageIcon;
	
	private int currentWidth;
	private int currentHeight;

	private int imageWidth;
	private int imageHeight;
	private Image image;

	private List<View> tempViews;
	
	private Point2D start = null;
	private Point2D end = null;

	public LineSegEditorImageLabel(LineSegEditorCanvas canvas, ImageIcon imageIcon) {
		super(imageIcon);
		LineSegEditorDefaultState state0 =  new LineSegEditorDefaultState(canvas);
		this.mode = (LineSegEditorMode)LineSegEditorDefaultMode.getInstance();
		state0.setMode(mode);
		this.state = state0;
		this.canvas = canvas;
		this.imageIcon = imageIcon;
		this.setImageWidth(this.imageIcon.getIconWidth());
		this.setImageHeight(this.imageIcon.getIconHeight());
		this.image = this.imageIcon.getImage();
		this.tempViews = new ArrayList<View>();
		this.addMouseListener(this);
		this.addMouseMotionListener(this);
		this.loadLinesFromXMLFile();
		this.showImage();
		this.setLayout(new FlowLayout(FlowLayout.LEFT));
		if (cursor != null) {
			this.setCursor(cursor);
		}
	}

	public void showImage() {
		double ratio = (double) getImageWidth() / (double) getImageHeight();
		int w = DEFAULT_WIDTH + scale * ZOOM_VALUE;
		this.setCurrentWidth(w);
		this.setCurrentHeight((int) (w / ratio));
		BufferedImage bufImage = new BufferedImage(this.getCurrentWidth(),
				this.getCurrentHeight(), BufferedImage.TYPE_INT_RGB);
		Graphics offg = bufImage.getGraphics();
		offg
				.drawImage(image, 0, 0, this.getCurrentWidth(), this.getCurrentHeight(),
						this);
		this.setSize(this.getCurrentWidth(), this.getCurrentHeight());
		this.setIcon(new ImageIcon(bufImage));
		WorkspaceWindow.getInstance().getImageToolBar().enableIcons();
	}

	public Point getCornerPoint() {
		return this.getLocation();
	}

	public void zoomIn() {
		// 2007/11/19 kazuhiro kobayashi
		if (this.scale < 21) {
			this.scale++;
			this.showImage();
		}
	}

	public void zoomOut() {
		// 2007/11/19 kazuhiro kobayashi
		if (this.scale > -5) {
			this.scale--;
			this.showImage();
		}
	}

	public void fullSize() {
		this.scale = 0;
		this.showImage();
	}

	public void fitWidth(int width) {
		this.scale = (width - DEFAULT_WIDTH) / ZOOM_VALUE - 1;
		this.showImage();
	}

	public void fitHeight(int height) {
		double ratio = (double) getImageWidth() / (double) getImageHeight();
		this.scale = (int) ((ratio * (double) height - DEFAULT_WIDTH) / ZOOM_VALUE - 1);
		this.showImage();
	}
	public void setScale(int scale) {
		this.scale = scale;
	}

	@Override
	public void paint(Graphics g) {
		super.paint(g);

		int width = this.canvas.getSpread().getWidth();
		int w = DEFAULT_WIDTH + scale * ZOOM_VALUE;
		double ratio = (double) ((double) w / (double) width);

		int canvasWidth = this.canvas.getWidth();
		int canvasHeight = this.canvas.getHeight();
		int iconHeight = this.getIcon().getIconHeight();
		int iconWidth = this.getIcon().getIconWidth();

		int scrollHeight = this.canvas.getHorizontalScrollBar().getHeight();
		int scrollWidth = this.canvas.getVerticalScrollBar().getWidth();
		double gapX = 0;
		double gapY = 0;

		if (iconWidth < canvasWidth) {
			gapX = (canvasWidth - scrollWidth - iconWidth) / 2.0;
		}
		if (iconHeight < canvasHeight) {
			gapY = (canvasHeight - scrollHeight - iconHeight) / 2.0;
		}

		if (lines != null ) {
			for (int i = 0; i < lines.size(); i++) {
				LineSegView view = (LineSegView) lines.get(i).getView().enlargedView(ratio, gapX,
						gapY);
				view.drawShapeForLineSegImageLabel((Graphics2D) g, lineSegShowingMode);
			}
		}
		// This prints the incomplete line segment drawn.
		getState().paint(g, canvas);
	}


	public double getGapWidth() {
		int canvasWidth = this.canvas.getWidth();
		int iconWidth = this.getIcon().getIconWidth();
		int scrollWidth = this.canvas.getVerticalScrollBar().getWidth();
		double gapX = 0;
		if (iconWidth < canvasWidth) {
			gapX = (canvasWidth - scrollWidth - iconWidth) / 2.0;
		}
		return gapX;
	}

	public double getGapHeight() {
		int canvasHeight = this.canvas.getHeight();
		int iconHeight = this.getIcon().getIconHeight();
		int scrollHeight = this.canvas.getHorizontalScrollBar().getHeight();
		double gapY = 0;
		if (iconHeight < canvasHeight) {
			gapY = (canvasHeight - scrollHeight - iconHeight) / 2.0;
		}
		return gapY;
	}

	public double getRatio() {
		int width = this.canvas.getSpread().getWidth();
		int w = DEFAULT_WIDTH + scale * ZOOM_VALUE;
		double ratio = ((double) ((double) w / (double) width));
		return ratio;
	}


	/**
	 * 
	 * @param point
	 *            
	 * @return
	 */
	public Point getAdjustedPoint(Point point) {
		double x = point.x;
		double y = point.y;
		int canvasWidth = this.canvas.getWidth();
		int canvasHeight = this.canvas.getHeight();
		int iconHeight = this.getIcon().getIconHeight();
		int iconWidth = this.getIcon().getIconWidth();

		double gapX = 0;
		double gapY = 0;
		int scrollHeight = this.canvas.getHorizontalScrollBar().getHeight();
		int scrollWidth = this.canvas.getVerticalScrollBar().getWidth();
		if (iconWidth < canvasWidth) {
			gapX = (double) (canvasWidth - scrollWidth - iconWidth) / 2.0;

		}
		if (iconHeight < canvasHeight) {
			gapY = (canvasHeight - scrollHeight - iconHeight) / 2.0;

		}

		x -= gapX;
		y -= gapY;

		int width = this.canvas.getSpread().getWidth();
		int w = iconWidth;
		double ratio = (double) ((double) w / (double) width);
		Point p = new Point((int) (x / ratio), (int) (y / ratio));
		return p;
	}

	private GSMouseEvent getAdjustedMouseEvent(MouseEvent e) {
		Point p = this.getAdjustedPoint(e.getPoint());
		return new GSMouseEvent(e, p);
	}

	public void mouseDragged(MouseEvent e) {
		// 2010/11/24 kukita
		
		this.repaint();
	}

	public void mouseMoved(MouseEvent e) {
		GSMouseEvent ge = this.getAdjustedMouseEvent(e);
		getState().mouseMoved(ge, canvas);
		this.repaint();
	}

	public void mouseClicked(MouseEvent e) {
		Cursor cursor = this.getCursor();
		GSMouseEvent ge = this.getAdjustedMouseEvent(e);
		getState().mouseClicked(ge, canvas);
		this.repaint();
		this.setCursor(cursor);
	}

	public void mouseEntered(MouseEvent e) {
		GSMouseEvent ge = this.getAdjustedMouseEvent(e);
		getState().mouseEntered(ge, canvas);
		this.repaint();
	}

	public void mouseExited(MouseEvent e) {
		GSMouseEvent ge = this.getAdjustedMouseEvent(e);
		getState().mouseExited(ge, canvas);
		this.repaint();
	}

	public void mousePressed(MouseEvent e) {
		// 2007/11/19 kazuhiro kobayashi
		this.start = e.getPoint();
		//
		this.tempViews.clear();
		GSMouseEvent ge = this.getAdjustedMouseEvent(e);
		getState().mousePressed(ge, canvas);
		this.repaint();
	}

	public void mouseReleased(MouseEvent e) {
		// 2007/11/19 kazuhiro kobayashi
			this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
			this.start = null;
			this.end = null;
		//
		GSMouseEvent ge = this.getAdjustedMouseEvent(e);
		getState().mouseReleased(ge, canvas);
		this.repaint();
	}

	/**
	 * 
	 * @param point
	 *            original
	 */
	public void setCenterLocation(Point point) {
		double ratio = this.getRatio();
		int x = (int) (point.x * ratio);
		int y = (int) (point.x * ratio);
		this.setLocation(-x + 100, -y + 100);
	}

	//2011/01/25/ kukita
	public void moveTo(Point point) {
		int locX = (int)this.getLocation().getX();
		int locY = (int)this.getLocation().getY();

		int cw = this.canvas.getWidth();
		int ch = this.canvas.getHeight();
		int sh = this.canvas.getHorizontalScrollBar().getHeight();
		int sw = this.canvas.getVerticalScrollBar().getWidth();
		int iw = this.getIcon().getIconWidth();
		int ih = this.getIcon().getIconHeight();
		int x;
		int y; 
		double ratio = this.getRatio();
		if (iw < cw) {
			x = locX;
		} else {
			x = (int) (cw/2 - (point.x * ratio));
			if (x > 0) {
				x = 0;
			} else if (x < cw - (sw + iw)) {
				x = cw - (sw + iw);
			}
		}
		if (ih < ch) {
			y = locY;
		} else {
			y = (int) (ch/2 - (point.y * ratio));
			if (y > 0) {
				y = 0;
			} else if (y < ch - (sh + ih)) {
				y = ch - (sh + ih);
			}
		}
	
		int hscroll = 0;
		while (!neighbor((int)this.getLocation().getX(),x)) {
			hscroll++;
			this.canvas.getHorizontalScrollBar().setValue(hscroll);
		}
		int vscroll = 0;
		while (!neighbor((int)this.getLocation().getY(),y)) {
			vscroll++;
			this.canvas.getVerticalScrollBar().setValue(vscroll);
		}

	}

	private static boolean neighbor(int n, int m) {
		return ((n - m) * (n - m)) <=1 ;
	}

	
	public void addTempView(View view) {
		this.tempViews.add(view);
	}

	/**
	 * 
	 * 
	 * @return
	 */
	public Spread getSpread() {
		return this.canvas.getSpread();
	}

	public void setCurrentWidth(int currentWidth) {
		this.currentWidth = currentWidth;
	}

	public int getCurrentWidth() {
		return currentWidth;
	}

	public void setCurrentHeight(int currentHeight) {
		this.currentHeight = currentHeight;
	}

	public int getCurrentHeight() {
		return currentHeight;
	}

	public void setImageWidth(int imageWidth) {
		this.imageWidth = imageWidth;
	}

	public int getImageWidth() {
		return imageWidth;
	}

	public void setImageHeight(int imageHeight) {
		this.imageHeight = imageHeight;
	}

	public int getImageHeight() {
		return imageHeight;
	}

	public LineSegEditorState getState() {
		return state;
	}
		
	public void setState(LineSegEditorState state){
		this.state = state;
	}
	
	public void setMode(LineSegEditorMode mode){
		this.mode = mode;
		this.state.setMode(mode);
	}

	public Show getLineSegShowingMode() {
		return lineSegShowingMode;
	}
	public void setLineSegShowingMode(Show mode) {
		lineSegShowingMode = mode;
	}

	public void stepLineSegShowingMode(Show mode) {
		if (mode == Show.LINE_AND_INDEX) {
			lineSegShowingMode = Show.LINE;
		} else if (mode == Show.LINE) {
			lineSegShowingMode = Show.LINE_AND_INDEX;
		}
	}


	public void rewriteLinesSegIndexes() {
		for (int i = 0; i<lines.size();i++){
			lines.get(i).setIndex(i);
		}
	}


	public void addLineSegmentForEdit(LineSegmentForEdit LineSegmentForEdit) {
		this.lines.add(LineSegmentForEdit);		
	}
	
	/**
	 * @return the lines
	 */
	public List<LineSegmentForEdit> getLines() {
		return this.lines;
	}
	
	public void loadLinesFromXMLFile() {		
		String filename = Preference.getInstance().getDscFolderPathString() + this.canvas.getSpread().getSpreadDirParent().getPath()
		+ this.canvas.getSpread().getFileNameWithoutExtension() + ".xml";

		File file = new File(filename);
		if (!file.exists()) {
			this.lines = null;
			return;
		}
		this.lines = new XMLToLineConverter(this.canvas.getSpread()).getLinesForEdit(new File(
				filename));
	}

	/**
	 * @param lines the lines to set
	 */
	public void setLines(List<LineSegmentForEdit> lines) {
		this.lines = lines;
	}
}
