/* $Id: MarkerView.java 741 2013-09-09 04:48:44Z minao $ */
package smart_gs.drawing_tool.view;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;

import javax.swing.ImageIcon;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import smart_gs.GSConstants;
import smart_gs.debugprint.Debugprint;
import smart_gs.drawing_tool.ExLine2D;
import smart_gs.drawing_tool.view.View.ViewColor;
import smart_gs.logical.Preference;
import smart_gs.logical.URICreator;
import smart_gs.swingui.WorkspaceWindow;
import sml_editor.logical.LineDirection;


public class MarkerView extends LineView{
	public static enum MarkerColor{YELLOW, CYAN, MAGENTA, GREEN}
	public static Color MARKER_YELLOW = new Color(Color.YELLOW.brighter().getRed(),Color.YELLOW.brighter().getGreen(),Color.YELLOW.brighter().getBlue(),128);
	public static Color MARKER_CYAN = new Color(0,255,255,128);
	public static Color MARKER_MAGENTA = new Color(255,153,255,128);
	public static Color MARKER_GREEN = new Color(153,255,0,128);
	public static Color DEFAULT_MARKER_COLOR = MARKER_YELLOW;
	public static int DEFAULT_MARKER_BREADTH = 20;

	private int breadth = DEFAULT_MARKER_BREADTH;
	private AffineTransform rotate;
	private Color color = DEFAULT_MARKER_COLOR;
	
	public MarkerView(Point2D start, Point2D end) {
		super(start, end);
		this.setPreferedColorAndBreadth();
		this.init();
	}
	public MarkerView(ExLine2D line){
		super(line);
		this.setPreferedColorAndBreadth();
		this.init();
	}
	public MarkerView(ExLine2D line,boolean isSelected,boolean isEmphasized, boolean isProtected){
		this(line);
		this.setPreferedColorAndBreadth();
		this.isSelected = isSelected;
		this.isEmphasized = isEmphasized;
		this.isProtected = isProtected;
	}
	private void init(){
//		Color selectColor = this.color;
//		selectColor = new Color(selectColor.getRed(),selectColor.getGreen(),selectColor.getBlue(),128);
//		this.setSelectionColor(selectColor);
//		this.setSelectionStroke(new BasicStroke(breadth));
		
//		Color protectedColor = color;
//		this.setProtectedColor(protectedColor);
//		this.setProtectedStroke(new BasicStroke(breadth));
		
		this.defaultColor = color;
		this.defaultStroke = new BasicStroke(breadth);
	}
	@Override
	public int getType() {
		return View.MARKER;
	}
	@Override
	public void drawShape(Graphics2D g) {
		if (isSelected) {
			g.setColor(this.color);
			this.drawSelectedIcon(g);
		} else if (isEmphasized) {
			g.setColor(this.color);
		} else {
			g.setColor(this.color);
		}
		g.setStroke(new BasicStroke(breadth));
		g.fill(this.enclosingRect(0));
		if (this.isProtected) {
			g.setColor(Color.BLACK);
			g.setStroke(new BasicStroke(1));
			g.draw(this.enclosingRect(3));
		}
	}

	@Override
	public View enlargedView(double ratio, double gapX, double gapY) {
		Point2D start = this.line.getP1();
		Point2D end = this.line.getP2();
		Point2D p1 = new Point2D.Double(start.getX()*ratio+gapX,start.getY()*ratio+gapY);
		Point2D p2 = new Point2D.Double(end.getX()*ratio+gapX,end.getY()*ratio+gapY);
		MarkerView mview = new MarkerView(new ExLine2D(p1,p2),this.isSelected,this.isEmphasized, this.isProtected);
		mview.color = this.color;
		mview.breadth = (int) (this.breadth*ratio);
		return mview;
	}
	@Override
	public String getTypeString() {
		return URICreator.MARKER;
	}
	@Override
	public boolean contains(Point2D point) {
		return this.enclosingRect(0).contains(point);
	}
	
	@Override
	public Element createXMLElement(Document document) {
		Element element = document.createElement("view");
		element.setAttribute("type",URICreator.MARKER);
		element.setAttribute("x1",this.line.x1+"");
		element.setAttribute("y1",this.line.y1+"");
		element.setAttribute("x2",this.line.x2+"");
		element.setAttribute("y2",this.line.y2+"");
		element.setAttribute("color", colorToString(this.color));
		element.setAttribute("breadth",this.breadth+"");
		return element;
	}
	public static String colorToString(Color c) {
		if (c.equals(MarkerView.MARKER_YELLOW)) {
			return "yellow";
		} else if (c.equals(MarkerView.MARKER_CYAN)) {
			return "cyan";
		} else if (c.equals(MarkerView.MARKER_MAGENTA)){
			return "magenta";
		} else {
			return "green";
		}
	}
	public static Color stringToColor(String s) {
		if (s.equals("yellow")) {
			return MarkerView.MARKER_YELLOW;
		} else if (s.equals("cyan")) {
			return MarkerView.MARKER_CYAN;
		} else if (s.equals("magenta")) {
			return MarkerView.MARKER_MAGENTA;
		} else {
			return MarkerView.MARKER_GREEN;
		}
	}
	@Override
	public void drawLinkedShape(Graphics2D g, Image image) {
		this.draw(g);
		this.drawLinkIcon(g, image);
		return;
	}
	@Override
	public void drawTemporaryShape(Graphics2D g, Image image) {
		this.draw(g);
		this.drawTemporaryIcon(g);
	}
	public static MarkerView restore(Element elem) {
		double x1 = new Double(elem.getAttribute("x1"));
		double y1 = new Double(elem.getAttribute("y1"));
		double x2 = new Double(elem.getAttribute("x2"));
		double y2 = new Double(elem.getAttribute("y2"));
		Color col;
		if (elem.hasAttribute("color")) {
			col = stringToColor(elem.getAttribute("color"));
		} else {
			col = stringToColor(Preference.getInstance().getMarkerColor());
		}
		int br;
		if (elem.hasAttribute("breadth")) {
			br = Integer.parseInt(elem.getAttribute("breadth"));
		} else {
			br = new Integer(Preference.getInstance().getMarkerBreadth());
		}
		MarkerView mview =  new MarkerView(new ExLine2D(x1,y1,x2,y2));
		mview.color = col;
		mview.breadth = br;
		return mview;
	}
	@Override
	public Rectangle2D getRectangle2D() {
		double x1 = this.getMinX();
		double x2 = this.getMaxX();
		double y1 = this.getMinY();
		double y2 = this.getMaxY();
		double width = ((BasicStroke)this.defaultStroke).getLineWidth();
		return new Rectangle2D.Double(x1-1,y1-25,(x2-x1),y2-y1+width+50);
	}
	@Override
	public void setViewColor(ViewColor c) {
		switch(c) {
		case YELLOW:
			this.color = MarkerView.MARKER_YELLOW;
			WorkspaceWindow.getInstance().repaint();
			return;
		case CYAN:
			this.color = MarkerView.MARKER_CYAN;
			WorkspaceWindow.getInstance().repaint();
			return;
		case MAGENTA:
			this.color = MarkerView.MARKER_MAGENTA;
			WorkspaceWindow.getInstance().repaint();
			return;
		case GREEN:
			this.color = MarkerView.MARKER_GREEN;
			WorkspaceWindow.getInstance().repaint();
			return;
		default:
			this.color = MarkerView.MARKER_YELLOW;
			WorkspaceWindow.getInstance().repaint();
			return;
		}
	}
	public int getBreadth() {
		return breadth;
	}
	public void setBreadth(int b) {
		this.breadth = b;
		WorkspaceWindow.getInstance().repaint();
	}
	public double length() {
		return line.getP1().distance(line.getP2());
	}
	public Point2D leftPoint() {
		if (this.line.getP1().getX() <= this.line.getP2().getX()) {
			return this.line.getP1();
		} else {
			return this.line.getP2();
		}
	}
	public Point2D rightPoint() {
		if (this.line.getP1().getX() >= this.line.getP2().getX()) {
			return this.line.getP1();
		} else {
			return this.line.getP2();
		}
		
	}
	public Point2D topPoint() {
		if (this.line.getP1().getY() <= this.line.getP2().getY()) {
			return this.line.getP1();
		} else {
			return this.line.getP2();
		}
		
	}

	public double angle() {
		double r = this.length();
		double h = this.rightPoint().getY() - this.leftPoint().getY();
		return Math.asin(h/r);
	}
	public Shape enclosingRect(double margin) {
		double x0 = this.leftPoint().getX();
		double y0 = this.leftPoint().getY();
		double x = x0 - margin;
		double y = y0 - margin;
		double w = this.length() + (margin * 2);
		double h = breadth + margin * 2;
		double theta = angle();
		AffineTransform rotate = AffineTransform.getRotateInstance(theta, x0, y0);
		Rectangle2D rect = new Rectangle2D.Double(x, y, w, h);
		return rotate.createTransformedShape(rect);
	}
	@Override
	public String getTypeStringForDisplay() {
		return "Marker";
	}
	@Override
	public void drawLinkIcon(Graphics2D g, Image image) {
		Point2D endPoint = this.getLine().getP2();
		int x = (int)endPoint.getX();
		int y = (int)endPoint.getY();
		int w = image.getWidth(null) / 3;
		int h = image.getHeight(null) / 3;
		g.drawImage(image, x, y, w, h, null);
	}
	@Override
	public void drawTemporaryIcon(Graphics2D g) {
		Image image = new ImageIcon(GSConstants.ICON_PATH + "Temporary.png").getImage();
		Point2D endPoint = this.getLine().getP2();
		int x = (int)endPoint.getX();
		int y = (int)endPoint.getY();
		int w = image.getWidth(null) / 3;
		int h = image.getHeight(null) / 3;
		g.drawImage(image, x, y, w, h, null);
	}
	public void drawSelectedIcon(Graphics2D g) {
		LineDirection direction = WorkspaceWindow.getInstance().getSpread().getLineDirection();
		ImageIcon selected = new ImageIcon(GSConstants.ICON_PATH + "selected_mark.png");
		Image image = selected.getImage();
		Point2D point = this.leftPoint();
		if (direction == LineDirection.VERTICAL) {
			point = this.topPoint();
		}
		int w = (int)(image.getWidth(null) / 2.5);
		int h = (int)(image.getHeight(null) / 2.5);
		int x = (int)(point.getX()) - w;
		int y = (int)(point.getY()) - h;
		g.drawImage(image, x, y, w, h, null);
	}
	
	private static boolean isNumeral(char c) {
		String numerals = "0123456789";
		for (int i = 0; i < numerals.length(); i++) {
			if (c == numerals.charAt(i)) {
				return true;
			}
		}
		return false;
	}
	private static boolean isConvertibleToInteger(String str) {
		if (str == null) {
			return false;
		}
		if (str.length() == 0) {
			return false;
		}
		for (int i = 0; i < str.length(); i++) {
			if (!(isNumeral(str.charAt(i)))) {
				return false;
			}
		}
		return true;
	}
	
	private void setPreferedColorAndBreadth() {
		Color preferedColor = MarkerView.stringToColor(Preference.getInstance().getMarkerColor());
		if (preferedColor != null) {
			this.color = preferedColor;
		}
		int preferedBreadth = 0;
		String preferedBreadthString = (Preference.getInstance().getMarkerBreadth());
		if (isConvertibleToInteger(preferedBreadthString)) {
			preferedBreadth = new Integer(preferedBreadthString);
		}
		if (preferedBreadth >= 5){
			this.breadth = preferedBreadth;
		}
	}

}
