Ext.define("Ext.ux.svg.DrawRoom", {
	extend: "Ext.container.Container",
	alias: ["widget.drawroom"],

	config: {
		polygonEl: null,
		points: null,
		movePoints: null,
		mode: null,
		svg: null,
		mouseDown: false,
		mouseDownX: 0,
		mouseDownY: 0,
		focuced: null,
		mapPath: null,
		zoomFactor: 1,
		mapSize: null,
		allowDraw: true
	},

	modes: {
		NORMAL: 0,
		DRAW: 1,
		RESIZE: 2,
		SELECT: 3
	},

	layout: "auto",
	style: {
		"overflow-y": "auto"
	},

	initComponent: function() {

		var i_self = this;
		i_self.callParent(arguments);

		i_self.updatePoints = Ext.Function.createBuffered(i_self.updatePoints, 500);

		i_self.enableBubble("pointchange");
		i_self.enableBubble("drawcomplete");
		i_self.enableBubble("polygonmove");

		i_self.on({
			afterrender: {
				fn: function(i_container) {
					i_container.add(i_self.createSvg());
				}
			}
		});
	},

	updateMap: function(s_path, points) {

		var i_self = this;
		var mapLoader = new Image();

		var i_svg = i_self.getSvg();
		var s_background = i_svg.getEl().dom.style.backgroundImage;

		s_background = s_background.slice(4, -1).replace(/["|']/g, "");

		if (s_path) {
			if (s_background !== s_path) {
				i_self.setLoading(true);
			}

			mapLoader.onload = function() {
				i_self.setLoading(false);
				var zoomFactor = (i_self.getWidth() - Ext._scrollbarSize.width) / mapLoader.width;
				var i_svg = i_self.getSvg();
				i_svg.getEl().dom.style.backgroundImage = 'url(' + s_path + ')';
				i_svg.getEl().dom.style.backgroundSize = 'contain';
				i_svg.getEl().dom.style.backgroundRepeat = 'no-repeat';

				i_self.setZoomFactor(zoomFactor);

				i_self.setMapSize({
					width: mapLoader.width,
					height: mapLoader.height
				});

				i_svg.setHeight(zoomFactor * mapLoader.height);

				i_self.deletePolygon();

				if (points && points.length) {
					i_self.setValue(points);
					i_self.createPolygon();
					i_self.draw();
				}
			};

			mapLoader.src = s_path;
		}
		else {
			i_self.setLoading(false);

			var i_svg = i_self.getSvg();
			i_svg.getEl().dom.style.backgroundImage = 'none';

			i_self.setMapSize({
				width: i_self.getWidth(),
				height: 0
			});

			i_svg.setHeight(0);

			i_self.deletePolygon();
		}
	},

	updatePoints: function(newValue) {

		var i_self = this;
		i_self.fireEvent("pointchange", i_self, i_self.getValue());
	},

	setPoints: function(newValue) {
		this.points = newValue;
		this.updatePoints(newValue);
	},

	getPointIndex: function(x, y, points) {
		if (arguments.length == 2) {
			points = this.getPoints();
		}
		if (!points) {
			return;
		}
		for (var i = 0; i < points.length; i += 2) {
			var x2 = points[i];
			var y2 = points[i + 1];

			if (Math.abs(x - x2) < 5 && Math.abs(y - y2) < 5) {
				return i;
			}
		}

		return -1;
	},

	createSvg: function() {

		var i_self = this;

		var i_component = Ext.widget("component", {
			height: 100,
			autoEl: {
				tag: 'svg',
				style: 'width: 100%; border: none;'
			},
			listeners: {
				afterrender: {
					fn: function(i_svg) {

						i_self.setSvg(i_svg);
						i_self.setMode(i_self.modes.NORMAL);

						var s_path = i_self.getMapPath();

						if (s_path) {
							var a_points = i_self.getPoints();
							i_self.updateMap(s_path, a_points);
						}

						if (i_self.getAllowDraw()) {
							i_self.attachListeners(i_svg.getEl().dom);
						}
					}
				},
				resize: {
					fn: function(i_svg) {

						// getValue (Points) BEFORE updating zoomFactor:
						var a_points = i_self.getValue();
						var size = i_self.getMapSize();
						if (size) {
							var zoomFactor = (i_self.getWidth() - Ext._scrollbarSize.width) / size.width;
							i_self.setZoomFactor(zoomFactor);
							i_svg.setHeight(zoomFactor * size.height);
						}
						if (a_points) {
							i_self.setValue(a_points);
							i_self.draw();
						}
					}
				}
			}
		});

		return i_component;
	},

	setValue: function(points) {
		var i_self = this;
		var zoomFactor = i_self.getZoomFactor();
		i_self.setPoints(points.map(function(point) {
			return point * zoomFactor;
		}));
	},

	getValue: function() {
		var points = this.getPoints();
		var zoomFactor = this.getZoomFactor();
		return points ? points.map(function(point) {
			return point / zoomFactor;
		}) : null;
	},

	initDraw: function(x, y) {
		var i_self = this;
		var modes = i_self.modes;
		i_self.setMode(modes.DRAW);
		i_self.createPolygon();
		i_self.setPoints([]);
		i_self.addCoord(x, y);
		i_self.draw();
	},
	addCoord: function(x, y) {
		var i_self = this;
		var points = i_self.getPoints();
		points.push(x, y);
		i_self.setPoints(points);
	},
	draw: function(x, y) {
		var i_self = this;
		var points = i_self.getPoints();
		if (arguments.length == 2) {
			points = points.concat(x, y);
		}
		var polyEl = i_self.getPolygonEl();
		if (polyEl) {
			polyEl.setAttribute('points', points.join(' '));
		}
	},
	createPolygon: function() {
		var svg = this.getSvg().getEl().dom;
		var poly = document.createElementNS("http://www.w3.org/2000/svg", "polygon");
		poly.style.fill = 'rgba(112,181,93,0.2)';
		poly.style.stroke = '#70b55d';
		poly.style.strokeDasharray = '3, 5';
		poly.style.strokeLinejoin = 'round';
		poly.style.strokeWidth = '3px';
		svg.appendChild(poly);
		this.setPolygonEl(poly);
	},
	deletePolygon: function() {
		var polyEl = this.getPolygonEl();
		if (polyEl && polyEl.parentNode) {
			polyEl.parentNode.removeChild(polyEl);
		}
		this.setPolygonEl(null);
		this.setPoints(null);
		this.setMovePoints(null);
	},
	selectPolygon: function() {
		var i_self = this;
		var modes = i_self.modes;
		i_self.setMode(modes.SELECT);
		var poly = this.getPolygonEl();
		poly.style.fill = 'rgba(181,112,93,0.2)';
		poly.style.stroke = '#b5705d';
		poly.style.strokeDasharray = '3, 5';
		poly.style.strokeLinejoin = 'round';
		poly.style.strokeWidth = '3px';
	},
	deselectPolygon: function() {
		var i_self = this;
		var modes = i_self.modes;
		i_self.setMode(modes.SELECT);
		var poly = this.getPolygonEl();
		poly.style.fill = 'rgba(112,181,93,0.2)';
		poly.style.stroke = '#70b55d';
		poly.style.strokeDasharray = '3, 5';
		poly.style.strokeLinejoin = 'round';
		poly.style.strokeWidth = '3px';
	},
	movePolygon: function(x, y) {
		var polyEl = this.getPolygonEl();
		var points = this.getPoints().map(function(val, key) {
			if (key & 1) {
				// y
				return val + y;
			}
			else {
				// x
				return val + x;
			}
		});
		this.setMovePoints(points);
		polyEl.setAttribute('points', points.join(' '));
	},

	addHandle: function(idx) {

		var i_self = this;
		var points = i_self.getPoints();
		var polyEl = i_self.getPolygonEl();
		var xy = points.slice(idx);
		var svg = this.getSvg().getEl().dom;

		var x = xy[0] - 15;
		var y = xy[1] - 15;

		var handle = document.createElement('div');
		handle.style.backgroundColor = 'rgba(0, 0, 0, 0.6)';
		handle.style.border = '1px solid rgba(255, 255, 255, 0.8)';
		handle.style.borderRadius = '100px';
		handle.style.position = 'absolute';
		handle.style.left = x + 'px';
		handle.style.top = y + 'px';
		handle.style.width = 30 + 'px';
		handle.style.height = 30 + 'px';

		var down = false;
		var startX;
		var startY;

		handle.addEventListener('mousedown', function(evt) {
			startX = evt.pageX - svg.getBoundingClientRect().left;
			startY = evt.pageY - svg.getBoundingClientRect().top;
			down = true;
		});
		handle.addEventListener('mousemove', function(evt) {
			if (down) {
				var offsetX = evt.pageX - svg.getBoundingClientRect().left - startX;
				var offsetY = evt.pageY - svg.getBoundingClientRect().top - startY;
				points.splice(idx, 2, offsetX + xy[0], offsetY + xy[1]);
				i_self.setPoints(points);
				i_self.draw();
				handle.style.left = (offsetX + x) + 'px';
				handle.style.top = (offsetY + y) + 'px';
			}
		});
		handle.addEventListener('mouseup', function(evt) {
			down = false;
			i_self.fireEvent("polygonmove", i_self, i_self.getValue());
		});

		handle.addEventListener('mouseout', function() {
			if (!down && handle.parentNode) {
				handle.parentNode.removeChild(handle);
			}
		});
		svg.parentNode.appendChild(handle);
	},

	attachListeners: function(el) {

		var i_self = this;

		var svg = i_self.getSvg().getEl().dom;
		var modes = i_self.modes;

		el.addEventListener('mouseover', function() {
			i_self.setFocuced(true);
		});
		el.addEventListener('mousemove', function() {
			i_self.setFocuced(true);
		});
		el.addEventListener('mouseout', function() {
			i_self.setFocuced(false);
		});

		el.addEventListener('mousedown', function(evt) {
			var x = evt.pageX - svg.getBoundingClientRect().left;
			var y = evt.pageY - svg.getBoundingClientRect().top;

			i_self.setMouseDown(true);
			i_self.setMouseDownX(x);
			i_self.setMouseDownY(y);

			switch (i_self.getMode()) {
				case modes.NORMAL:
					if (event.which != 1) {
						// Left click only!
						return;
					}
					if (!i_self.getPolygonEl()) {
						i_self.initDraw(x, y);
					}
					else if (evt.target.nodeName == 'polygon') {
						i_self.selectPolygon();
					}
					break;
				case modes.DRAW:
					if (event.which != 1) {
						// Left click only!
						return;
					}
					if (i_self.getPointIndex(x, y, i_self.getPoints().slice(0, 2)) > -1) {
						if (i_self.getPoints().length >= 6) {
							i_self.draw();
							i_self.setMode(modes.NORMAL);
						}
					}
					else {
						i_self.addCoord(x, y);
						i_self.draw();
					}
					break;
				case modes.SELECT:
					if (evt.target.nodeName != 'polygon') {
						i_self.deselectPolygon();
						i_self.setMode(modes.NORMAL);
					}
					else if (event.which == 3) {
						// Right click and on polygon
						i_self.deletePolygon();
						i_self.setMode(modes.NORMAL);
					}
			}
		});
		el.addEventListener('mouseup', function() {
			i_self.setMouseDown(false);
			switch (i_self.getMode()) {
				case modes.SELECT:
					var mp = i_self.getMovePoints();
					if (mp) {
						i_self.setPoints(mp);
						i_self.fireEvent("polygonmove", i_self, i_self.getValue());
					}
					i_self.draw();
					break;
			}
		});
		el.addEventListener('mousemove', function(evt) {
			var x = evt.pageX - svg.getBoundingClientRect().left;
			var y = evt.pageY - svg.getBoundingClientRect().top;

			switch (i_self.getMode()) {
				case modes.DRAW:
					i_self.draw(x, y);
					break;
				case modes.SELECT:
					if (i_self.getMouseDown()) {
						var startX = i_self.getMouseDownX();
						var startY = i_self.getMouseDownY();
						var offsetX = x - startX;
						var offsetY = y - startY;
						i_self.movePolygon(offsetX, offsetY);
					}
					else {
						var idx = i_self.getPointIndex(x, y);
						if (idx > -1) {
							i_self.addHandle(idx);
						}
					}
					break;
				case modes.NORMAL:
					var idx = i_self.getPointIndex(x, y);
					if (idx > -1) {
						i_self.addHandle(idx);
					}
					break;

			}
		});
		el.addEventListener('contextmenu', function(evt) {
			var x = evt.pageX - svg.getBoundingClientRect().left;
			var y = evt.pageY - svg.getBoundingClientRect().top;

			switch (i_self.getMode()) {
				case modes.DRAW:
					if (i_self.getPoints().length >= 6) {
						i_self.draw();
						i_self.setMode(modes.NORMAL);
						i_self.fireEvent("drawcomplete", i_self, i_self.getValue());
					}
					break;
			}
		});
		document.addEventListener('keydown', function(evt) {
			if (!i_self.getFocuced()) {
				return;
			}

			switch (i_self.getMode()) {
				case modes.SELECT:
					if (evt.key == 'Delete') {
						i_self.deletePolygon();
						i_self.setMode(modes.NORMAL);
						i_self.fireEvent("drawcomplete", i_self, i_self.getValue());
					}
					break;
				case modes.DRAW:
					if (evt.key == 'Delete') {
						i_self.deletePolygon();
						i_self.setMode(modes.NORMAL);
						i_self.fireEvent("drawcomplete", i_self, i_self.getValue());
					}
					if (evt.key == 'Enter') {
						if (i_self.getPoints().length >= 6) {
							i_self.draw();
							i_self.setMode(modes.NORMAL);
							i_self.fireEvent("drawcomplete", i_self, i_self.getValue());
						}
					}
					break;
			}
		});
	}
});
