/* $Id: View.java 1058 2016-01-17 17:09:20Z shayashi $ */
package smart_gs.drawing_tool.view;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
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.drawing_tool.ExLine2D;
import smart_gs.logical.Region;


public abstract class View {
	public enum ViewColor {YELLOW, CYAN, MAGENTA, GREEN, TRANSPARENT, OPAQUE}

	public static final int RECTANGLE = 0;
	public static final int MARKER = 1;
	public static final int POLYGON = 2;
	public static final int LINE_SEGMENT = 3;
	public static final int LINE = 4;
	public static final int MEMOPAD = 5;
	public static final int BOOKMARK = 6;
	public static final int ANCHOR = 7;
	public static final int CENTER = 0;
	
	public static final String linkInIconName = "link_in.png";
	public static final String linkOutIconName = "link_out.png";
	public static final String linkBothIconName = "link_both.png";
	public static final String rwIconName = "reasoning_web.png";
	public static final String tempIconName = "Temporary.png";
	public static final String inBasketIconName = "basketWithItem.png";
	
	protected boolean isSelected;
	protected boolean isEmphasized;
	protected boolean isProtected;
	protected boolean isSelectable = true;
	protected Color defaultColor;
	protected Stroke defaultStroke;
	protected Color selectionColor;
	protected Stroke selectionStroke;
	protected Color emphasizeColor;
	protected Stroke emphasizeStroke;

	protected Color protectedColor;
	protected Stroke protectedStroke;
	protected String title;
		
	protected View(){
		this.selectionColor = Color.RED;
		this.selectionStroke = new BasicStroke();
		this.emphasizeColor = Color.RED;
		this.emphasizeStroke = new BasicStroke(5);
		
		Color c = new Color(50,150,100);
		this.protectedColor = c;
		this.protectedStroke = new BasicStroke(2);
		
		this.defaultColor = Color.black;
	}
	
	public abstract void moveBy(Point2D d);
	public abstract boolean contains(Point2D point);
	public abstract View enlargedView(double ratio,double gapX,double gapY);
	public boolean isSelected(){
		return this.isSelected;
	}
	public void setIsSelected(boolean isSelected) {
		this.isSelected = isSelected;
	}
	public void setIsEmphasized(boolean isEmphasized){
		this.isEmphasized = isEmphasized;
	}
	/*
	 *2007/9/13 
	 */
	public void setIsProtected(String protection){
		//kazuhiro kobayashi 10/7
		this.isProtected = protection.equals(Region.PROTECTED);
	}
	
	public final void draw(Graphics2D g){
		Color oldColor = g.getColor();
		Stroke oldStroke = g.getStroke();
		if(this.isEmphasized){
			g.setColor(this.emphasizeColor);
			g.setStroke(this.emphasizeStroke);
		}
		else if(this.isSelected){
			g.setColor(this.selectionColor);
			g.setStroke(this.selectionStroke);
		}
		else if(this.isProtected){
			g.setColor(this.protectedColor);
			g.setStroke(this.protectedStroke);
		}
		else{
			g.setColor(this.defaultColor);
			if(this.defaultStroke != null){
				g.setStroke(this.defaultStroke);
			}
		}
		
		this.drawShape(g);
		g.setColor(oldColor);
		g.setStroke(oldStroke);
	}
	protected abstract void drawShape(Graphics2D g);
	
	public Color getSelectionColor() {
		return this.selectionColor;
	}
	public Stroke getSelectionStroke(){
		return this.selectionStroke;
	}
	public Color getProtectedColor(){
		return this.protectedColor;
	}
	public Stroke getProtectedStroke(){
		return this.protectedStroke;
	}
	public void setSelectionColor(Color color){
		this.selectionColor = color;
	}
	public void setSelectionStroke(Stroke stroke){
		this.selectionStroke = stroke;
	}
	public void setProtectedColor(Color color){
		this.protectedColor = color;
	}
	public void setProtectedStroke(Stroke stroke){
		this.protectedStroke = stroke;
	}
	public abstract Rectangle2D getRectangle2D();

	public final Rectangle getRectangle() {
		Rectangle2D rect = this.getRectangle2D();
		int x = (int)rect.getX();
		int y = (int)rect.getY();
		int width = (int)rect.getWidth();
		int height = (int)rect.getHeight();
		Rectangle r = new Rectangle(x,y,width,height);
		return r;
	}
	public int getHeight() {
		Rectangle2D rect = this.getRectangle2D();
		return (int)rect.getHeight();
	}
	public int getWidth() {
		Rectangle2D rect = this.getRectangle2D();
		return (int)rect.getWidth();
	}
	public abstract String getTypeString();
	public abstract int getType();
	public abstract Element createXMLElement(Document document);
	public boolean containsInCorner(Point2D point) {
		return false;
	}
	public boolean isResizable() {
		return false;
	}
	public void resize(Point2D d) {
	}

	public boolean isProtected() {
		return this.isProtected;
	}

	public abstract Point getCenterPoint();


	public void setViewColor(ViewColor color) {
		return;
	}
	public static boolean lineContains(ExLine2D line, double breadth, Point2D point) {
		double x1, y1, x2, y2;
		if (line.getP1().getX() < line.getP2().getX()) {
			x1 = line.getP1().getX();
			y1 = line.getP1().getY();
			x2 = line.getP2().getX();
			y2 = line.getP2().getY();
		} else {
			x1 = line.getP2().getX();
			y1 = line.getP2().getY();
			x2 = line.getP1().getX();
			y2 = line.getP1().getY();			
		}
		double d = line.getP1().distance(line.getP2());
		double y = y2 - y1;
		double theta = Math.asin(y/d);
		AffineTransform rotate = AffineTransform.getRotateInstance(theta, x1, y1);
		Rectangle2D rect = new Rectangle2D.Double(x1, y1 - breadth/2, d, breadth);
		Shape shape = rotate.createTransformedShape(rect);
		return shape.contains(point);
	}
	
	public abstract String getTypeStringForDisplay();

	public int getIndex() {
		return 0;
	}

	public String getTitle() {
		if (this.title == null || this.title.equals("")) {
			return "UNTITLED";
		} else {
			return this.title;
		}
	}

	public void setTitle(String title) {
		this.title = title;
	}
	
	protected abstract Rectangle closeUpImageRectangle();
	
	public boolean containsInCloseUpIcon(Point2D point) {
		Rectangle closeUpImageRectangle = this.closeUpImageRectangle();
		int w = (int)closeUpImageRectangle.getWidth();
		int h = (int)closeUpImageRectangle.getHeight();
		int x = (int)closeUpImageRectangle.getX();
		int y = (int)closeUpImageRectangle.getY();
		double px = point.getX();
		double py = point.getY();
		return px >= x && px <= x+w && py >= y && py <= y+h;
	}


	public abstract void drawSelectedIcon(Graphics2D g);
	public void drawTemporaryAndInBasketShape(Graphics2D g) {
		this.draw(g);
		Image tempIcon = this.getAuxIcon(tempIconName);
		Image basketIcon = this.getAuxIcon(inBasketIconName);
		Rectangle rect = this.getRectangle();
		int w = tempIcon.getWidth(null) / 3;
		int h = tempIcon.getHeight(null) / 3;
		Point2D iconPoint1 = this.getFirstAuxIconPoint(w, h);
		int x = (int)iconPoint1.getX();
		int y = (int)iconPoint1.getY();
		Point2D iconPoint2 = this.getSecondAuxIconPoint(x, y, w, h);
		int w2 = basketIcon.getWidth(null) / 3;
		int h2 = basketIcon.getHeight(null) / 3;
		int x2 = (int)iconPoint2.getX();
		int y2 = (int)iconPoint2.getY();
		g.drawImage(tempIcon, x, y, w, h, null);
		g.drawImage(basketIcon, x2, y2, w2, h2, null);

	}
	public void drawLinkedAndInBasketShape(Graphics2D g, Image linkedImage) {
		this.draw(g);
		int w = linkedImage.getWidth(null) / 3;
		int h = linkedImage.getHeight(null) / 3;
		Point2D iconPoint1 = this.getFirstAuxIconPoint(w, h);
		int x = (int)iconPoint1.getX();
		int y = (int)iconPoint1.getY();
		Point2D iconPoint2 = this.getSecondAuxIconPoint(x, y, w, h);
		Image basketIcon = this.getAuxIcon(inBasketIconName);
		int w2 = (int)basketIcon.getWidth(null)/3;
		int h2 = (int)basketIcon.getHeight(null)/3;
		int x2 = (int)iconPoint2.getX();
		int y2 = (int)iconPoint2.getY();
		g.drawImage(linkedImage, x, y, w, h, null);
		g.drawImage(basketIcon, x2, y2, w2, h2, null);
	}
	
	
	public Image getAuxIcon(String iconName) {
		return new ImageIcon(GSConstants.ICON_PATH + iconName).getImage();

	}
	
	
	public Point2D getFirstAuxIconPoint(int w, int h) {
		Rectangle rect = this.getRectangle();
		int x = (int)(rect.getX() + rect.getWidth() - w/3);
		int y = (int)(rect.getY()) - h/2;
		return new Point2D.Double(x, y);
	}
	public Point2D getSecondAuxIconPoint(int firstIconX, int firstIconY, double firstIconW, double firstIconH) {
		int x = (int) firstIconX;
		int y = (int)(firstIconY + (firstIconH*1.2));
		return new Point2D.Double(x, y);
	}

	public void drawRWAndInBasketShape(Graphics2D g) {
		this.draw(g);
		Image rwIcon = this.getAuxIcon(rwIconName);
		int w = rwIcon.getWidth(null) / 3;
		int h = rwIcon.getHeight(null) / 3;
		Point2D iconPoint1 = this.getFirstAuxIconPoint(w, h);
		int x = (int)iconPoint1.getX();
		int y = (int)iconPoint1.getY();
		Point2D iconPoint2 = this.getSecondAuxIconPoint(x, y, w, h);
		Image basketIcon = this.getAuxIcon(inBasketIconName);
		int w2 = (int)basketIcon.getWidth(null)/3;
		int h2 = (int)basketIcon.getHeight(null)/3;
		int x2 = (int)iconPoint2.getX();
		int y2 = (int)iconPoint2.getY();
		g.drawImage(rwIcon, x, y, w, h, null);
		g.drawImage(basketIcon, x2, y2, w2, h2, null);
	}

	
	public void drawInBasketShape(Graphics2D g) {
		this.draw(g);
		this.drawInBasketIcon(g);
	}
	protected void drawInBasketIcon(Graphics2D g) {
		Image image = this.getAuxIcon(inBasketIconName);
		Rectangle rect = this.getRectangle();
		int w = image.getWidth(null) / 3;
		int h = image.getHeight(null) / 3;
		Point2D iconPoint1 = this.getFirstAuxIconPoint(w, h);
		int x = (int)iconPoint1.getX();
		int y = (int)iconPoint1.getY();
		g.drawImage(image, x, y, w, h, null);
	}
	public void drawRWShape(Graphics2D g) {
		this.draw(g);
		this.drawRWIcon(g);
	}	
	protected void drawRWIcon(Graphics2D g) {
		Image image = new ImageIcon(GSConstants.ICON_PATH + "reasoning_web.png").getImage();
		Rectangle rect = this.getRectangle();
		int w = image.getWidth(null) / 3;
		int h = image.getHeight(null) / 3;
		Point2D iconPoint1 = this.getFirstAuxIconPoint(w, h);
		int x = (int)iconPoint1.getX();
		int y = (int)iconPoint1.getY();
		g.drawImage(image, x, y, w, h, null);
	}
	public void drawLinkedShape(Graphics2D g, Image image) {
		this.draw(g);
		this.drawLinkIcon(g, image);
	}
	public void drawLinkIcon(Graphics2D g, Image image) {
		Rectangle rect = this.getRectangle();
		int w = image.getWidth(null) / 3;
		int h = image.getHeight(null) / 3;
		Point2D iconPoint1 = this.getFirstAuxIconPoint(w, h);
		int x = (int)iconPoint1.getX();
		int y = (int)iconPoint1.getY();
		g.drawImage(image, x, y, w, h, null);
	}
	public void drawTemporaryShape(Graphics2D g) {
		this.draw(g);
		this.drawTemporaryIcon(g);
	}
	public void drawTemporaryIcon(Graphics2D g) {
		Image image = new ImageIcon(GSConstants.ICON_PATH + "Temporary.png").getImage();
		Rectangle rect = this.getRectangle();
		int w = image.getWidth(null) / 3;
		int h = image.getHeight(null) / 3;
		int x = (int)(rect.getX() + rect.getWidth() - w/3);
		int y = (int)(rect.getY()) - h/2;
		g.drawImage(image, x, y, w, h, null);
	}
}