package com.smartgwt.sample.client;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.HashMap;

import com.google.gwt.regexp.shared.RegExp;
import com.google.gwt.user.client.Timer;
import com.smartgwt.client.types.TitleAutoFitRotationMode;
import com.smartgwt.client.util.SC;
import com.smartgwt.client.widgets.drawing.DrawItem;
import com.smartgwt.client.widgets.drawing.DrawLabel;
import com.smartgwt.client.widgets.drawing.DrawPane;
import com.smartgwt.client.widgets.drawing.DrawPolygon;
import com.smartgwt.client.widgets.drawing.DrawRect;
import com.smartgwt.client.widgets.drawing.Point;
import com.smartgwt.client.widgets.drawing.events.ClickEvent;
import com.smartgwt.client.widgets.drawing.events.ClickHandler;
import com.smartgwt.client.widgets.events.MouseWheelEvent;
import com.smartgwt.client.widgets.events.MouseWheelHandler;

public class BEERChipSTAPOC extends DrawPane {
	Map<String, Object> blockDefs = new HashMap<String, Object>();
//	ItemClickHandler itemClickHandler;
	Double zoom = .04;
	double xMax = 0D;
	double yMax = 0D;
	protected Integer[] chipBoundary;
	private boolean autoFit;

	public BEERChipSTAPOC() {

		this.setEdgeSize(5);

		this.setCanDragScroll(true);
		this.addMouseWheelHandler(new MouseWheelHandler() {

			@Override
			public void onMouseWheel(MouseWheelEvent event) {
				zoom(event.getWheelDelta() < 0);
			}
		});

	}

	public void zoom(boolean zoomIn) {
		autoFit = false;
		if (!zoomIn) {
			zoom(getZoomLevelAsDouble() * .95);
		} else {
			zoom(getZoomLevelAsDouble() * 1.05);
		}
	}

	public void zoomToBestFit() {
		autoFit = true;
		int vlayoutWidth = getWidth();
		double zoom1 = (double) vlayoutWidth / xMax;
		double zoom2 = (double) this.getHeight() / yMax;

		this.setZoomLevel(Math.min(zoom1, zoom2));
	}

	public enum TRANSFORM {
		R90, R180, R270, R0, MX, R90MY, MY, R90MX
	};

	public Point transform(Point point, String transformation) {
		double sx = point.getXAsDouble();
		double sy = point.getYAsDouble();
		double nx = 0, ny = 0;
		switch (TRANSFORM.valueOf(transformation)) {
		case R90:
			ny = sx;
			nx = sy * -1;
			break;
		case R180:
			nx = sx * -1;
			ny = sy * -1;
			break;
		case R270:
			nx = sy;
			ny = sx * -1;
			break;
		case R0:
			nx = sx;
			ny = sy;
			break;
		case MX:
			nx = sx * -1;
			ny = sy;
			break;
		case R90MY:
			nx = sy * -1;
			ny = sx * -1;
			break;
		case MY:
			nx = sx;
			ny = sy * -1;
			break;
		case R90MX:
			nx = sy;
			ny = sx;
			break;

		}
		return new Point(nx, ny);

	}

	private DrawItem getItem(String string, final String instanceID, Double x, Double y, String orientation) {
		DrawItem item = null;
		x = x * zoom;
		y = y * zoom;
		if (blockDefs.get(string) != null) {
			if (blockDefs.get(string) instanceof List && ((List)blockDefs.get(string)).size()>4) {
				DrawPolygon poly = new DrawPolygon();
				poly.setID(instanceID);
				poly.setLineWidth(1);
				poly.setTitleAutoFit(true);
				poly.setTitleAutoFitRotationMode(TitleAutoFitRotationMode.NEVER);
				
				Point[] points = new Point[((List) blockDefs.get(string)).size() ];
				int index = 0;
				for ( List<Number> coords : (List<List<Number>>)blockDefs.get(string))  {
					 points[index] = new Point(coords.get(0).intValue(), coords.get(1).intValue());
					index++;
				}
				
				Point[] newPoints = new Point[points.length];
				Point[] transPoints = new Point[points.length];

				double transx = 0;
				double transy = 0;
				for (int i = 0; i < newPoints.length; i++) {
					Point point = points[i];
					newPoints[i] = transform(new Point(point.getX() * zoom, point.getY() * zoom), orientation);
					transx = Math.min(transx, newPoints[i].getXAsDouble());
					transy = Math.min(transy, newPoints[i].getYAsDouble());
				}
				if (transx < 0) {
					transx = transx * -1;
				} else {
					transx = 0;
				}
				if (transy < 0) {
					transy = transy * -1;
				} else {
					transy = 0;
				}
				double tempXMax = 0;
				double tempYMax = 0;
				for (int i = 0; i < newPoints.length; i++) {
					transPoints[i] = new Point(newPoints[i].getX() + transx, newPoints[i].getY() + transy);
					tempXMax = Math.max(transPoints[i].getX(), tempXMax);
					tempYMax = Math.max(transPoints[i].getY(), tempYMax);
				}
				Long mx = x.intValue() - Math.round(transx);
				Long my = y.intValue() - Math.round(transy);

				tempXMax += mx;
				tempYMax += my;

				xMax = Math.max(tempXMax, xMax);
				yMax = Math.max(tempYMax, yMax);
				poly.setPoints(transPoints);
				poly.setDrawPane(this);
				poly.moveTo(Integer.parseInt(mx.toString()), Integer.parseInt(my.toString()));

				item = poly;
			} else {
				DrawRect rect = new DrawRect();
				rect.setID(instanceID);
				rect.setTitleAutoFit(true);
				rect.setTitleAutoFitRotationMode(TitleAutoFitRotationMode.NEVER);
				rect.setTitleAutoFitMargin(0);
				Object test = blockDefs.get(string);
				List<Number> coordList = (List<Number>)blockDefs.get(string);
				Number[] coords = coordList.toArray(new Number[coordList.size()]);
				for (int i = 0; i < coords.length; i++) {
					coords[i] = ((Number) (coords[i].intValue() * zoom)).intValue();
				}
				Double x1 = Double.parseDouble(coords[0].toString());
				Double y1 = Double.parseDouble(coords[1].toString());
				Double x2 = Double.parseDouble(coords[2].toString());
				Double y2 = Double.parseDouble(coords[3].toString());
				Point p1 = transform(new Point(x1, y1), orientation);
				Point p2 = transform(new Point(x2, y2), orientation);
				Long lx1 = Math.round(p1.getXAsDouble());
				Long ly1 = Math.round(p1.getYAsDouble());
				Long lx2 = Math.round(p2.getXAsDouble());
				Long ly2 = Math.round(p2.getYAsDouble());

				Integer ix1 = Integer.parseInt(lx1.toString());
				Integer iy1 = Integer.parseInt(ly1.toString());
				Integer ix2 = Integer.parseInt(lx2.toString());
				Integer iy2 = Integer.parseInt(ly2.toString());

				Integer transx = 0;
				Integer transy = 0;

				if (ix1 < 0) {
					transx = ix1 * -1;
				}
				if (ix2 < ix1 && ix2 < 0) {
					transx = ix2 * -1;
				}
				if (iy1 < 0) {
					transy = iy1 * -1;
				}
				if (iy2 < iy1 && iy2 < 0) {
					transy = iy2 * -1;
				}
				ix1 += transx;
				ix2 += transx;
				iy1 += transy;
				iy2 += transy;

				Integer iy3 = Math.max(iy1, iy2);
				Integer ix3 = Math.max(ix1, ix2);
				rect.setRect(0, 0, ix3, iy3);

				double tempXMax = ix3 + x.intValue() - transx;
				double tempYMax = iy3 + y.intValue() - transy;

				xMax = Math.max(tempXMax, xMax);
				yMax = Math.max(tempYMax, yMax);

				rect.setLineWidth(1);
				rect.setDrawPane(this);
				rect.moveTo(x.intValue() - transx, y.intValue() - transy);
				item = rect;
			}
		} else {
			// item = null;
		}
		if (item != null) {
			item.setLineColor("black");
			item.setFillColor("white");
			final DrawItem thisItem = item;
			item.addClickHandler(new ClickHandler() {

				@Override
				public void onClick(ClickEvent event) {
//					itemClickHandler.onItemClick(thisItem);
				}
			});

			item.setCanHover(true);
			String instanceWithSlash = instanceID.replace("FSLASH", "/");
//			item.setPrompt(prompt);
//			item.setPrompt(heatmap.formatBlockInstance(instanceWithSlash));
			RegExp regexp = RegExp.compile(".*\\/");
			item.setTitle(regexp.replace(instanceWithSlash,""));
						
		}

		return item;
	}


	public void drawFloorplan(Map<String, Object> blockDefs, ArrayList<Map> blockInstances) {
		drawOrigFloorplan(blockDefs, blockInstances);
	}

	public void drawOrigFloorplan(Map<String, Object> blockDefs, ArrayList<Map> blockInstances) {

		this.blockDefs = blockDefs;
		
		final List<DrawItem> instances = new ArrayList<DrawItem>();

		for (int i = 0; i < blockInstances.size(); i++) {
			Map instance = (Map) blockInstances.get(i);
			if (!"top_level".equals(instance.get("Block_Name"))) {
				Double x = Double.parseDouble(instance.get("Instance_X").toString());
				Double y = Double.parseDouble(instance.get("Instance_Y").toString());
				String instanceName = ((String) instance.get("Instance_Name")).replaceAll("/", "FSLASH"); // IDs don't allow for /'s
				String orientation = (String) instance.get("Instance_Orientation");
				instances.add(getItem((String) instance.get("Block_Name"), instanceName, x, y, orientation));
			} else {
				DrawRect rect = new DrawRect();
				rect.setID("boundary");
				Integer[] coords = (Integer[]) blockDefs.get(instance.get("Block_Name"));
				for (int i2 = 0; i2 < coords.length; i2++) {
					coords[i2] = ((Number) (coords[i2] * zoom)).intValue();
				}
				chipBoundary = new Integer[] { coords[2], coords[3] };
				rect.setRect(0, 0, coords[2], coords[3]);
				rect.setLineWidth(1);
				rect.setDrawPane(this);
				rect.moveTo(0, 0);
			}
		}

		Timer timer = new Timer() {
			@Override
			public void run() {
				zoomToBestFit();
			}
		};

		timer.schedule(200);
	}

	public DrawItem getItemByID(String id) {
		for (DrawItem item : getDrawItems()) {
			if (id.equals(item.getID())) {
				return item;
			}
		}
		return null;
	}

	public void mirrorY() {
		if (chipBoundary == null) {
			return;
		}
		Integer maxY = chipBoundary[1] + 10;

		for (DrawItem item : getDrawItems()) {
			if (item instanceof DrawPolygon) {
				Point[] points = ((DrawPolygon) item).getPoints();
				// int[] bbox = item.getBoundingBox();

				Point[] flippedPoints = new Point[points.length];
				for (int i = 0; i < points.length; i++) {
					Point point = points[i];
					Integer flippedY = maxY - point.getY();
					flippedPoints[i] = new Point(point.getX(), flippedY);
				}
				((DrawPolygon) item).setPoints(flippedPoints);

			} else if (item instanceof DrawRect) {
				((DrawRect) item).setTop(maxY - ((DrawRect) item).getTop() - ((DrawRect) item).getHeight());
			}
		}

	}

	public boolean isAutoFit() {
		return autoFit;
	}
}
