/**	
 * DHTML Animation Class : Handles translations, resizing, fades, and visual effects for HTML Elements
 */
function AnimationController(id) {

	this.id = id;
	this.groupMap = new Array();
	
	return this;
}	

// Constants
AnimationController.prototype.CYCLE_TIME = 300;
AnimationController.prototype.STATE_HOVER_ON = "on";
AnimationController.prototype.STATE_HOVER_OFF = "off";
AnimationController.prototype.STATE_ALTERNATE_ON = "open";
AnimationController.prototype.STATE_ALTERNATE_OFF = "closed";
AnimationController.prototype._cssAttributes = undefined;
AnimationController.prototype._cssText = undefined;

// Attributes
AnimationController.prototype.id = "AnimationController";
AnimationController.prototype.groupMap = undefined;

function getWidth(pObject){
	var returnValue=0;
	if(pObject!=0&&pObject!=undefined){
		if(pObject.clientWidth!=undefined&&pObject.clientWidth!=0){
			returnValue=parseInt(pObject.clientWidth);
		}else if(pObject.style.width&&pObject.style.width!=""&&pObject.style.width!=0){
			returnValue=parseInt(pObject.style.width);
		}else if(pObject.offsetWidth&&pObject.offsetWidth!=0){
			returnValue=parseInt(pObject.offsetWidth);
		}
	}
	return returnValue;
}
function getHeight(pObject){
	var returnValue=0;
	if(pObject!=0&&pObject!=undefined){
		if(pObject.clientHeight!=undefined&&pObject.clientHeight!=0){
			returnValue=parseInt(pObject.clientHeight);
		}else if(pObject.style.height&&pObject.style.height!=""&&pObject.style.height!=0){
			returnValue=parseInt(pObject.style.height);
		}else if(pObject.offsetHeight&&pObject.offsetHeight!=0){
			returnValue=parseInt(pObject.offsetHeight);
		}
	}
	return returnValue;
}

/**
 * Returns the css attributes of the specified elementId
 */
AnimationController.prototype.getElementCSSAttributes = function(elementId) {
	
	if (this._cssText == undefined) {
		
		this._cssText = "";
		
		for (var i=0; i<document.styleSheets.length; i++) {
			this._cssText += document.styleSheets[i].cssText
		}
	}
	
	var attributes = new Array();
	
	// Generate css attributes map for the elementId
	if (this._cssText.indexOf(elementId) > -1) {

		var cssText = new RegExp("#" + elementId + "\\s\\{([^\\}]*)\\}","g").exec(this._cssText.replace(/[\n\r]/g,""))[1];

		if (cssText != undefined) {
			var cssAttributes = cssText.match(/[A-Za-z]+\:\s?[^\;\t]*/g);
			var attributeInfo = undefined;
			
			for (var i=0; i<cssAttributes.length; i++) {
				attributeInfo = cssAttributes[i].match(/([^\:]*)\:\s?(.*)/);
				attributes[attributeInfo[1].toLowerCase()] = attributeInfo[2];
			}
		}
	}
	
	var element = document.getElementById(elementId);
	if (element != undefined) {
		element._cssAttributes = attributes;
	}
	
	return attributes;
}
	
/**
 * Defines a DIV element as an animatable DIV
 * @param {HTMLElement} element			HTML element to define
 */
AnimationController.prototype._define = function(element) {

    element.isDefined = true;
    
    var cssAttributes = this.getElementCSSAttributes(element.id);
    
    element.onComplete = (element.getAttribute("onAnimationComplete")!=undefined?element.getAttribute("onAnimationComplete"):undefined);
    
    element.oClass = element.className;
    element.tClass = element.getAttribute("tClass");

	element.oZIndex = element.style.zIndex;

    element.tZIndex = (cssAttributes["tZIndex"] != undefined ? cssAttributes["tZIndex"] 
    	: (element.style.tZIndex != undefined ? element.style.tZIndex : element.getAttribute("tZIndex")));

	if (element.style.position != "relative" && isNaN(parseInt(element.style.left)) && !isNaN(parseInt(element.offsetLeft))) {
		element.oLeft = parseInt(element.offsetLeft);
	} else if (!isNaN(parseInt(element.style.left))) {
		element.oLeft = parseInt(element.style.left);
	} else {
		element.oLeft = 0;
	}

	if (element.style.position != "relative" && isNaN(parseInt(element.style.top)) && !isNaN(parseInt(element.offsetTop))) {
		element.oTop = parseInt(element.offsetTop);
	} else if (!isNaN(parseInt(element.style.top))) {
		element.oTop = parseInt(element.style.top);
	} else {
		element.oTop = 0;
	}

    element.oWidth = parseInt(cssAttributes["width"] != undefined ? cssAttributes["width"]
    	: getWidth(element));
    	
    element.oHeight = parseInt(cssAttributes["height"] != undefined ? cssAttributes["height"]
    	: getHeight(element));

    element.tLeft = parseInt(cssAttributes["tleft"] != undefined ? cssAttributes["tleft"]
    	: (element.getAttribute("tLeft") != undefined ? element.getAttribute("tLeft") : element.oLeft));

    element.tTop = parseInt(cssAttributes["ttop"] != undefined ? cssAttributes["ttop"]
    	: (element.getAttribute("tTop") != undefined ? element.getAttribute("tTop") : element.oTop));

    element.tWidth = parseInt(cssAttributes["twidth"] != undefined ? cssAttributes["twidth"]
    	: (element.getAttribute("tWidth") != undefined ? element.getAttribute("tWidth") : element.oWidth));

    element.tHeight = parseInt(cssAttributes["theight"] != undefined ? cssAttributes["theight"] 
    	: (element.getAttribute("tHeight") != undefined ? element.getAttribute("tHeight") : element.oHeight));


    element.state = this.STATE_ALTERNATE_OFF;
    
    element.groupName = (cssAttributes["groupname"] != undefined ? cssAttributes["groupname"]
    	: (element.getAttribute("groupName") != undefined ? element.getAttribute("groupName")
	    	: (element.getAttribute("group_name") != undefined ? element.getAttribute("group_name") : undefined)));

    this.registerElementIdInGroup(element.id, element.groupName);
}

/**
 * Adds an elementId in a group
 * @param {String} elementId			ID of the HTML element to include
 * @param {String} groupName			Name of the group (optional)
 */	
AnimationController.prototype.registerElementIdInGroup = function(elementId, groupName) {

	if (groupName != undefined) {

	    // Create a group of reference to affect multiple elements simultaneously
	    if (this.groupMap[groupName] == undefined) {
	    	this.groupMap[groupName] = new Array();
	    }
	    
	    this.groupMap[groupName].push(elementId);
	}
}

/**
 * Animates the div to the targetted position and size or back to the original size
 * @param {String} elementId			ID of the HTML element to include
 * @param {String} groupName			Name of the group (optional)
 */
AnimationController.prototype.openAndClose = function(elementId, isQuickMode) {

	quickMode = (isQuickMode != undefined && isQuickMode == true ? true : false);

    // Getting a reference on the DIV element
    var element = document.getElementById(elementId);

    if (element != undefined) {
	    
	    // Define the element attributes
	    if (element.isDefined == undefined ) {
	        this._define(element);
	    }
    
	    this.resetAll(element.groupName, new Array(elementId), quickMode);
    
	    // Closed div, will be opened
	    if (element.state == this.STATE_ALTERNATE_OFF) {
	        this.open(elementId);
	        
	   	// Opened div, will be closed
	    } else if (element.state == this.STATE_ALTERNATE_ON) {
	        this.reset(elementId);
	    }
	    
    } /*else {
    	log.error("element '" + elementId + "' is undefined", this);
    }*/
}

/**	
 * Animates the div to the targetted position and size and resets all other divs in the same group
 * This will allow automatic closing of every other in the group when one is opened.
 * @param {String} elementId			ID of the HTML element to include
 * @param {String} groupName			Name of the group (optional)
 */
AnimationController.prototype.openSingle = function(elementId, isQuickMode) {

	quickMode = (isQuickMode != undefined && isQuickMode == true ? true : false);

    // Getting a reference on the DIV element
    var element = document.getElementById(elementId);
    
    if (element != undefined) {
   
	    // Define the element attributes
	    if (element.isDefined == undefined ) {
	        this._define(element);
	    }

		this.resetAll(element.groupName, new Array(elementId), quickMode);
		element.thread = setTimeout(this.id+".open('"+elementId+"', undefined, "+quickMode+")", 1);    
	}
}

/**
 * Animates the div to the targetted position and size 
 * @param {String} elementId			ID of the HTML element to include
 * @param {String} groupName			Name of the group (optional)
 */
AnimationController.prototype.open = function(elementId, isQuickMode) {

	quickMode = (isQuickMode != undefined && isQuickMode == true ? true : false);

    // Getting a reference on the DIV element
    var element = document.getElementById(elementId);
    
    if (element != undefined) {

	    // Define the element attributes
	    if (element.isDefined == undefined ) {
	        this._define(element);
	    }
	    
	    element.state = this.STATE_ALTERNATE_ON;
	    
	    if (element.tZIndex != undefined) {
		    element.style.zIndex = element.tZIndex;
	    }
	    
	    if ( element.thread != undefined ) {
	        clearTimeout(element.thread);
	    }
	    
	    var onComplete = (element.getAttribute("onOpen") != undefined ? element.getAttribute("onOpen") : (element.getAttribute("onopen") != undefined ? element.getAttribute("onopen") : element.onComplete));
	    
		var attributes = new Array();
		attributes["tLeft"] = element.tLeft;
		attributes["tTop"] = element.tTop;
		attributes["tWidth"] = element.tWidth;
		attributes["tHeight"] = element.tHeight;
		attributes["tClass"] = element.tClass;
		attributes["onComplete"] = onComplete;
			    	
	    if (quickMode) {
	    	attributes["duration"] = 0;
	    }
	    
		this.animateElement(elementId, attributes);
    			
    } else {
    	log.error("element '" + elementId + "' is undefined", this);
	}
}

/**	
 * Resets the animated DIV position and size to the original.
 * @param {String} elementId			ID of the HTML element to include
 * @param {String} groupName			Name of the group (optional)
 * @param {Boolean} isQuickMode			(optional) resets without animating the closing
 */
AnimationController.prototype.reset = function(elementId, isQuickMode) {

	quickMode = (isQuickMode != undefined && isQuickMode == true ? true : false);

    // Getting a reference on the DIV element
    var element = document.getElementById(elementId);
    
    if (element != undefined) {
    
	    // Define the element attributes
	    if (element.isDefined == undefined ) {
	        this._define(element);
	    }

	    element.state = this.STATE_ALTERNATE_OFF;
	    element.style.zIndex = element.oZIndex;
	    
	    var onComplete = (element.getAttribute("onClose") != undefined ? element.getAttribute("onClose") : (element.getAttribute("onclose") != undefined ? element.getAttribute("onclose") : element.onComplete));
		var attributes = new Array();
		attributes["tLeft"] = element.oLeft;
		attributes["tTop"] = element.oTop;
		attributes["tWidth"] = element.oWidth;
		attributes["tHeight"] = element.oHeight;
		attributes["tClass"] = element.oClass;
		attributes["onComplete"] = onComplete;
			    	
	    if (quickMode) {
	    	attributes["duration"] = 0;
	    }
	    
		this.animateElement(elementId, attributes);
    			
    } else {
    	log.error("element '" + elementId + "' is undefined", this);
	}
}

/**
 * Closes all animated DIVs in the specified groupName
 * @param {String} groupName			Name of the group
 * @param {String} pExceptionArray		Array containing the element IDs of elements to exclude
 * @param {String} isQuickMode			Avoid a closing animation, close in one frame
 */
AnimationController.prototype.resetAll = function(groupName, pExceptionArray, isQuickMode ) {

	if (groupName != undefined) {
	
		var groupList = this.groupMap[groupName];
		var exceptionList = "|" + ( pExceptionArray != undefined ? pExceptionArray : new Array() ).join("|") + "|";
		
	    // Close all other divs in the same groupList
	    if ( groupList != undefined ) {
	        for ( var i=0; i<groupList.length; i++) {
	        	if ( exceptionList.indexOf( "|" + groupList[i] + "|" ) == -1 ) {
		        	
		        	tmpAnimatedDiv = document.getElementById(groupList[i]);
		            if ( tmpAnimatedDiv.state == this.STATE_ALTERNATE_ON ) {
		            	
	            		this.reset(groupList[i], isQuickMode);
		            }
		        }
	        }
	    }                    
	}
}

/**
 * runs an element animation
 */
AnimationController.prototype.animateElement = function(elementId, attributes) {
	
	var element = document.getElementById(elementId);
	
	if (element != undefined && attributes != undefined) {
		
		attributes["sLeft"] = (attributes["sLeft"] != undefined ? attributes["sLeft"] : (!isNaN(parseInt(element.style.left)) ? parseInt(element.style.left) : element.oLeft));
		attributes["sTop"] = (attributes["sTop"] != undefined ? attributes["sTop"] : (!isNaN(parseInt(element.style.top)) ? parseInt(element.style.top) : element.oTop));
		attributes["sWidth"] = (attributes["sWidth"] != undefined ? attributes["sWidth"] : (!isNaN(parseInt(element.style.width)) ? parseInt(element.style.width) : element.oWidth));
		attributes["sHeight"] = (attributes["sHeight"] != undefined ? attributes["sHeight"] : (!isNaN(parseInt(element.style.height)) ? parseInt(element.style.height) : element.oHeight));

		attributes["sOpacity"] = (attributes["sOpacity"] != undefined ? attributes["sOpacity"] : element.getAttribute("sOpacity") ? element.getAttribute("sOpacity") : undefined);
		attributes["tOpacity"] = (attributes["tOpacity"] != undefined ? attributes["tOpacity"] : element.getAttribute("tOpacity") ? element.getAttribute("tOpacity") : undefined);

		// Recalculate sLeft and tLeft when using mLeft (move left)
		if (attributes["mLeft"] != undefined) {
			attributes["tLeft"] = attributes["sLeft"] + attributes["mLeft"];
		}
		
		// Recalculate sTop and tTop when using mTop (move top)
		if (attributes["mTop"] != undefined) {
			attributes["tTop"] = attributes["sTop"] + attributes["mTop"];
		}

		this._animate(
			elementId
			,attributes
			,true
		);	
	}
}

/**
 * Private method to execute the animation
 */
AnimationController.prototype._animate = function(elementId, animAttributes, isStartingCall) {

	var isTargetReached = true;
	var element = document.getElementById(elementId);
	
	if (element != undefined && (animAttributes != undefined || element._animationAttributes != undefined)) {
		
		var animAttributes = (animAttributes != undefined ? animAttributes : element._animationAttributes);
		
		//On first frame of animation, set the start time and frame index
		if (isStartingCall) {
			
			animAttributes["startAnimationTime"] = new Date().getTime();
			animAttributes["frameIndex"] = 0;
			
			// Create opacity object
			if (animAttributes["sOpacity"] != undefined 
					&& animAttributes["tOpacity"] != undefined 
					&& animAttributes["sOpacity"] != animAttributes["tOpacity"]) {

				animAttributes["cOpacity"] = animAttributes["sOpacity"];
				this.setOpacity(element, parseInt(animAttributes["cOpacity"]));
			}
							
			// position element as soure info requires
			if (animAttributes["sLeft"] != undefined 
					&& animAttributes["tLeft"] != undefined 
					&& animAttributes["sLeft"] != animAttributes["tLeft"]) {
				
				animAttributes["cLeft"] = parseInt(animAttributes["sLeft"]);
				element.style.left = animAttributes["cLeft"] + "px";
			}
			
			if (animAttributes["sTop"] != undefined 
					&& animAttributes["tTop"] != undefined 
					&& animAttributes["sTop"] != animAttributes["tTop"]) {
				
				animAttributes["cTop"] = parseInt(animAttributes["sTop"]);
				element.style.top = animAttributes["cTop"] + "px";
			}
			
			if (animAttributes["sWidth"] != undefined 
					&& animAttributes["tWidth"] != undefined 
					&& animAttributes["sWidth"] != animAttributes["tWidth"]) {
				
				animAttributes["cWidth"] = parseInt(animAttributes["sWidth"]);
				element.style.width = animAttributes["cWidth"] + "px";
			}
			
			if (animAttributes["sHeight"] != undefined 
					&& animAttributes["tHeight"] != undefined 
					&& animAttributes["sHeight"] != animAttributes["tHeight"]) {
				
				animAttributes["cHeight"] = parseInt(animAttributes["sHeight"]);
				element.style.height = animAttributes["cHeight"] + "px";
			}
		}
		
		if (animAttributes["duration"] == undefined) {
			animAttributes["duration"] = this.CYCLE_TIME;
		}
		
		animAttributes["frameIndex"]++;

		//Calculate average time to render a frame, remaining time for the animation and the remaining frames
		var averagetimePerFrame = (new Date().getTime() - animAttributes["startAnimationTime"]) / animAttributes["frameIndex"];
		if (averagetimePerFrame == 0) {
			averagetimePerFrame = 10;
		}
		
		var remainingTime = (animAttributes["startAnimationTime"] + animAttributes["duration"]) - new Date().getTime();
		var remainingFrames = remainingTime/averagetimePerFrame;
		
		//Clear thread handle
	    if (element.thread != undefined) {
	        clearTimeout(element.thread);
	    }
	
		if (animAttributes["cLeft"] != undefined) {
			var deltaLeft = (animAttributes["tLeft"]-animAttributes["sLeft"]) / remainingFrames;
			
		    if ( (deltaLeft > 0 && animAttributes["cLeft"] + deltaLeft < animAttributes["tLeft"]) 
			    	|| (deltaLeft < 0 && animAttributes["cLeft"] + deltaLeft > animAttributes["tLeft"]) ) {
				animAttributes["cLeft"] = animAttributes["cLeft"] + deltaLeft;
			    element.style.left = parseInt(animAttributes["cLeft"]) + "px";
		    	isTargetReached = false;
		    }
		}
		
		if (animAttributes["cTop"] != undefined) {
			var deltaTop = (animAttributes["tTop"]-animAttributes["sTop"]) / remainingFrames;
			
		    if ( (deltaTop > 0 && animAttributes["cTop"] + deltaTop < animAttributes["tTop"]) 
		    		|| (deltaTop < 0 && animAttributes["cTop"] + deltaTop > animAttributes["tTop"]) ) {
		    	animAttributes["cTop"] = animAttributes["cTop"] + deltaTop;
			    element.style.top = parseInt(animAttributes["cTop"]) + "px";
		    	isTargetReached = false;
		    }
		}
	
		if (animAttributes["cWidth"] != undefined) {
			var deltaWidth = (animAttributes["tWidth"]-animAttributes["sWidth"]) / remainingFrames;
		    
		    if (animAttributes["cWidth"] + deltaWidth < 0) {
		    	deltaWidth = animAttributes["cWidth"];
		    }
		    
		    if ( (deltaWidth > 0 && animAttributes["cWidth"] + deltaWidth < animAttributes["tWidth"]) 
		    		|| (deltaWidth < 0 && animAttributes["cWidth"] + deltaWidth > animAttributes["tWidth"]) ) {
		    	animAttributes["cWidth"] = animAttributes["cWidth"] + deltaWidth;
			    element.style.width = parseInt(animAttributes["cWidth"]) + "px";
		    	isTargetReached = false;
		    }
		}
	
		if (animAttributes["cHeight"] != undefined) {
			var deltaHeight = (animAttributes["tHeight"]-animAttributes["sHeight"]) / remainingFrames;
			
		    if (animAttributes["cHeight"] + deltaHeight < 0) {
		    	deltaHeight = animAttributes["cHeight"];
		    }
	
		    if ((deltaHeight > 0 && animAttributes["cHeight"] + deltaHeight < animAttributes["tHeight"]) 
			    	|| (deltaHeight < 0 && animAttributes["cHeight"] + deltaHeight > animAttributes["tHeight"]) ) {
				animAttributes["cHeight"] = animAttributes["cHeight"] + deltaHeight;
			    element.style.height = parseInt(animAttributes["cHeight"]) + "px";
		    	isTargetReached = false;
		    }
		}
		
		// Calculate opacity change
		if (animAttributes["cOpacity"] != undefined) {
		    				
			if (animAttributes["sOpacity"] < animAttributes["tOpacity"]) {
				animAttributes["cOpacity"] += (animAttributes["tOpacity"] - animAttributes["sOpacity"]) / remainingFrames;
			
			} else if (animAttributes["sOpacity"] > animAttributes["tOpacity"]) {
				animAttributes["cOpacity"] -= (animAttributes["sOpacity"] - animAttributes["tOpacity"]) / remainingFrames;
			}
			
			// Detect if the opacity target is reached
			if ((animAttributes["sOpacity"] < animAttributes["tOpacity"] && animAttributes["cOpacity"] < animAttributes["tOpacity"]) 
					|| (animAttributes["sOpacity"] > animAttributes["tOpacity"] && animAttributes["cOpacity"] > animAttributes["tOpacity"]) ) {
				this.setOpacity(element, parseInt(animAttributes["cOpacity"]));
				isTargetReached = false;
			}
		}

		element._animationAttributes = animAttributes;

	    // Check if reached the end of animation
		if (remainingFrames > 0 && !isTargetReached) {
	        element.thread = setTimeout(this.id+"._animate('"+elementId+"')", 10);
	
	    } else {
	        //TODO: Make sur calculation is perfect and avoid positionning at the end
	        
	        if (animAttributes["cLeft"] != undefined) {
		    	element.style.left = animAttributes["tLeft"] + "px";
	        }
	        
	        if (animAttributes["cTop"] != undefined) {
		    	element.style.top = animAttributes["tTop"] + "px";
	        }
	        
	        if (animAttributes["cWidth"] != undefined) {
		    	element.style.width = animAttributes["tWidth"] + "px";
	        }
	        
	        if (animAttributes["cHeight"] != undefined) {
		    	element.style.height = animAttributes["tHeight"] + "px";
	        }
	
	    	if (animAttributes["tClass"] != undefined) {
		    	element.className = animAttributes["tClass"];
		    }
		    
		    if (animAttributes["cOpacity"] != undefined) {
		    	this.setOpacity(element, animAttributes["tOpacity"]);
		    }

	    	// If an onComplete event is specified for the element, execute it.
	    	if (animAttributes["onComplete"] != undefined) {
	    		eval(animAttributes["onComplete"]);
	    	}
		}
	}
}

/**
 * Halts the element animation before the normal end
 */
AnimationController.prototype.stopElementAnimation = function(elementId) {
	
	var element = document.getElementById(elementId);
	if (element != undefined && element.thread != undefined) {
		clearTimeout(element.thread);
		element.thread = undefined;
	}
}

/**
 * Clears a group of element IDs
 */
AnimationController.prototype.clearGroup = function(groupName) {

	this.groupMap[groupName] = undefined;
}

/**
 * Registers a group of element IDs
 * @param {String} groupName		Name of the group
 * @param {Array} elementIdArray	Array containing the element Ids to add in the group
 */
AnimationController.prototype.registerGroup = function(groupName, elementIdArray) {

	this.groupMap[groupName] = elementIdArray;
}

/**
 * Changes the image source based on a state
 * @param {String} elementId	HTML element ID to affect
 * @param {String} attribute	key attribute to change
 * @param {String} value		value of the attribute to change
 */
AnimationController.prototype.setImageState = function(elementId, attribute, value) {

	var element = document.getElementById(elementId);

	if (element	!= undefined && element.getAttribute("src_token") != undefined) {

		// Extract the server prefix, filename and extension from the current src of the image
		var tmpArray = element.src.split("/");
		var fileExtension = "." + tmpArray[tmpArray.length-1].split(".")[1];
		var originalFilename = tmpArray.pop().split(".")[0];
		var filePrefix = tmpArray.join("/") + "/";
		var originalSrcArray = originalFilename.split("_");
		
		// Extract the filename from the token src
		var tmpArray = element.getAttribute("src_token").split("/");
		var tokenedSrcArray = tmpArray.pop().split(".")[0].split("_");

		// Replace the value of the token in the original src
		for (var i=0; i<tokenedSrcArray.length; i++) {
			if (tokenedSrcArray[i] == attribute) {
				originalSrcArray[i] = value;
			}
		}

		// Apply new src to image
		element.src = filePrefix + originalSrcArray.join("_") + fileExtension;
	}
}

/**
 *
 */
AnimationController.prototype.isOpen = function(elementId) {
	
	var element = document.getElementById(elementId);
	
	if (element != undefined && element.state == this.STATE_ALTERNATE_ON) {
		return true;
	} else {
		return false;
	}
}

/**
 * Zooms in an element with a specified center and ratio (1x, 2x, etc)
 * @param {String} elementId	Id of the HTMLElement to affect
 * @param {Integer} centerX		X position of the zooming point on the element
 * @param {Integer} centerY		Y position of the zooming poing on the element
 * @param {Integer} pRatio		Number of times to zoom (1=1X, 2=2X)
 */
AnimationController.prototype.scale = function(elementId, centerX, centerY, pRatio) {
	
	var element = document.getElementById(elementId);
	
	if (element != undefined) {
	
	    // Define the element attributes
	    if (element.isDefined == undefined ) {
	        this._define(element);
	    }
	    
		var tLeft = parseInt((element.oWidth/2)-(centerX*pRatio));
		var tTop = parseInt((element.oHeight/2)-(centerY*pRatio));
		
		// Re-position zoomed-in image if it goes over the boundaries of the view
		if ( tLeft > 0 ) { 
			tLeft = 0; 
		}
		if ( tTop > 0 ) {
			tTop = 0;
		}
		if ( tLeft < (element.oWidth*(pRatio-1)*-1) ) {
			tLeft = element.oWidth*(pRatio-1)*-1;
		} 
		if ( tTop < (element.oHeight*(pRatio-1)*-1) ) {
			tTop = element.oHeight*(pRatio-1)*-1;
		}
		
		var attributes = new Array();
		attributes["tLeft"] = tLeft;
		attributes["tTop"] = tTop;
		attributes["tWidth"] = element.oWidth*pRatio;
		attributes["tHeight"] = element.oHeight*pRatio;
		attributes["duration"] = this.CYCLE_TIME*2;

		this.animateElement(elementId, attributes);
	}
}

/**
 * Swaps between displayed and hidden state
 */
AnimationController.prototype.showAndHide = function(elementId) {
    
    // Getting a reference on the DIV element
    var element = document.getElementById(elementId);

    if (element != undefined) {
    	
    	if (element.style.display == "block") {
    		this.hide(elementId);
    	} else {
    		this.show(elementId);
    	}
	    
    } else {
    	log.error("element '" + elementId + "' is undefined", this);
    }	
}

/**
 * Shows an element
 * @param {String} elementId	ID of the html element to display
 */
AnimationController.prototype.show = function(elementId, isSmoothMode) {

	smoothMode = (isSmoothMode != undefined && isSmoothMode == true ? true : false);

	var element = document.getElementById(elementId);
	
	if (element != undefined) {
		if(smoothMode)
			element.style.cssText="";
		else
			element.style.display = "block";
		element.state = this.STATE_ALTERNATE_ON;
		
		var onComplete = (element.getAttribute("onOpen") != undefined ? element.getAttribute("onOpen") : (element.getAttribute("onopen") != undefined ? element.getAttribute("onopen") : element.onComplete));
		
		if (onComplete != undefined) {
			eval(onComplete);
		}
	}
}

/**
 * Shows an element
 * @param {String} elementId	ID of the html element to display
 */
AnimationController.prototype.hide = function(elementId) {

	var element = document.getElementById(elementId);
	
	if (element != undefined) {
		element.style.display = "none";
		element.state = this.STATE_ALTERNATE_OFF;
		
		var onComplete = (element.getAttribute("onClose") != undefined ? element.getAttribute("onClose") : (element.getAttribute("onclose") != undefined ? element.getAttribute("onclose") : element.onComplete));
		
		if (onComplete != undefined) {
			eval(onComplete);
		}
	}
}

/**
 * Sets the level of opacity for the HTML element
 * @param {HTMLElement} obj		HTML Element to set opacity on
 * @param {Integer} opacity		(0-100) value of the % of opacity 
 */
AnimationController.prototype.setOpacity = function(obj, opacity) {

	opacity = (opacity == 100)?99.999:opacity;
	
	if (obj != undefined) {
		// IE/Win
		obj.style.filter = "alpha(opacity:"+opacity+")";
		// Safari<1.2, Konqueror
		obj.style.KHTMLOpacity = opacity/100;
		// Older Mozilla and Firefox
		obj.style.MozOpacity = opacity/100;
		// Safari 1.2, newer Firefox and Mozilla, CSS3
		obj.style.opacity = opacity/100;
	}
}

/**
 * Returns the current opacity level for the specified HTML Element
 * @type Integer
 * @return (0-100) opacity percentage
 */
AnimationController.prototype.getOpacity = function(obj) {
	
	opacity = 0;

	if (obj != undefined) {
		if (obj.style.filter) {
			var filterString = obj.style.filter;
			opacity = parseInt(filterString.match(/opacity\:([^\)].*)\)/)[1]);
		} else if (obj.style.KHTMLOpacity) {
			opacity = parseInt(obj.style.KHTMLOpacity)*100;
		} else if (obj.style.MozOpacity) {
			opacity = parseInt(obj.style.MozOpacity)*100;
		} else if (obj.style.opacity) {
			opacity = parseInt(obj.style.opacity)*100;
		}
	}
		
	return opacity;
}

/**
 * Fades in the selected element (opacity 0-100)
 */
AnimationController.prototype.fade = function(elementId, sOpacity, tOpacity, onComplete, speed) {

	var attributes = new Array();
	attributes["sOpacity"] = sOpacity;
	attributes["tOpacity"] = tOpacity;
	attributes["duration"] = (speed != undefined ? speed : 300);
	attributes["onComplete"] = onComplete;
	
	this.animateElement(elementId, attributes);
}

/**
 * Fades in the selected element (opacity 0-100)
 */
AnimationController.prototype.fadeIn = function(elementId, onComplete, speed) {
	
	this.fade(elementId, 0, 100, onComplete, speed);
}

/**
 * Fades out the selected element (opacity 100-0)
 */
AnimationController.prototype.fadeOut = function(elementId, onComplete, speed) {

	this.fade(elementId, 100, 0, onComplete, speed);
}

/**
 * Animate a pulsing effect for the selected element
 * @param {String} elementId				ID of the HTML element to apply effect on
 * @param {Integer} minimalOpacity		Minimal opacity setting
 * @param {Integer} maximalOpacity		Maximal opacity setting
 * @param {Integer} speed					Speed setting (lower is faster)
 */
AnimationController.prototype.startPulse = function(elementId, minimalOpacity, maximalOpacity, speed) {

	minimalOpacity = (minimalOpacity != undefined ? minimalOpacity : 30);
	maximalOpacity = (maximalOpacity != undefined ? maximalOpacity : 100);
	speed = (speed != undefined ? speed : this.CYCLE_TIME);

	var element = document.getElementById(elementId);

	if (element != undefined) {
		
		var attributes = new Array();
		attributes["sOpacity"] = minimalOpacity;
		attributes["tOpacity"] = maximalOpacity;
		attributes["duration"] = speed;
		attributes["onComplete"] = this.id + ".startPulse('" + elementId + "', " + maximalOpacity + ", " + minimalOpacity + ", " + speed +")";
		
		this.animateElement(elementId, attributes);
	}
}

/**
 * Stops the pulsing animation of an element
 * @param {String} elementId				ID of the HTML element to apply effect on
 */
AnimationController.prototype.stopPulse = function(elementId) {

	var element = document.getElementById(elementId);
	
	if (element != undefined) {

		element._onComplete = undefined;
		
		// Cancel thread
		if (element.thread != undefined) {
			clearTimeout(element.thread);
			element.thread = undefined;
		}
		
		this.setOpacity(element, 100);
	}	
}

/**
 * Sets the image src attribute
 */
AnimationController.prototype.setImage = function(elementId, imageUrl) {
	
	var element = document.getElementById(elementId);
	
	if (element != undefined) {
		element.src = imageUrl;
	}
}

var Anim = new AnimationController("Anim");
