/*
 * TemplateControl class start
 */
 
// Constructor. 
// FIXME: For templates with multiple apertures, one TemplateControl instance per aperture
// would work but setting the templateimg size for each one is redundant.
function TemplateControl(templateElementPrefix, elementPrefix, templateApertureRectF, borderApertureRectF, photoCropRectF, controlOption) {
	// Get elements
	this.isShown = false;
	this.elementPrefix = elementPrefix;
	this.templateElementPrefix = templateElementPrefix;

	this.setDOMObjects();
	
	var mglassW=16;//const
	var mglassH=16;//const
	
	move(this.templateimg, 0, 0);
	
	this.templateApertureRectF = templateApertureRectF;
	this.borderApertureRectF = borderApertureRectF;
	this.photoCropRectF = photoCropRectF;
	this.zoomFactor = 1.1; // each zoom level increases 10%
	this.changed = false;
	this.photoimg.galleryImg="false";
	
	// controlOption parameter controls any special ways we want to display an image
	// Options:
	// 1 - display the picture unscaled, but cropped to the aperture size.
	// 2 - tile the image if it is smaller than the aperture (not implemented).
	if (controlOption)
	{
		this.controlOption = controlOption;
	}
	else
	{
		this.controlOption = '0';
	}
	
	this.redeyeMU = null;
	this.redeyeMM = null;
	this.redeyeMD = null; 
	this.redeye = false;	// redeye mode
	var myself=this;
	
	function SetZoomPos(x,y)
	{
		var x3 = x-getLeft(myself.photodiv);
		var y3 = y-getTop(myself.photodiv);
		// x3,y3 - now relative to the image
		var s=getSize(myself.photoimg);
		var relX=x3/s.w;
		var relY=y3/s.h;
		if(redeyeZoom)redeyeZoom.MoveRedeyeZoomImg2(relX,relY);
	}
	
	this.SetMGlassPos=function(pos) //center pos
	{
		var s = getSize(myself.photoimg);
		var cr = myself.getCrop();
		var x = pos.l - cr.x;
		var y = pos.t - cr.y;
		
		var dx=getLeft(myself.clickzone);
		var dy=getTop(myself.clickzone);
		
		x = s.w*x+dx-mglassW;
		y = s.h*y+dy-mglassH;
		move(myself.mglass,x,y);
	}
	
	this.enableRedEyeEditing = function( isEnabled )
	{
		this.mglass.style.visibility = (isEnabled)?"visible":"hidden";
		this.mglass.style.cursor = 'pointer';
		this.clickzone.style.cursor = (isEnabled)?"default":'pointer';
		setLeft( this.mglass, getLeft(this.clickzone)-mglassW );
		setTop ( this.mglass, getTop(this.clickzone) -mglassH );

		if(!isEnabled)
		{
			if(!this.redeye)return;
			if(redeyeZoom)
				redeyeZoom.SetRedeyeZoomImg(null);
			this.clickzone.onmousedown = this.redeyeMD;	this.redeyeMD = null;
			this.redeye = false;
			return;
		}

		this.redeyeMD = this.clickzone.onmousedown;
		this.clickzone.onmousedown = null;

		//get image dimensions
		var sz = getSize(this.photoimg);
		var pos = getPosition(this.photodiv);
		
		this.redeye = true;
		var obj = this; // once inside event handlers "this" has different meaning
		if( redeyeZoom )
			redeyeZoom.SetRedeyeZoomImg( this.photoimg, this.SetMGlassPos );
		
		SetZoomPos(0,0);

		this.mglass.onmousedown = function(e)
		{
			obj.clickzone.style.cursor = 'move';
			var ev = (typeof(e) != 'undefined' ? e : event);
			var dragStartElementPoint = getPosition(obj.photodiv);
			var dragStartClickPoint = new Point(ev.clientX, ev.clientY);
			obj.redeyeMM = document.onmousemove;
			obj.redeyeMU = document.onmouseup;
			obj.mglass.style.cursor = 'move';

			var mgX = getLeft( obj.mglass );
			var mgY = getTop( obj.mglass );
			
			document.onmousemove = function(e2) 
			{
				if(!obj.redeye)return false; //should not be here
				var ev2 = (typeof(e2) != 'undefined' ? e2 : event);
				var dx = ev2.clientX - dragStartClickPoint.x;
				var dy = ev2.clientY - dragStartClickPoint.y;
				var l = mgX + dx;
				var t = mgY + dy;
				
				var x2 = getLeft(obj.clickzone);
				var y2 = getTop(obj.clickzone);
				var x3=l-x2+mglassW;
				var y3=t-y2+mglassH;
				// x3,y3 - are now relative to the clickzone,areptureDiv,borderDiv,

				//limit glass movement 
				var sz=getSize(obj.clickzone);
				if(x3<0){x3=0;l=x2-mglassW;}
				if(y3<0){y3=0;t=y2-mglassH;}
				if(x3>sz.w){x3=sz.w;l=x3+x2-mglassW;}
				if(y3>sz.h){y3=sz.h;t=y3+y2-mglassH;}
				
				move(obj.mglass,l,t);
				SetZoomPos(x3,y3);
				return false;
			}
			document.onmouseup = function(e) 
			{
				obj.clickzone.style.cursor = 'default';
				var ev = (typeof(e) != 'undefined' ? e : event);
				if (!obj.redeye) return false;
				obj.mglass.style.cursor = 'pointer';
				document.onmouseup = obj.redeyeMU;		obj.redeyeMU = null;
				document.onmousemove = obj.redeyeMM;	obj.redeyeMM = null;
				return false;
			}
			return false;
		}	
	}
}

TemplateControl.prototype.setDOMObjects = function() {
    this.maindiv = gebi(this.templateElementPrefix);
    this.aperturediv = gebi(this.elementPrefix + '_aperturediv');
    this.photodiv = gebi(this.elementPrefix + '_photodiv');
    this.photoimg = gebi(this.elementPrefix + '_photoimg');
    this.templateimg = gebi(this.templateElementPrefix + '_templateimg');
    this.borderdiv = gebi(this.elementPrefix + '_borderdiv');
    this.borderimg = gebi(this.elementPrefix + '_borderimg');
    this.clickzone = gebi(this.elementPrefix + '_clickzone');
    this.mglass = gebi(this.templateElementPrefix + '_mglass');
    this.apertureAbsRect = null;
    if (this.aperturediv) {
        this.aperturediv.style.overflow = 'hidden';
    }
}

TemplateControl.prototype.isBlank = function() {
	return (this.photoimg.src.toLowerCase().indexOf("/getimage.aspx") < 0);
}

TemplateControl.prototype.onMouseWheel = function(e) {
	if(!this.apertureAbsRect || !this.maindiv || this.redeye) return;
	var x = (this.isFF)?e.screenX + document.body.scrollLeft:Event.pointerX(e);
	var y = (this.isFF)?e.screenY + document.body.scrollTop:Event.pointerY(e);
	if(
		x > this.apertureAbsRect.x && x < (this.apertureAbsRect.x + this.apertureAbsRect.w) &&
		y > this.apertureAbsRect.y && y < (this.apertureAbsRect.y + this.apertureAbsRect.h)
	){
		var wheelDelta = (e.wheelDelta)?e.wheelDelta*((!!window.opera)?-1:1) : e.detail*-1;
		if (wheelDelta < 0){ this.zoomOut();}
		else{ this.zoomIn();}
		if(typeof updateZoomGraph == "function") updateZoomGraph();
	}
	else
	{
		return;
	}
	Event.stop(e); return false;
}
TemplateControl.prototype.setApertureAbsRect = function() {
	if(!this.borderimg.parentNode || typeof this.borderimg.parentNode.activeElement == "unknown") return;//the element is just added by ajax call
	var aperturePos = findPos(this.borderimg);
	var apertureDim = getDim(this.borderimg);
	this.apertureAbsRect = new Rectangle(aperturePos.x, aperturePos.y, apertureDim.w, apertureDim.h);
}
TemplateControl.prototype.show = function() {
	this.isFF = ( navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1  );	
	var sz = getSize(this.templateimg);
	resize(this.maindiv, sz.w, sz.h);
	// Scale border to available size. Distort aspect if needed.
	var templateApertureRect = new Rectangle(
		this.templateApertureRectF.x * sz.w,
		this.templateApertureRectF.y * sz.h,
		this.templateApertureRectF.w * sz.w,
		this.templateApertureRectF.h * sz.h);
	move(this.borderdiv, Math.round(templateApertureRect.x), Math.round(templateApertureRect.y));
	resize(this.borderimg, Math.round(templateApertureRect.w), Math.round(templateApertureRect.h));
	//this.apertureRect = new Rectangle(Math.floor(this.borderApertureRectF.x * templateApertureRect.w), Math.floor(this.borderApertureRectF.y * templateApertureRect.h), Math.ceil(this.borderApertureRectF.w * templateApertureRect.w), Math.ceil(this.borderApertureRectF.h * templateApertureRect.h));
	this.apertureRect = new Rectangle((this.borderApertureRectF.x * templateApertureRect.w), (this.borderApertureRectF.y * templateApertureRect.h), (this.borderApertureRectF.w * templateApertureRect.w), (this.borderApertureRectF.h * templateApertureRect.h));
	// Position and size clickzone
	move(this.clickzone, Math.round(templateApertureRect.x), Math.round(templateApertureRect.y));
	resize(this.clickzone, Math.round(templateApertureRect.w), Math.round(templateApertureRect.h));

	var photoimgdim = getSize(this.photoimg);
	
	// The image we want to place is larger than the allowed aperture size, we have to scale it down.
	if ((photoimgdim.w > this.apertureRect.w) || (photoimgdim.h > this.apertureRect.h))
	{
		this.controlOption = 0;
	}

	// Choose the way we want to display the images
	// 0(Default) - Scale image to aperture.
	// 1 - No scaling, and center image.
	// Invalid Number - Same as option 0.
	switch (this.controlOption)
	{
		case '1':
		{	// Do not scale the image, just center it in the aperture area.
			var w = (this.apertureRect.w / this.photoCropRectF.w);
			var h = (w * (photoimgdim.h / photoimgdim.w));
			var x = (this.photoCropRectF.x * w);
			var y = (this.photoCropRectF.y * h);
			var bounds = new Rectangle(-x, -y, w, h);
			this.enforceBounds(bounds);

			move(this.photodiv, Math.round(bounds.x), Math.round(bounds.y));
			move(this.photoimg, Math.round(this.apertureRect.x +  ((this.apertureRect.w - photoimgdim.w) / 2)),
				Math.round(this.apertureRect.y +  ((this.apertureRect.h - photoimgdim.h) / 2)));
			break;
		}
		case '0':
		default:
		{
			// Position and clip aperturediv
			move(this.aperturediv, Math.floor(this.apertureRect.x), Math.floor(this.apertureRect.y));
			clip(this.aperturediv, new Rectangle(0, 0, Math.ceil(this.apertureRect.w), Math.ceil(this.apertureRect.h)));

			var hasCrop = (typeof(this.photoCropRectF) != 'undefined' && this.photoCropRectF != null);
			var reCrop;
			if (hasCrop)
			{
				var apertureAspect = this.apertureRect.w / this.apertureRect.h;
				var cropAspect = (this.photoCropRectF.w * photoimgdim.w) / (this.photoCropRectF.h * photoimgdim.h);
				// if the crop was not done for this aperture then we should recrop it ourself
				reCrop = (apertureAspect + 0.01 < cropAspect || apertureAspect - 0.01 > cropAspect);
			}
			else
			{
				reCrop = true;
			}
			if (reCrop)
			{
				// Resze photo for aperture
				var pimgdim = scale(photoimgdim, this.apertureRect, true);
				resize(this.photoimg, Math.round(pimgdim.w), Math.round(pimgdim.h));

				// Center photoimg in aperturediv
				var padw = (pimgdim.w - this.apertureRect.w) / 2;
				var padh = (pimgdim.h - this.apertureRect.h) / 2;//0;

				move(this.photodiv, Math.round(-padw), Math.round(-padh));
				this.changed = true;
			}
			else
			{
				var w = (this.apertureRect.w / this.photoCropRectF.w);
				var h = (w * (photoimgdim.h / photoimgdim.w));
				var x = (this.photoCropRectF.x * w);
				var y = (this.photoCropRectF.y * h);
				var bounds = new Rectangle(-x, -y, w, h);
				this.enforceBounds(bounds);
				resize(this.photoimg, Math.round(bounds.w), Math.round(bounds.h));

				move(this.photodiv, Math.round(bounds.x), Math.round(bounds.y));
			}
			break;
		} // case 0, case default
	} // switch

	if (useIEPngHack && this.templateimg.src.toLowerCase().indexOf(".gif") == -1) {
		this.templateimg.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.templateimg.src + "', sizingMethod='scale')";
		this.templateimg.src = "../images/spacer.gif";
	}

	// Unhide
	this.maindiv.style.visibility = 'visible';
	
	this.enableRedEyeEditing( typeof activeTag != "undefined" && activeTag.value == "Redeye" );

	if(!this.controlOption && typeof updateZoomGraph == "function"){
		this.setApertureAbsRect();
		
		Event.observe(window, "DOMMouseScroll", this.onMouseWheel.bindAsEventListener(this));//firefox
		Event.observe(window, "mousewheel", this.onMouseWheel.bindAsEventListener(this));//safari,opera
		Event.observe(document, "mousewheel", this.onMouseWheel.bindAsEventListener(this));//ie
	}
	Event.observe(window, 'resize', this.onWindowResize.bindAsEventListener(this));

	this.isShown = true;
	this.dispatchEvent("show", null, true, false);
}

TemplateControl.prototype.onWindowResize = function() {
	this.setApertureAbsRect();
}

TemplateControl.prototype.enableDragPanning = function() {
	fncall('enableDragPanning');
	var originalonmouseup = document.onmouseup;
	var originalonmousemove = null;
	var dragging = false;

	var obj = this; // once inside event handlers "this" has different meaning

	// Mouse down event handler
	this.clickzone.onmousedown = function(e) {
		//fncall('dragPanMouseDownHandler');
		var ev = (typeof(e) != 'undefined' ? e : event);
		var dragStartElementPoint = getPosition(obj.photodiv);
		var dragStartClickPoint = new Point(ev.clientX, ev.clientY);
		originalonmousemove = document.onmousemove;
		dragging = true;
		obj.clickzone.style.cursor = 'move';
		// Mouse move event handler
		document.onmousemove = function(e2) {
			//fncall('dragPanMouseMoveHandler');
			if (!dragging) {
				document.onmousemove = originalonmousemove;
				return false;
			}
			var ev2 = (typeof(e2) != 'undefined' ? e2 : event);
			var dx = ev2.clientX - dragStartClickPoint.x;
			var dy = ev2.clientY - dragStartClickPoint.y;
			var dim = getSize(obj.photoimg);
			var rect = new Rectangle(dragStartElementPoint.x, dragStartElementPoint.y, dim.w, dim.h);
			rect.x += dx;
			rect.y += dy;
			obj.enforceBounds(rect);
			move(obj.photodiv, rect.x, rect.y);
			obj.changed = true;
			return false;
		}

		// Mouse up event handler
		document.onmouseup = function(e) {
			//fncall('dragPanMouseUpHandler');
			var ev = (typeof(e) != 'undefined' ? e : event);
			if (dragging) {
				document.onmousemove = originalonmousemove;
				dragging = false;
				obj.clickzone.style.cursor = 'pointer';
			}
			if (typeof(originalonmouseup) != 'undefined' && originalonmouseup != null) {
				return originalonmouseup(ev);
			}
			else {
				return false;
			}
		}
		return false;
	}

	// correcton: currently enableDragPanning function is called on page.onload without taking into account activeTag flag.
	if(typeof(activeTag)!= 'undefined')
	{
		if(activeTag.value=='Effects')showEffects();
		else if (activeTag.value=='Redeye')showRedeye();
		else showEdit();
	}
}

TemplateControl.prototype.zoomIn = function() {
	fncall('zoomIn');
	this.setZoom(this.getZoom() + 1);
}

TemplateControl.prototype.zoomOut = function() {
	fncall('zoomOut');
	this.setZoom(this.getZoom() - 1);
}

TemplateControl.prototype.setZoom = function(z) {
	fncall('setZoom ' + z);
	var oldZ = this.getZoom();
	
	// calculate size for zoom=0
	var oldsz = getSize(this.photoimg);
	var newsz = scale(oldsz, this.apertureRect, true);
	// scale it up to the desired point
	var i;
	for (i = 0; i < z; i++) {
		newsz.w *= this.zoomFactor;
		newsz.h *= this.zoomFactor;
	}
	// remain centered on center
	var pos = getPosition(this.photodiv);
	pos.x = (pos.x - this.apertureRect.w / 2) / oldsz.w;
	pos.y = (pos.y - this.apertureRect.h / 2) / oldsz.h;
	var newx = (pos.x * newsz.w) + this.apertureRect.w / 2;
	var newy = (pos.y * newsz.h) + this.apertureRect.h / 2;

    this.completeZoom(new Rectangle(newx, newy, newsz.w, newsz.h), oldZ, z);

}

TemplateControl.prototype.crop = function(cropArea) {
    var oldZoom = this.getZoom();
    
    var posApt = findPos(this.borderimg);
    var dimApt = getDim(this.borderimg);
    var aperture = new Rectangle(posApt.x,posApt.y,dimApt.w,dimApt.h);
    
    var scaleFactor = aperture.w / cropArea.w;
    var imgPos = findPos(this.photoimg);
    var imgDim = getDim(this.photoimg);
    
    var relPoint = new Point((cropArea.x - imgPos.x) / imgDim.w,(cropArea.y - imgPos.y) / imgDim.h);
    
    imgDim.w *= scaleFactor;
    imgDim.h *= scaleFactor;
    
    var absPoint = new Point(imgDim.w * relPoint.x * -1,imgDim.h * relPoint.y * -1);

	this.completeZoom(new Rectangle(absPoint.x, absPoint.y, imgDim.w, imgDim.h), oldZoom, this.getZoom());
}

TemplateControl.prototype.completeZoom = function(rect, oldZoom, newZoom) {
	this.enforceBounds(rect);
	move(this.photodiv, Math.round(rect.x), Math.round(rect.y));
	resize(this.photoimg, Math.round(rect.w), Math.round(rect.h));
	this.changed = true;
	
	this.dispatchEvent("zoom", {"oldZoom":oldZoom, "newZoom":newZoom}, true, false);
}

TemplateControl.prototype.getZoom = function() {
	fncall('getZoom');
	// calculate size for zoom=0
	var oldsz = getSize(this.photoimg);
	var newsz = scale(oldsz, this.apertureRect, true);
	// scale it up to the current point
	var z = 0;
	while (Math.round(newsz.w) < oldsz.w && Math.round(newsz.h) < oldsz.h) {
		newsz.w *= this.zoomFactor;
		newsz.h *= this.zoomFactor;
		z++;
	}
	return z;
}

TemplateControl.prototype.enforceBounds = function(rect) {
	fncall('enforceBounds ' + rect.x + ' ' + rect.y + ' ' + rect.w + ' ' + rect.h);
	// Size
	if (rect.w < this.apertureRect.w) {
		var scale = this.apertureRect.w / rect.w;
		rect.w *= scale;
		rect.h *= scale;
	}
	
	if (rect.h < this.apertureRect.h) {
		var scale = this.apertureRect.h / rect.h;
		rect.w *= scale;
		rect.h *= scale;
	}
	// Position
	rect.x = Math.min(0, Math.max(rect.x, this.apertureRect.w - rect.w));
	rect.y = Math.min(0, Math.max(rect.y, this.apertureRect.h - rect.h));
}
TemplateControl.prototype.insureDouble = function(d){
    if(d == Number.POSITIVE_INFINITY) d = 1;
    else if(d == Number.NEGATIVE_INFINITY) d = 0;
    else if(isNaN(d)) d = 0;
    else if(d > 1) d = 1;
    else if(d < -1) d = -1;
    return d;
}
TemplateControl.prototype.getCrop = function() {
	if (this.apertureRect != null) 
	{
		var w = this.apertureRect.w;
		var h = this.apertureRect.h;
		var sz = getSize(this.photoimg);
		var pos = getPosition(this.photodiv);
		return new Rectangle(this.insureDouble((-pos.x) / sz.w), this.insureDouble((-pos.y) / sz.h), this.insureDouble(w / sz.w), this.insureDouble(h / sz.h));
	}
}
TemplateControl.prototype.dispose = function() {
	// detouch listeners
	if(!this.controlOption && typeof updateZoomGraph == "function"){
		Event.stopObserving(window, "DOMMouseScroll", this.onMouseWheel.bindAsEventListener(this));//firefox
		Event.stopObserving(window, "mousewheel", this.onMouseWheel.bindAsEventListener(this));//safari,opera
		Event.stopObserving(document, "mousewheel", this.onMouseWheel.bindAsEventListener(this));//ie
	}
	// Delete references to DOM elements to avoid memory leakage
	this.clickzone.onmousedown = null;
	this.maindiv = null
	this.aperturediv = null;
	this.photodiv = null;
	this.imgdiv = null;
	this.templateimg = null;
	this.clickzone = null;
}

Object.extend(TemplateControl.prototype , Event.Publisher);

/*
 * TemplateControl class end
 */
