Function.prototype.bind = function(obj) {
	var _this = this;

	return function() {
		return _this.apply(obj, arguments);
	};
};

function Vector2D(x, y) {
	this.x = x;
	this.y = y;
}

Vector2D.prototype = {
	add: function(p) {
		return new Vector2D(this.x + p.x, this.y + p.y);
	},

	sub: function(p) {
		return new Vector2D(this.x - p.x, this.y - p.y);
	}
};

L = new Object();

L.Event = new Object();

L.Event.getMousePosition = function(e) {
	if (e.pageX) {
		return new Vector2D(e.pageX, e.pageY);
	} else if (e.clientX) {
		return new Vector2D(document.body.scrollLeft + document.documentElement.scrollLeft + e.clientX,
		                    document.body.scrollTop + document.documentElement.scrollTop + e.clientY);
	} else {
		return new Vector2D(0, 0);
	}
};
L.Event.stop = function(e) {
	if (e.cancelBubble) {
		e.cancelBubble();
	} else if (e.stopPropagation) {
		e.stopPropagation();
	}
};

L.Element = new Object();

L.Element.getPosition = function(el) {
	var x = 0, y = 0, node;
	for (node = el; node.offsetParent; node = node.offsetParent) {
		x += (typeof node.offsetLeft != "undefined") ? node.offsetLeft : 0;
		y += (typeof node.offsetTop != "undefined") ? node.offsetTop : 0;
	}
	return new Vector2D(x, y);
};

L.Element.getDimensions = function(el) {
	return new Vector2D(el.offsetWidth, el.offsetHeight);
};

function Canvas(elements) {
	this.el = new Object();
	
	for (i in elements) {
		this.el[i] = document.getElementById(elements[i]);
	}
	this.el.canvas = this.el.imageArea;

	this.el.canvas.onmouseout = this.endAction.bind(this);
	
	var s = L.Element.getDimensions(this.el.panelBg);
	this.aspect = s.x / s.y;
	
	this.minPos = L.Element.getPosition(this.el.minSize).sub(L.Element.getPosition(this.el.canvas));
	this.minDim = L.Element.getDimensions(this.el.minSize);

	this.imgPos = L.Element.getPosition(this.el.panelBg).sub(L.Element.getPosition(this.el.canvas));
	this.origDim = this.imgDim = L.Element.getDimensions(this.el.panelBg);
	this.origPos = L.Element.getPosition(this.el.panelBg).sub(L.Element.getPosition(this.el.canvas));

	this.el.panel.style.margin = "0";
	this.el.panelBg.style.margin = "0";

	this.el.handleSE.onmousedown = this.startScaleSE.bind(this);
	this.el.handleNW.onmousedown = this.startScaleNW.bind(this);
	this.el.handleNE.onmousedown = this.startScaleNE.bind(this);
	this.el.handleSW.onmousedown = this.startScaleSW.bind(this);

	this.el.panel.onmousedown = this.startMove.bind(this);

	this.el.zoomIn.onclick = this.zoomIn.bind(this);
	this.el.zoomOut.onclick = this.zoomOut.bind(this);

	this.state = Canvas.NONE;

	this.updateElements();
	this.zoomBy(1.0 / 10.0);
	//this.zoomIn();
}

Canvas.prototype = {
	startScale: function(d, e) {
		var e = e || window.event;
		
		this.state = Canvas.SCALE;
		this.dir = d;

		this.initMousePos = L.Event.getMousePosition(e).sub(L.Element.getPosition(this.el.canvas));
		this.initPos = this.imgPos;
		this.initDim = this.imgDim;

		this.el.canvas.onmousemove = this.scaleMouseMove.bind(this);
		this.el.canvas.onmouseup = this.endAction.bind(this);
	},

	scaleMouseMove: function(e) {
		var e = e || window.event;
		
		var newPos = new Vector2D(0, 0);
		var newDim = new Vector2D(0, 0);
		
		var mousePos = L.Event.getMousePosition(e).sub(L.Element.getPosition(this.el.canvas));

		switch (this.dir) {
			case Canvas.SE:
				var t = mousePos.sub(this.imgPos);
				if (Math.abs(t.x) / Math.abs(t.y) < this.aspect) {
					// fix lower edge to cursor
					newPos.x = this.initPos.x;
					newPos.y = this.initPos.y;
					newDim.y = mousePos.y - newPos.y;
					newDim.x = newDim.y * this.aspect;
				} else {
					// fix right edge to cursor	
					newPos.x = this.initPos.x;
					newPos.y = this.initPos.y;
					newDim.x = mousePos.x - newPos.x;
					newDim.y = newDim.x / this.aspect;
				}
				break;
			case Canvas.NW:
				var t = this.imgPos.add(this.imgDim).sub(mousePos);
				if (Math.abs(t.x) / Math.abs(t.y) < this.aspect) {
					// fix top edge to cursor
					newPos.y = mousePos.y;
					newPos.x = this.initPos.x - (this.initPos.y - newPos.y) * this.aspect;
					newDim.x = this.initPos.x + this.initDim.x - newPos.x;
					newDim.y = this.initPos.y + this.initDim.y - newPos.y;
				} else {
					// fix left edge to cursor	
					newPos.x = mousePos.x;
					newPos.y = this.initPos.y - (this.initPos.x - newPos.x) / this.aspect;
					newDim.x = this.initPos.x + this.initDim.x - newPos.x;
					newDim.y = this.initPos.y + this.initDim.y - newPos.y;
				}
				break;
			case Canvas.NE:
				var t = mousePos.sub(new Vector2D(this.imgPos.x, this.imgPos.y + this.imgDim.y));
				if (Math.abs(t.x) / Math.abs(t.y) > this.aspect) {
					// fix right edge to cursor
					newPos.x = this.initPos.x;
					newDim.x = mousePos.x - newPos.x;
					newDim.y = newDim.x / this.aspect;
					newPos.y = this.initPos.y + this.initDim.y - newDim.y;
				} else {
					// fix top edge to cursor	
					newPos.x = this.initPos.x;
					newPos.y = mousePos.y;
					newDim.y = this.initPos.y + this.initDim.y - newPos.y;
					newDim.x = newDim.y * this.aspect;
				}
				break;
			case Canvas.SW:
				var t = new Vector2D(this.imgPos.x, this.imgPos.y + this.imgDim.y).sub(mousePos);
				if (Math.abs(t.x) / Math.abs(t.y) < this.aspect) {
					// fix left edge to cursor
					newPos.x = mousePos.x;
					newPos.y = this.initPos.y;
					newDim.x = this.initPos.x + this.initDim.x - newPos.x;
					newDim.y = newDim.x / this.aspect;
				} else {
					// fix bottom edge to cursor
					newPos.y = this.initPos.y;
					newDim.y = mousePos.y - newPos.y;
					newDim.x = newDim.y * this.aspect;
					newPos.x = this.initPos.x + this.initDim.x - newDim.x;
				}
				break;
		}

		newPos.x = Math.min(newPos.x, this.minPos.x);
		newPos.y = Math.min(newPos.y, this.minPos.y);
		
		if (newPos.y + newDim.y < this.minPos.y + this.minDim.y) {
			newDim.y = this.minPos.y + this.minDim.y - newPos.y;
			newDim.x = newDim.y * this.aspect;
		}

		if (newPos.x + newDim.x < this.minPos.x + this.minDim.x) {
			newDim.x = this.minPos.x + this.minDim.x - newPos.x;
			newDim.y = newDim.x / this.aspect;
		}

		this.imgPos = newPos;
		this.imgDim = newDim;

		this.updateElements();
		
		L.Event.stop(e);
		return false;
	},

	zoomBy: function(f) {
		var newDim = new Vector2D(0, 0);
		var newPos = new Vector2D(0, 0);

		newDim.y = this.imgDim.y * f;
		newDim.x = newDim.y * this.aspect;

		newPos.x = this.imgPos.x + (this.imgDim.x - newDim.x) / 2;
		newPos.y = this.imgPos.y + (this.imgDim.y - newDim.y) / 2;

		// first ensure the top left corner of the image is within legal limits

		newPos.x = Math.min(newPos.x, this.minPos.x);
		newPos.y = Math.min(newPos.y, this.minPos.y);
		
		if (newPos.y + newDim.y < this.minPos.y + this.minDim.y) {
			newDim.y = this.minPos.y + this.minDim.y - newPos.y;
			newDim.x = newDim.y * this.aspect;
		}

		if (newPos.x + newDim.x < this.minPos.x + this.minDim.x) {
			newDim.x = this.minPos.x + this.minDim.x - newPos.x;
			newDim.y = newDim.x / this.aspect;
		}

		this.imgPos = newPos;
		this.imgDim = newDim;

		this.updateElements();
	},

	startMove: function(e) {
		var e = e || window.event;

		if (e.target != this.el.panel && e.srcElement != this.el.panel) {
			return;
		}
		
		this.initPos = this.imgPos;

		this.initMousePos = L.Event.getMousePosition(e);
		
		this.state = Canvas.MOVE;

		this.el.canvas.onmousemove = this.moveMouseMove.bind(this);
		this.el.canvas.onmouseup = this.endAction.bind(this);
	},

	moveMouseMove: function(e) {
		var e = e || window.event;

		var newPos = this.initPos.add(L.Event.getMousePosition(e).sub(this.initMousePos));
		if (newPos.x > this.minPos.x) {
			newPos.x = this.minPos.x;
		} else if (newPos.x + this.imgDim.x < this.minPos.x + this.minDim.x) {
			newPos.x = this.minPos.x + this.minDim.x - this.imgDim.x;
		}

		if (newPos.y > this.minPos.y) {
			newPos.y = this.minPos.y;
		} else if (newPos.y + this.imgDim.y < this.minPos.y + this.minDim.y) {
			newPos.y = this.minPos.y + this.minDim.y - this.imgDim.y;
		}

		this.imgPos = newPos;
		
		this.updateElements();

		L.Event.stop(e);
		return false;
	},

	endAction: function(e) {
		var e = e || window.event;
		
		if (e.type == "mouseout") {
			// lots of mouseout events are caused by the mouse going over elements inside the canvas...
			// we should only stop the action if the mouse actually exited the entire canvas.
			var mousePos = L.Event.getMousePosition(e);
			var cPos = L.Element.getPosition(this.el.canvas);
			var cDim = L.Element.getDimensions(this.el.canvas);

			if (mousePos.x > cPos.x + 1 && mousePos.x < cPos.x + cDim.x - 1 && mousePos.y > cPos.y + 1 && mousePos.y < cPos.y + cDim.y - 1) {
				return;
			}
		}

		this.el.canvas.onmousemove = null;
		this.el.canvas.onmouseup = null;
		this.state = Canvas.NONE;
	},

	updateElements: function() {
		this.el.panel.style.left = this.imgPos.x + "px";
		this.el.panel.style.top = this.imgPos.y + "px";
		this.el.panel.style.width = this.imgDim.x + "px";
		this.el.panel.style.height = this.imgDim.y + "px";
		
		this.el.panelBg.style.left = (this.origPos.x - this.imgPos.x) * -1 + "px";
		this.el.panelBg.style.top = (this.origPos.y - this.imgPos.y) * -1 + "px";
		this.el.panelBg.style.width = this.imgDim.x + "px";
		this.el.panelBg.style.height = this.imgDim.y + "px";

/*
		this.el.panelBg.style.left = this.el.panel.style.left = this.imgPos.x + "px";
		this.el.panelBg.style.top = this.el.panel.style.top = this.imgPos.y + "px";
		this.el.panelBg.style.width = this.el.panel.style.width = this.imgDim.x + "px";
		this.el.panelBg.style.height = this.el.panel.style.height = this.imgDim.y + "px";
*/		
		var hfX = document.getElementById("ucDesign_hfImageX");
		hfX.setAttribute('value', this.origPos.x - this.imgPos.x);
		var hfY = document.getElementById("ucDesign_hfImageY");
		hfY.setAttribute('value', this.origPos.y - this.imgPos.y);
		var hfScale = document.getElementById("ucDesign_hfImageScale")
		hfScale.setAttribute('value', this.imgDim.x / this.origDim.x);
		
		// DEBUG
		//document.getElementById("debug").firstChild.nodeValue = "X: " + this.imgPos.x + " (" + (this.origPos.x - this.imgPos.x) + ") Y: " + this.imgPos.y + " (" + (this.origPos.y - this.imgPos.y) + ") Aspect ratio: " + (this.imgDim.x / this.imgDim.y) + " Scale factor: " + (this.imgDim.x / this.origDim.x) + " == " + (this.imgDim.y / this.origDim.y);
	},

	startScaleSE: function(e) { this.startScale(Canvas.SE, e); },
	startScaleNW: function(e) { this.startScale(Canvas.NW, e); },
	startScaleNE: function(e) { this.startScale(Canvas.NE, e); },
	startScaleSW: function(e) { this.startScale(Canvas.SW, e); },

	zoomIn: function() { this.zoomBy(1.05); },
	zoomOut: function() { this.zoomBy(1.0 / 1.05); }
};

Canvas.NONE = 0;
Canvas.MOVE = 1;
Canvas.SCALE = 2;

Canvas.NW = 1;
Canvas.NE = 2;
Canvas.SE = 3;
Canvas.SW = 4;

function openPic(linkid,divid)
{
    var el = document.getElementById(linkid);
    var coords = getPageCoords(el);
    var d = document.getElementById(divid);
    d.style.top = coords.y + 'px';
    d.style.left = coords.x + 'px';   
    alert(coords.x + ' ' + coords.y) 
}

function getPageCoords (element) 
{
    var coords = { x: 0, y: 0 };
    var p = null;
    do 
    {
        coords.x += element.offsetLeft;
        coords.y += element.offsetTop;
        p = element.offsetParent;
        element = element.offsetParent;
    }while(p.tagName.toLowerCase() != 'div')       
    return coords; 
}