var INTERVAL = 10, DELTA = 2;
		
																					
function animateImage(oImg, bExpand, fSpeed) {
	if( !fSpeed ) fSpeed = 1;
	
	if( !oImg.clipRect ) {					
		oImg.clipRect = oImg.style.clip.replace("rect(", "").replace("px)", "").replace(/px,?/gi, "").split(" ");					
	}
	
	if( !bExpand && oImg.toggled ) return;
	
	var oInitialSize = getPrefixedSize(oImg, "initial");
	var oInitialPos = getPrefixedPos(oImg, "initial");
	var oThumbSize = getPrefixedSize(oImg, "thumb");
	
	oImg.expanding = bExpand;
	expansionStarted(oImg);				 
	var oSizeTo, oMoveTo;
	if( bExpand ) {								
		oSizeTo = oThumbSize;
		oMoveTo = {
			width: (oInitialSize.width - oThumbSize.width) / 2 - oImg.sizeMargin + oInitialPos.width, 					
			height: (oInitialSize.height - oThumbSize.height) / 2 - oImg.sizeMargin + oInitialPos.height}; 
	} else {
		oSizeTo = oInitialSize;						
		oMoveTo = {width: oInitialPos.width - oImg.sizeMargin, height: oInitialPos.height + -oImg.sizeMargin}
	}									
										
	sizeTo(oImg, oSizeTo, null, fSpeed*DELTA);
	moveTo(oImg, oMoveTo, bExpand ? null : expansionEnded, fSpeed*getSynchronisedStepSize(getPosDelta(oImg, oMoveTo), getSizeDelta(oImg, oSizeTo))*DELTA, clipImage);
}

function moveTo(o, oMoveTo, fOnEnded, fStepSize, fOnChange) {
	_animate(o, oMoveTo, fOnEnded, fStepSize, fOnChange, true);	
}

function sizeTo(o, oSizeTo, fOnEnded, fStepSize, fOnChange) {
	_animate(o, oSizeTo, fOnEnded, fStepSize, fOnChange, false);
}

function clipImage(oImg) {
	var oThumbSize = getPrefixedSize(oImg, "thumb");				
	var oSize = getSizeF(oImg);
	var oInitialSize = getPrefixedSize(oImg, "initial");
	
	var iSizeMax = Math.max(oSize.width, oSize.height);
	var iThumbMax = Math.max(oThumbSize.width, oThumbSize.height);
	var iInitMax = Math.max(oInitialSize.width, oInitialSize.height);
	
	var fProgress = (iThumbMax - iSizeMax) / (iThumbMax - iInitMax);
	var cClip = oImg.clipRect;
	oImg.style.clip = "rect(" + 
		(fProgress*cClip[0]) + "px " +
		(oSize.width - fProgress*cClip[3] + 2*oImg.sizeMargin) + "px " +
		(oSize.height - fProgress*cClip[0] + 2*oImg.sizeMargin) + "px " +
		(fProgress*cClip[3]) + "px)";
}

	
var htFadeInfos = [];			
function fadeTo(o, fOpacity, fSpeed, fOnComplete) {				
	var oFadeInfo = [];
	oFadeInfo.opacity = fOpacity;
	oFadeInfo.speed = fSpeed;
	oFadeInfo.onComplete = fOnComplete;
	
	htFadeInfos[o.id] = oFadeInfo;
	_fadeTo(o.id);				
}	

function _fadeTo(sID) {				
	clearImgTimeout(sID, "fade");				
	var o = document.getElementById(sID);
	if( !o ) 
		return;
		
	var oFadeInfo = htFadeInfos[sID];
	var fOpacity = getOpacityF(o);				
	fOpacity += oFadeInfo.speed;
	if( oFadeInfo.speed < 0 && fOpacity < oFadeInfo.opacity ) fOpacity = oFadeInfo.opacity;
	else if( oFadeInfo.speed > 0 && fOpacity > oFadeInfo.opacity ) fOpacity = oFadeInfo.opacity;
	
	setOpacityF(o, fOpacity);		
	if( fOpacity == oFadeInfo.opacity ) {					
		if( oFadeInfo.onComplete )
			oFadeInfo.onComplete(o);
	} else {					
		setImgTimeout(sID, "_fadeTo", "fade");
	}
}


var iZInc = 0, iAnimatingImages = 0;
function expansionStarted(oImg) {		
	if( !oImg.hovered ) {					
		++iAnimatingImages;
		oImg.parentNode.style.zIndex = 10000 + iZInc++;					 					
	}
					
	setClassAbs(oImg, oImg.toggled ? "selectedThumbImage" : (oImg.expanding ? "activeThumbImage" : "thumbImage"));								
	oImg.hovered = true;
}

function setClassAbs(o, sClass) {
	var oPos = getPosF(o);
	var iPreBorderWidth = getBorderWidth(o);
	o.className = sClass;
	var iBorderWidth = getBorderWidth(o);								
	var iChange = iBorderWidth - iPreBorderWidth;
	
	o.sizeMargin = iBorderWidth;
	setPosF(o, oPos.width - iChange, oPos.height - iChange);				
}

function expansionEnded(oImg) {				
	if( --iAnimatingImages <= 0 ) iZInc = 0;
	oImg.parentNode.style.zIndex = 0;
	oImg.hovered = false;
	oImg.toggled = false;
}

function toggleThumb(oImg, bToggle) {
	var sClassName = bToggle ? "selectedThumbImage" : "thumbImage";
	oImg.className = sClassName;
	oImg.toggled = bToggle;
	animateImage(oImg, bToggle);
}

function getBorderWidth(o) {
	return (o.offsetWidth - o.clientWidth) / 2;
}
	
var htTimeouts = [];
function setImgTimeout(sID, sFunc, sName) {
	if( !sName ) sName = "";
	if( !htTimeouts[sID+"__"+sName] ) {				
		htTimeouts[sID+"__"+sName] = setTimeout(sFunc + "('" + sID + "')", INTERVAL);					
	}				
}
			
function clearImgTimeout(sID, sName) {
	if( !sName ) sName = "";
	if( htTimeouts[sID+"__"+sName] ) {					
		clearTimeout(htTimeouts[sID+"__"+sName]);
		htTimeouts[sID+"__"+sName] = null;
	}						
}

function getPrefixedSize(oImg, sPrefix) {				
	if( !oImg.getAttribute(sPrefix + "_width") ) {
		oImg.setAttribute(sPrefix + "_width", parseInt(oImg.style.width));
		oImg.setAttribute(sPrefix + "_height", parseInt(oImg.style.height));
	}
	
	return { width: 1*oImg.getAttribute(sPrefix + "_width"), height: 1*oImg.getAttribute(sPrefix + "_height") }; 
}

function getPrefixedPos(oImg, sPrefix) {				
	if( !oImg.getAttribute(sPrefix + "_left") && oImg.getAttribute(sPrefix + "_left") != "0" ) {
		oImg.setAttribute(sPrefix + "_left", parseInt(oImg.style.left));
		oImg.setAttribute(sPrefix + "_top", parseInt(oImg.style.top));
	}
	
	return { width: 1*oImg.getAttribute(sPrefix + "_left"), height: 1*oImg.getAttribute(sPrefix + "_top") }; 
}

function getSizeF(oImg) {			
	if( oImg.fWidth == null ) {					
		setSizeF(oImg, parseInt(oImg.style.width), parseInt(oImg.style.height));
	}
	
	return { width: oImg.fWidth, height: 1*oImg.fHeight };
}

function setSizeF(oImg, fWidth, fHeight) {
	if( fWidth != null ) {
		oImg.fWidth = fWidth;					
		oImg.style.width = oImg.width = Math.round(fWidth) + "px";					
	}
	if( fHeight != null ) { 
		oImg.fHeight = fHeight;
		oImg.style.height = oImg.height = Math.round(fHeight) + "px";
	}				
}

function getPosF(o) {								
	if( o.fLeft == null ) {					
		setPosF(o, parseInt(o.style.left), parseInt(o.style.top));										
	}				
	return { width: o.fLeft, height: o.fTop };
}
			
function setPosF(o, fLeft, fTop) {				
	if( fLeft != null ) {
		o.fLeft = fLeft;			
		o.style.left = Math.round(fLeft) + "px";
	}
	if( fTop != null ) { 
		o.fTop = fTop;
		o.style.top = Math.round(fTop) + "px";					
	}	
}

function getOpacityF(o) {
	if( o.fOpacity == null ) {					
		setOpacityF(o, 1);
	}				
	return o.fOpacity;
}

function setOpacityF(o, fOpacity) {
	o.fOpacity = fOpacity;				
	if( document.all ) {
		o.style.filter = "alpha(opacity=" + Math.round(fOpacity*100) + ")";
	} else {
		o.style.opacity = fOpacity;
		o.style.MozOpacity = fOpacity;
	}								
}

function resetF(o) {
	o.fLeft = o.fTop = o.fWidth = o.fHeight = o.fOpacity = null;												
}									

function _animate(o, oSizeTo, fOnEnded, fStepSize, fOnChange, bMove) {			
	var oDelta = bMove ? getPosDelta(o, oSizeTo) : getSizeDelta(o, oSizeTo);
	if( oDelta.width == 0 && oDelta.height == 0 ) return;
	
	var oSizeInfo = [];				
	oSizeInfo.sizeTo = oSizeTo;
	if( oDelta.height == 0 )
		oSizeInfo.aspect = 1;
	else
		oSizeInfo.aspect = Math.abs(oDelta.width / oDelta.height);
	
	oSizeInfo.stepSize = !fStepSize ? 1 : fStepSize;				
	
	oSizeInfo.onComplete = fOnEnded;
	oSizeInfo.onChange = fOnChange;				
	htSizeInfos[_getSizeKey(o.id, bMove)] = oSizeInfo;
					
	if( bMove ) _moveImage(o.id); else _sizeImage(o.id);
}

function _getSizeKey(sID, bMove) {
	return sID+(bMove ? "__move" : "__size");
}


var htSizeInfos = [];

function _moveImage(sID) {
	_sizeOrMoveImage(sID, true);
}

function _sizeImage(sID) {
	_sizeOrMoveImage(sID, false);
}			

var sDebug = "";
function _sizeOrMoveImage(sID, bMove) {	
	clearImgTimeout(sID, bMove ? "move" : "size");				
	var o = document.getElementById(sID);			
	if( !o ) return;
	
	var oSize = bMove ? getPosF(o) : getSizeF(o);				
									
	var oSizeInfo = htSizeInfos[_getSizeKey(sID, bMove)];
	var oFinalSize = oSizeInfo.sizeTo;
					
	
	var fIncX, fIncY;
	var fAspect = oSizeInfo.aspect;
	var fStepSize = oSizeInfo.stepSize;
	
	fIncX = fAspect > 1 ? 1 : fAspect;
	fIncY = fAspect <= 1 ? 1 : 1 / fAspect;
					
	fIncX = oFinalSize.width >= oSize.width ? 
		Math.min(fStepSize * fIncX, oFinalSize.width - oSize.width) : Math.max(-fStepSize * fIncX, oFinalSize.width - oSize.width);
	fIncY = oFinalSize.height >= oSize.height ? 
		Math.min(fStepSize * fIncY, oFinalSize.height - oSize.height) : Math.max(-fStepSize * fIncY, oFinalSize.height - oSize.height);							
		
	if( bMove ) {					
		setPosF(o, oSize.width + fIncX, oSize.height + fIncY);
	} else {
		setSizeF(o, oSize.width + fIncX, oSize.height + fIncY);
	}				
	
	if( oSizeInfo.onChange ) oSizeInfo.onChange(o);
	
	if( fIncX || fIncY ) {						
		setImgTimeout(sID, bMove ? "_moveImage" : "_sizeImage", bMove ? "move" : "size");
	} else {
		htSizeInfos[_getSizeKey(sID, bMove)] = null;
		if( oSizeInfo.onComplete )
			oSizeInfo.onComplete(o);					
	}					
}

function getSizeDelta(o, oNewSize) {
	var oSize = getSizeF(o);
	return { width: Math.abs(oSize.width - oNewSize.width), height: Math.abs(oSize.height - oNewSize.height) };
}

function getPosDelta(o, oNewPos) {
	var oPos = getPosF(o);
	return { width: Math.abs(oPos.width - oNewPos.width), height: Math.abs(oPos.height - oNewPos.height) };
}
			

function getSynchronisedStepSize(oSize1, oSize2) {
	var iMax1 = Math.max(Math.abs(oSize1.width), Math.abs(oSize1.height));
	var iMax2 = Math.max(Math.abs(oSize2.width), Math.abs(oSize2.height));
	return iMax1 / iMax2;
}

function getSpeedFromSteps(oDelta, iSteps) {
	var iMax = Math.max(Math.abs(oDelta.width), Math.abs(oDelta.height));				
	return iMax / iSteps;
}


var iCloneID = 0;

function createClone(oSrc) {			
	if( !oSrc.cloneID ) {
		var oClone = oSrc.cloneNode(true);
		oClone.id = "__clone" + ++iCloneID;
		oClone.style.position = "absolute";
		oClone.style.left = findPosX(oSrc) + "px";
		oClone.style.top = findPosY(oSrc) + "px";																 
		
		oClone.onmouseover = oClone.onmouseout = null;
		document.body.appendChild(oClone);
		
		oClone.srcID = oSrc.id;
		oSrc.cloneID = oClone.id;
		
		resetF(oClone);
		
		return oClone;
	} else {
		return null;
	}
}

function getPreviewSize(oImg) {
	var oPreviewSize = getPrefixedSize(oImg, "main");
	
	var oPreviewImage = document.getElementById("imgPreview");	
	var oContainer = oPreviewImage.parentNode; 	
	if( oContainer.getAttribute("oversizePreview") != "true" ) {
		var iMaxWidth = oContainer.clientWidth;
		var iMaxHeight = oContainer.clientHeight;		
		while( oPreviewSize.width > iMaxWidth || oPreviewSize.height > iMaxHeight ) { 
			if( oPreviewSize.width > iMaxWidth ) {
				oPreviewSize.height = iMaxWidth * oPreviewSize.height / oPreviewSize.width;
				oPreviewSize.width = iMaxWidth;
			} 
			if( oPreviewSize.height > iMaxHeight ) {
				oPreviewSize.width = iMaxHeight * oPreviewSize.width / oPreviewSize.height;
				oPreviewSize.height = iMaxHeight;
			}
		}
	}
	
	return oPreviewSize;
}

var oCurrentClone = null;
function destroyOldClone() {
	if( oCurrentClone ) {
		var oSrc = document.getElementById(oCurrentClone.srcID);
		if( oSrc ) 
			oSrc.cloneID = null;					
		oCurrentClone.parentNode.removeChild(oCurrentClone);
		oCurrentClone = null;
	}		
}

function cloneHasMoved(o) {
	destroyOldClone();			
	oCurrentClone = o;		
	var oImg = document.getElementById(o.srcID);
	
	if( o.onImageSelected ) {
		o.onImageSelected(oImg);
		o.onImageSelected = null;
	}
	var oPreviewImage = document.getElementById("imgPreview");
	oPreviewImage.style.visibility = "visible";
	oPreviewImage.src = o.getAttribute("path");
	var oPreviewSize = getPreviewSize(oImg);
	setSizeF(oPreviewImage, oPreviewSize.width, oPreviewSize.height);
}

function previewImageLoaded() {	
	destroyOldClone();
}

var oOldSel = null;
var toSelectImageAtOnce = null;
function selectImageAtOnce(sImgID, fOnImageSelected) {		
	clearTimeout(toSelectImageAtOnce);
	var oImg = document.getElementById(sImgID);
	
	if( fOnImageSelected )
		oImg.onImageSelected = fOnImageSelected;
	
	var oPreviewImage = document.getElementById("imgPreview");
	var oContainer = oPreviewImage.parentNode;
	
	var bAnimatePreview = oContainer.getAttribute("animatePreview") == "true";
	var oPreviewSize = getPreviewSize(oImg);
	if( oPreviewSize.width == 0 ) {
		toSelectImageAtOnce = setTimeout("selectImageAtOnce('" +sImgID + "')", 100);
		return;
	}
	setSizeF(oPreviewImage, oPreviewSize.width, oPreviewSize.height)
	if( bAnimatePreview ) {
		var oContainerSize = { width: oContainer.clientWidth, height: oContainer.clientHeight };			
		oPreviewNewPos = {width: (oContainerSize.width - oPreviewSize.width) / 2, height: (oContainerSize.height - oPreviewSize.height) / 2};
		setPosF(oPreviewImage, oPreviewNewPos.width, oPreviewNewPos.height); 
	}	
	oPreviewImage.style.visibility = "visible";
	oPreviewImage.src = oImg.getAttribute("path");
	
	if( oOldSel != null ) {
		toggleThumb(oOldSel, false);										
	}
	oOldSel = oImg;
	toggleThumb(oImg, true);	
	oOldSel = oImg;
	
	if( oImg.onImageSelected ) {
		oImg.onImageSelected(oImg);
		oImg.onImageSelected = null;		
	}
}

function selectImage(oImg, fOnImageSelected) {
	if( oImg.toggled ) return;

	var iSteps = 20;
	var oClone = createClone(oImg);								
	if( oClone ) {
		oClone.style.zIndex = oImg.parentNode.style.zIndex + 1;
		oClone.className = "";
		oClone.style.clip = "rect(auto auto auto auto)";
		oClone.onImageSelected = fOnImageSelected;
		
		var oClonePos = getPosF(oClone);
		setClassAbs(oImg, oImg.className); // Ensure sizeMargin
		setPosF(oClone, oClonePos.width + oImg.sizeMargin, oClonePos.height + oImg.sizeMargin);

		var oPreviewImage = document.getElementById("imgPreview");
		var oContainer = oPreviewImage.parentNode;
		var bAnimatePreview = oContainer.getAttribute("animatePreview") == "true";
		
		if( !oPreviewImage.onload ) {
			oPreviewImage.onload = previewImageLoaded;	
		}
		
		var oPreviewPos = {width: findPosX(oPreviewImage), height: findPosY(oPreviewImage)};
		var oPreviewSize = getPreviewSize(oImg);
		var oPreviewNewPos;		
				
		if( bAnimatePreview ) {			
			var oContainerSize = { width: oContainer.clientWidth, height: oContainer.clientHeight };			
			oPreviewNewPos = {width: (oContainerSize.width - oPreviewSize.width) / 2, height: (oContainerSize.height - oPreviewSize.height) / 2};
			var oPos = getPosF(oPreviewImage);
			oPreviewPos.width += oPreviewNewPos.width - oPos.width;
			oPreviewPos.height += oPreviewNewPos.height - oPos.height;			
		} 		 				
		
		var oPosDelta = getPosDelta(oClone, oPreviewPos);
		var fMainSpeed = getSpeedFromSteps(oPosDelta, iSteps);
		
		fPreviewSpeed = fMainSpeed * getSynchronisedStepSize(getSizeDelta(oPreviewImage, oPreviewSize), oPosDelta);										
		sizeTo(oClone, oPreviewSize, null, fMainSpeed * getSynchronisedStepSize(getSizeDelta(oClone, oPreviewSize), oPosDelta));
		moveTo(oClone, oPreviewPos, cloneHasMoved, fMainSpeed);
		sizeTo(oPreviewImage, oPreviewSize, null, fPreviewSpeed);
		
		if( bAnimatePreview ) {
			moveTo(oPreviewImage, oPreviewNewPos, null, fMainSpeed * getSynchronisedStepSize(getPosDelta(oPreviewImage, oPreviewNewPos), oPosDelta));		
		}
		
		if( oOldSel != null ) {
			toggleThumb(oOldSel, false);										
		}
		oOldSel = oImg;
		toggleThumb(oImg, true);
		
	}	
	
}


function findPosX(obj)
{
	var curleft = 0;
	if (obj.offsetParent)
	{
		while (obj.offsetParent)
		{
			curleft += obj.offsetLeft
			if( obj.tagName.toLowerCase() == "td" && obj.currentStyle && obj.currentStyle.borderLeftStyle != "none" )
			{
				var iBorderLeftWidth = parseInt(obj.currentStyle.borderLeftWidth);
				if( !isNaN(iBorderLeftWidth) )
					curleft += parseInt(obj.currentStyle.borderLeftWidth);				
			}
		
			obj = obj.offsetParent;
		}
	}
	else if (obj.x)
		curleft += obj.x;
	return curleft;
}


function findPosY(obj)
{
	var curtop = 0;	
	if (obj.offsetParent)
	{
		while (obj.offsetParent)
		{
			curtop += obj.offsetTop;
			if( obj.tagName.toLowerCase() == "td" && obj.currentStyle && obj.currentStyle.borderTopStyle != "none" )
			{
				curtop += parseInt(obj.currentStyle.borderTopWidth);				
			}
			obj = obj.offsetParent;
		}
	}
	else if (obj.y)
		curtop += obj.y;
	return curtop;
}
