/* $Id: LineSegView.java 1100 2016-05-05 06:53:11Z shayashi $ */
package smart_gs.drawing_tool.view;

import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.swing.ImageIcon;

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

import smart_gs.GSConstants;
import smart_gs.drawing_tool.ExLine2D;
import smart_gs.drawing_tool.ImageLabel;
import smart_gs.drawing_tool.drawing_mode.LineSegEditorEditVertexMode;
import smart_gs.drawing_tool.drawing_mode.LineSegEditorMode;
import smart_gs.logical.URICreator;
import smart_gs.util.GSLog;
import smart_gs.util.Pair;
import sml_editor.logical.LineDirection;

public class LineSegView extends View{
	Color LineSegmentDefaultColor = new Color(0,0,80,80);
	private List<LineView> lineViews;
	private int index;
	private IndexView indexView;
	private LineDirection lineDirection;
	private Color lineSegViewSelectionColor = Color.YELLOW;
	private boolean vertexEditMode = false;
	private final static  double VERTEX_WIDTH = 6.0d;
	private final static  double VERTEX_HEIGHT = 6.0d;
	private final static  double X_OFFSET = VERTEX_WIDTH/2;
	private final static  double Y_OFFSET = VERTEX_HEIGHT/2;

	public LineSegView(LineDirection lineDirection, int index){
		this.lineViews = new ArrayList<LineView>();
//		Line_segment color shayashi 2011.05.31
		this.defaultColor = LineSegmentDefaultColor;
		this.index = index;
		this.lineDirection = lineDirection;
//		this.createIndexView(index);
	}
	
	
	public LineSegView(List<ExLine2D> exLines, LineDirection lineDirection, int index){
		super();
		this.lineDirection = lineDirection;
		this.lineViews = new ArrayList<LineView>();
		for(int i=0;i<exLines.size();i++){
			this.lineViews.add(new LineView(exLines.get(i)));
		}
		if (exLines.size()>0) {
			this.lineViews.add(new LineView(new ExLine2D(exLines.get(exLines.size()-1).getP2(),exLines.get(0).getP1())));
		}
		//		Line_segment color shayashi 2011.05.31
		this.defaultColor = LineSegmentDefaultColor;
		this.index = index;
		if (this.lineViews.size() != 0) {
			this.createIndexView(index);
		}
	}
	
	public LineSegView(List<ExLine2D> lines, LineDirection lineDirection, boolean isSelected,boolean isEmphasized, boolean isProtected, int index) {
		this(lines, lineDirection, index);
		this.isSelected = isSelected;
		this.isEmphasized = isEmphasized;
		this.isProtected = isProtected;
		this.lineDirection = lineDirection;
	}

	public LineSegView(List<ExLine2D> exLines) {
		super();
		this.lineViews = new ArrayList<LineView>();
		for(int i=0;i<exLines.size();i++){
			this.lineViews.add(new LineView(exLines.get(i)));
		}
		this.lineViews.add(new LineView(new ExLine2D(exLines.get(exLines.size()-1).getP2(),exLines.get(0).getP1())));
		this.defaultColor = LineSegmentDefaultColor;
		this.selectionColor = Color.red;
	}
	

	public static double getVERTEX_WIDTH() {
		return VERTEX_WIDTH;
	}
	public static double getVERTEX_HEIGHT() {
		return VERTEX_HEIGHT;
	}
	public static double getX_OFFSET() {
		return X_OFFSET;
	}
	public static double getY_OFFSET() {
		return Y_OFFSET;
	}
	
	// changed 2011.01.02 shayashi
	@Override
	public boolean contains(Point2D point) {
		int xpoints[],  ypoints[];
		xpoints = new int[lineViews.size()];
		ypoints = new int[lineViews.size()];
		Polygon polygon;
		for(int i=0;i<this.lineViews.size();i++){
			xpoints[i] = (int)this.lineViews.get(i).getLine().getP1().getX();
			ypoints[i] = (int)this.lineViews.get(i).getLine().getP1().getY();
		}
		polygon = new Polygon(xpoints,ypoints,lineViews.size());
		return polygon.contains(point);
	}
	
	// The returned an int i such that
	//　i is the index of the pressed vertex of the LineView. It starts from 0. If i < 0, then 
	// the point is not on a vertex. If the LineView contains (by the method above) the point,
	// then i = -1. Otherwise, i = -2.
	public int indexOfPressedVertex(Point2D point) {
		double x = point.getX();
		double y = point.getY();
		
		for (int i = 0; i<lineViews.size(); i++) {
			LineView line_view = lineViews.get(i);
			Point2D start_point = line_view.getStartPoint();
			Point2D end_point = line_view.getEndPoint();
            double start_point_X = start_point.getX()-X_OFFSET;
            double start_point_Y = start_point.getY()-Y_OFFSET;
            
            if (start_point_X <= x && x <= start_point_X+VERTEX_WIDTH && start_point_Y <= y && y <= start_point_Y +VERTEX_HEIGHT)  {
            	return i;
            }
		}
		
        if (this.contains(point)) return -1;

        return -2;
	}
	
	// The returned an int i such that
	//　i is the index of the first LineView very closed to the specified point.
	// The index start from 0.
	// When it returns -1, there is no such LineView.
	public int indexOfPressedLineView(Point2D point) {
		int ans = -1;
		
		for (int i = 0; i<lineViews.size(); i++) {
			ExLine2D line = lineViews.get(i).getLine();
            if (((Line2D)line).ptSegDist(point) < 3d)  {
            	ans = i;
            	break;
            }
		}
		
        return ans;
	}
	
	public void addLineView(LineView line){
		this.lineViews.add(line);
	}
	@Override
	public void drawShape(Graphics2D g) {
		Color oldColor = g.getColor();
		if (this.isSelected()) {
			g.setColor(this.lineSegViewSelectionColor);
		}
		for(int i=0;i<this.lineViews.size();i++){
			this.lineViews.get(i).drawShape(g);
		}
		
		g.setColor(oldColor);

	}
	
//	public void drawShape(Graphics2D g, LineSegEditorImageLabel.Show mode) {
//		if (mode == LineSegEditorImageLabel.Show.LINE_AND_INDEX) {
//			this.drawShape(g);
//			this.indexView.drawShape(g);
//		} else if (mode == LineSegEditorImageLabel.Show.LINE) {
//			this.drawShape(g);
//		} 
//	}

	public void drawShapeForImageLabel(Graphics2D g, ImageLabel.Show mode) {
		if (mode == ImageLabel.Show.LINE_AND_INDEX) {
			this.drawShape(g);
			this.indexView.drawShape(g);
		} else if (mode == ImageLabel.Show.LINE) {
			this.drawShape(g);
		} 
	}
	
	public void drawShapeForLineSegEditorImageLabel(
			Graphics2D g,
			smart_gs.drawing_tool.LineSegEditorImageLabel.Show lineSegShowingMode, LineSegEditorMode mode) {
	
		boolean vertexEditMode = false;
		
		if (mode instanceof LineSegEditorEditVertexMode) {
			vertexEditMode = true;
			lineSegShowingMode = smart_gs.drawing_tool.LineSegEditorImageLabel.Show.LINE;
		}

		if (lineSegShowingMode == smart_gs.drawing_tool.LineSegEditorImageLabel.Show.LINE_AND_INDEX) {
			this.drawShape(g);
			this.indexView.drawShape(g);

		} else if (lineSegShowingMode == smart_gs.drawing_tool.LineSegEditorImageLabel.Show.LINE) {
			this.drawShape(g);
			if (vertexEditMode) this.drawVertexes(g);
		} 
		
	}
	
	private void drawVertexes(Graphics2D g) {
		Iterator<LineView> it = this.lineViews.iterator();
		
		while (it.hasNext()) {
			LineView line = it.next();
			drawVertex(line.getStartPoint(),g);
		}
		
	}
	private void drawVertex(Point2D point, Graphics g) {
		Rectangle rect = new Rectangle();
	    rect.setRect(point.getX()-X_OFFSET,point.getY()-Y_OFFSET, VERTEX_WIDTH, VERTEX_HEIGHT);
	    ((Graphics2D) g).fill(rect);
	}
	
	@Override
	public int getType() {
		return View.LINE_SEGMENT;
	}
	
	//2011/01/06 kukita
	public String getTypeString() {
		return URICreator.LINE_SEGMENT;
	}

	@Override
	public void moveBy(Point2D d) {
		for(int i=0;i<this.lineViews.size();i++){
			this.lineViews.get(i).moveBy(d);
		}
	}

	@Override
	public View enlargedView(double ratio, double gapX, double gapY) {
		List<ExLine2D> newLines = new ArrayList<ExLine2D>();
		for(int i=0;i<this.lineViews.size();i++){
			LineView line = this.lineViews.get(i);
			line = (LineView)line.enlargedView(ratio,gapX,gapY);
			newLines.add(line.getLine());
		}
		return new LineSegView(newLines,this.lineDirection, this.isSelected,this.isEmphasized, this.isProtected, this.index);
	}
	@Override
	public Rectangle2D getRectangle2D() {
		LineView line1 = this.lineViews.get(0);
		double minX = line1.getMinX(),minY = line1.getMinY(),maxX = line1.getMaxX(),maxY = line1.getMaxY(); 
		for(int i=0;i<this.lineViews.size();i++){
			LineView line = this.lineViews.get(i);
			if(minX > line.getMinX() || minX == -1){
				minX = line.getMinX();
			}
			if(minY > line.getMinY() || minX == -1){
				minY = line.getMinY();
			}
			if(maxX < line.getMaxX() || minX == -1){
				maxX = line.getMaxX();
			}
			if(maxY < line.getMaxY() || minX == -1){
				maxY = line.getMaxY();
			}
		}
		
		return new Rectangle2D.Double(minX,minY,maxX-minX,maxY-minY);
	}

	@Override
	public void drawLinkedShape(Graphics2D g, Image image) {
		if(this.isSelected){
			this.draw(g);
			return;
		};
		for(int i=0;i<this.lineViews.size();i++){
			this.lineViews.get(i).drawLinkedShape(g, image);
		}
	}
	@Override
	public Element createXMLElement(Document document) {
		Element element = document.createElement("view");
		element.setAttribute("type",URICreator.LINE_SEGMENT);
		for(int i=0;i<this.lineViews.size();i++){
			element.appendChild(this.lineViews.get(i).createXMLElement(document));
		}
		return element;
	}

	public static LineSegView restore(Element element, int index) {
		String lineDirectionType = element.getAttribute("LineDirection");
		LineDirection lineDirection;
		if (lineDirectionType.equals("Horizontal")) {
			lineDirection = LineDirection.HORIZONTAL;
		} else if (lineDirectionType.equals("Vertical")) {
			lineDirection = LineDirection.VERTICAL;
		} else {
			GSLog.getInstance().error(String.format("Illegal XML line specification for element %s: %s",element));
			return null;
		}
		LineSegView view = new LineSegView(lineDirection, index);
		NodeList nodes = element.getChildNodes();

		for(int i=0;i<nodes.getLength();i++){
			if(nodes.item(i).getNodeType() == Node.ELEMENT_NODE){
				Element elem = (Element)nodes.item(i);
				String tagname = elem.getNodeName();
				if(tagname.equals("view")){
					LineView line = LineView.restore(elem);
					view.addLineView(line);
				}
			}
		}
		return view;
	}
	@Override
	public Point getCenterPoint() {
		return new Point((int)this.getRectangle2D().getCenterX(),
							(int)this.getRectangle2D().getCenterY());
	}
	@Override
	public String getTypeStringForDisplay() {
		return "LineSegment";
	}
	@Override
	public int getIndex() {
		return this.index;
	}
	
	public void setIndex(int i) {
		this.index = i;		
	}

	private void createIndexView(int index) {
		Point2D cornerPoint;
		Point2D ansPoint;
		if (lineViews.size() == 0) return;
	    ansPoint = lineViews.get(0).getStartPoint();
		if (this.lineDirection == LineDirection.HORIZONTAL) {
			cornerPoint = new Point(this.getMinX(),this.getMinY());
		} else {
			cornerPoint = new Point(this.getMaxX()-5,this.getMinY());
		}
		
		for (LineView lv : lineViews) {
			Point2D start = lv.getStartPoint();
			Point2D end = lv.getEndPoint();
			if (cornerPoint.distance(start) < cornerPoint.distance(ansPoint)) ansPoint = start;
			if (cornerPoint.distance(end) < cornerPoint.distance(end)) ansPoint = end;
		}
		this.indexView = new IndexView(index, (int)ansPoint.getX(), (int)ansPoint.getY());
	}
	private int getMinY() {
		int minY = (int) this.lineViews.get(0).getMinY();
		for (int i = 0; i < this.lineViews.size(); i++) {
			if (minY > (int)this.lineViews.get(i).getMinY()) {
				minY = (int)this.lineViews.get(i).getMinY();
			}
		}
		return minY;
	}
	private int getMinX() {
		int minX = (int) this.lineViews.get(0).getMinX();
		for (int i = 0; i < this.lineViews.size(); i++) {
			if (minX > (int)this.lineViews.get(i).getMinX()) {
				minX = (int)this.lineViews.get(i).getMinX();
			}
		}
		return minX;
	}

	private int getMaxX() {
		int maxX= (int) this.lineViews.get(0).getMaxX();
		for (int i = 0; i < this.lineViews.size(); i++) {
			if (maxX < (int)this.lineViews.get(i).getMaxX()) {
				maxX = (int)this.lineViews.get(i).getMaxX();
			}
		}
		return maxX;
	}
	
	private class IndexView {
		private int index;
		private int x;
		private int y;
		private Rectangle2D rectangle;
		
		public IndexView(int index, int x, int y) {
			this.index = index;
			this.x = x;
			this.y = y;
		}

		protected void drawShape(Graphics2D g) {
			FontMetrics fm = g.getFontMetrics();
			int h = fm.getHeight();
			int ast = fm.getAscent();
			int w = fm.stringWidth(this.index+"");
			int xx = x - w/2;
			int yy = y - h/2;
			rectangle = new Rectangle2D.Double(xx, yy, w + 10, h);
			Color c  = g.getColor();
			g.setColor(new Color(204,255,255));
			g.fill(rectangle);
			g.setColor(Color.BLACK);
			g.draw(rectangle);
			g.drawString(index+"", xx + 5, yy + ast);
			g.setColor(c);
		}

		public IndexView deepCopy() {
			return new IndexView(this.index, this.x, this.y);
		}
		
//		protected Rectangle2D getRectangle2D() {
//			return rectangle;
//		}
		
//		protected int getIndex() {
//			return index;
//		}
	}

	@Override
	public void drawLinkIcon(Graphics2D g, Image image) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void drawTemporaryIcon(Graphics2D g) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void drawTemporaryShape(Graphics2D g) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void drawSelectedIcon(Graphics2D g) {
		ImageIcon closeUp = new ImageIcon(GSConstants.ICON_PATH + "region_close_up.png");
		Image closeUpImage = closeUp.getImage();
		Rectangle closeUpImageRectangle = this.closeUpImageRectangle();
		int w2 = (int)closeUpImageRectangle.getWidth();
		int h2 = (int)closeUpImageRectangle.getHeight();
		int x2 = (int)closeUpImageRectangle.getX();
		int y2 = (int)closeUpImageRectangle.getY();
		g.drawImage(closeUpImage, x2, y2, w2, h2, null);		
	}
	
	@Override
	protected Rectangle closeUpImageRectangle() {
		Rectangle rect = this.getRectangle();
		ImageIcon closeUp = new ImageIcon(GSConstants.ICON_PATH + "region_close_up.png");
		Image closeUpImage = closeUp.getImage();
		int w = (int)(closeUpImage.getWidth(null) / 4.5);
		int h = (int)(closeUpImage.getHeight(null) / 4.5);
		int x = (int)(rect.getX()) - (int)(w * (2/3.0));
		int y = (int)(rect.getY()) + (int)(rect.getHeight() - (h * (1/3.0)));
		return new Rectangle(x, y, w, h);
	}


	public ExLine2D getLine2D(int index) {
		return this.lineViews.get(index).getLine();
	}


	@Override
	public void drawInBasketShape(Graphics2D g) {
		// TODO Auto-generated method stub
		
	}


	@Override
	public void drawRWShape(Graphics2D g) {
		// TODO Auto-generated method stub
		
	}


	public LineSegView deepCopy() {
		LineSegView copy = new LineSegView(new ArrayList<ExLine2D>());
		copy.LineSegmentDefaultColor = this.LineSegmentDefaultColor;
		copy.lineViews = new ArrayList();
		for (int i=0;i<this.lineViews.size();i++) {
			copy.lineViews.add((this.lineViews.get(i)).deepCopy());
		}
		copy.index = this.index;
		copy.indexView = this.indexView.deepCopy();
		copy.lineDirection = this.lineDirection;
		copy.lineSegViewSelectionColor = this.lineSegViewSelectionColor;
		copy.vertexEditMode = this.vertexEditMode;
        return copy;
	}


	
}