/**
 * 
 * @author Paul F. Gilzow, Web Communications, University of Missouri
 * @copyright 2008, Curators of the University of Missouri 
 * @version 0.1.1.2008.05.30
 * 
 * @param {String} strType The type of rotator to create: text or image.  Required.
 * @param {String} strElementID The ID of the element where the rotator should be.  Required.
 * @param {Array} objDataSource the array of items the rotator will rotate through.  Required.
 * @param {Boolean} boolRandom whether or not a random item should be selected to display at start up.  Default is false.  Optional.
 * @param {Integer} intDuration how long the transition effect should last (in milliseconds).  Default is 8 seconds.  Optional.
 * @param {Boolean} boolRotate whether or not they really want to rotate. Default is true.  Optional.
 * @param {Boolean} boolDebug whether or not to turn on debugging.  Default is true.  Optional.
 * @return void
 * 
 * @TODO can we change an effect's duration dynamically?  Seems overkill to have two separate effects when the only
 * difference is their duration.
 */
objMuRotator = new Class({
	/**
	 * 
	 * @param {Object} strType
	 * @param {Object} strElementID
	 * @param {Object} objDataSource
	 * @param {Object} boolRandom
	 * @param {Object} intDuration
	 * @param {Object} boolRotate
	 * @param {Object} boolDebug
	 */
	initialize:function(strType,strElementID,objDataSource,boolRandom,intDuration,boolRotate,boolDebug){
		window.addEvent('domready',function(){
			//set up the defaults
			this.name 				= new String('MU Rotator');
			this.strRotatorContainID= new String();
			this.objRotatorContainer= new Object();
			this.strRotatorID		= new String('mu-rotator');
			this.objRotator			= new Object();
			this.strFXID			= new String();
			this.intDuration 		= new Number(8000); // Isnt the duration passed in?
			this.intDelay			= new Number();
			this.debug 				= new Boolean(true); // Same here?
			this.rotatorType		= new String();
			this.currentItem		= new Number();
			this.datasource			= new Array();
			this.boolRandom			= new Boolean(true);
			this.boolRotate			= new Boolean(true);
			this.intStartIndex	 	= new Number(0);
			
			this.start(strType,strElementID,objDataSource,boolRandom,intDuration,boolRotate,boolDebug);		
		}.bind(this));	
	},
	
	/**
	 * 
	 * @param {Object} strType
	 * @param {Object} strElementID
	 * @param {Object} objDataSource
	 * @param {Object} boolRandom
	 * @param {Object} intDuration
	 * @param {Object} boolRotate
	 * @param {Object} boolDebug
	 */
	start:function(strType,strElementID,objDataSource,boolRandom,intDuration,boolRotate,boolDebug){
		//set up whether we are going to debug
		this.SetDebug(boolDebug);
		//determine the type of rotator we're going to create
		this.SetRotatorType(strType);
		//check to make sure the element exists and set our container
		this.SetRotatorContainer(strElementID);
		//check and set up our data source
		this.SetSource(objDataSource);
		//determine if they do or dont want a random item at start
		this.SetRandomStart(boolRandom);
		//determine if they want to change the duration time
		this.SetDuration(intDuration);
		//determine if they really want to rotate
		this.SetRotate(boolRotate);
		
		if(this.__errorsEncountered()){
			this.__buildErrors();	
		} else {
			//first we need to empty the container in case they put anything in there 
			this.objRotatorContainer.empty();
			this.objRotator = new Element('div',{id:this.strRotatorID});
			this.objRotatorContainer.appendChild(this.objRotator);
			
			//set up the initial first item value
			if(this.boolRandom){
				this.currentItem = $random(0,(this.datasource.length - 1));	
			} else {
				this.currentItem = 0;
			}
			
			switch(this.rotatorType){
				case 'text':
					this.objRotator.setHTML(this.datasource[this.currentItem].source);
					this.objEffect = this.objRotator;
					//this.strEffectID = this.strRotatorID;
					break;
				case 'image':
					this.strImageID = 'mu-rotator-image';
					
					this.objImage = new Element('img',{
						id:this.strImageID
					});
					
					this.__setImageContents(this.currentItem);							
					this.__setBackgroundImage(this.__getNextItem());
					this.objRotator.appendChild(this.objImage);

					this.objEffect = this.objImage;
					//this.strEffectID = this.strImageID;
					break;
			}
			
			//set up the effect for use later
			//alert('going to create the effect using the id ' + this.strEffectID);
			//alert('at line 245, bool rotate is set to ' + this.boolRotate);
			if(this.boolRotate){
				this.objFXOut = new Fx.Style(this.objEffect,'opacity',{duration:this.intDuration,transition: Fx.Transitions.Quart.easeInOut});
				//this.objFXOut = new Fx.Style(this.strEffectID,'opacity',{duration:this.intDuration,transition: Fx.Transitions.Quart.easeInOut});
				this.objFXOut.addEvent('onComplete',function(){
					this.UpdateRotator();
				}.bind(this));
				
				this.intDelay = this.intDuration * 1.5;
				//var intDelay = this.intDuration * 1.5;
				//this.UpdateRotator.periodical(this.intDelay,this);
				this.objFXOut.start.pass([1,0],this.objFXOut).periodical(this.intDelay,this);
				//this.objFXOut.start.periodical(this.intDelay,this,[1,0]);					
			}
			
		}			
	},
	
	UpdateRotator:function(){
		var intNextItem = this.__getNextItem();
		//update the current item
		this.currentItem = intNextItem;	
					
		switch(this.rotatorType) {
			case 'text':
				if(this.intDuration > 0){
					var intInDuration = this.intDuration/4;
				} else {
					var intInDuration = 0;
				}
				
				
				var objFXIn  = new Fx.Style(this.objEffect,'opacity',{duration:intInDuration,transition: Fx.Transitions.Quart.easeInOut});
										
				this.objRotator.setHTML(this.datasource[intNextItem].source);
				
				objFXIn.start(0,1);
				
				/*this.objFXOut.start(0,1);*/
				break;
			case 'image':
				/**
				 * this one is a bit more complex.  we need to set the source and alt of the main image now 
				 * that is has zero opacity.  Then we need to make it visible, and then set the background
				 * image of the rotator div to the next image 
				 */
				this.__setImageContents(intNextItem);
				//display the image
				this.objFXOut.set(1);
				//set the background to the next image
				this.__setBackgroundImage(this.__getNextItem());
				break;
		}			
	},
	
	SetRotatorContainer:function(strElementID){
		if($chk($(strElementID))){
			this.strRotatorContainID = strElementID;
			this.objRotatorContainer = $(strElementID);	
		} else {
			this.__recordError('The ID you gave me for the Rotator does not exist or is invalid.');
		}	
	},
	
	SetRotatorType:function(strType){
		strErrMsg = 'I was unable to determine what type of Rotator you want me to build.';
		if($type(strType) == 'string' && strType != ''){
			switch(strType.toLowerCase()){
				case 'image':
					this.rotatorType = 'image'; 
					break;
				case 'text':
					this.rotatorType = 'text';
					break;
				default:
					this.__recordError(strErrMsg);
					break;
			}
		} else {
			this.__recordError(strErrMsg);	
		}	
	},
	
	SetSource:function(objDataSource){
		var datatype = $type(objDataSource);
		if((datatype != 'object' && datatype != 'array') || objDataSource.length < 1){
			this.__recordError('Either the data source is missing or is not of the correct type.');		
		} else {
			//we need to make sure that each item in the array has a source property
			var boolOk = new Boolean(true);
			$each(objDataSource,function(val,key){
				if(!$chk(val.source)){
					boolOk = false;
				}	
			});
			
			if(boolOk){
				this.datasource = objDataSource;
			} else {
				strErrMsg = 'The Data Source does not appear to be formatted correctly.  Please make sure it follows the '
					+ 'correct format.';
				this.__recordError(strErrMsg);
			}
		}		
	},
	
	SetRandomStart:function(boolRandom){
		if($defined(boolRandom)){
			this.boolRandom = this.__retrieveBooleanValue(boolRandom);
		}	
	},
	
	SetDuration:function(intDuration){
		if($chk(intDuration) && intDuration != ''){
			switch($type(intDuration)){
				case 'number':
					this.intDuration = intDuration.toInt();//make sure it is an integer
					break;
				case 'string':
					if(isNaN(intDuration.toInt())){
						this.__recordError('You attempted to set a new delay, but what you gave me is not a valid number.');	
					} else {
						this.intDuration = intDuration.toInt();
					}
					break; 
			}
		}
	},
	
	/**
	 * Sets the Debug property
	 * @param {Mixed} boolDebug can be a boolean or string
	 */
	SetDebug:function(boolDebug){
		// first we need to see if they do or do not want to debug
		if($defined(boolDebug)){
			//if they left it blank, then we'll just leave the default of true
			this.debug = this.__retrieveBooleanValue(boolDebug);
		}				
	},
	
	SetRotate:function(boolRotate){
		//if it isnt defined, we'll keep the default
		if($defined(boolRotate)){
			this.boolRotate = this.__retrieveBooleanValue(boolRotate);
		}
	},
	
	__setImageContents:function(intIndex){
		//first set the image src
		this.objImage.setProperty('src',this.datasource[intIndex].source);
		//now set the alt if it is available
		if($chk(this.datasource[intIndex].alt)){
			this.objImage.setProperty('alt',this.datasource[intIndex].alt);
		}				
	},
	
	/**
	 * Sets the background-image CSS property of the Rotator Div
	 * @param {Integer} intIndex The index of the datasource to use
	 */
	__setBackgroundImage:function(intIndex){
		var strURL = 'url(\'' +  + '\');';
		//alert('attempt to set background image to ' + strURL);
		//this.objRotator.setStyle('background-image',strURL);
		this.objRotator.style.backgroundImage = "url('" + this.datasource[intIndex].source + "')";			
	},
	
	/**
	 * @return {Integer} the next index value
	 */
	__getNextItem:function(){
		if((this.currentItem + 1) >= this.datasource.length){
			return 0;	
		} else {
			return this.currentItem + 1;
		}	
	},
	
	__buildContainter:function(){
		
	},
	
	__retrieveBooleanValue:function(mxTest){
		switch($type(mxTest)) {
			case 'string':
				switch(mxTest.toLowerCase) {
					case 'false':
						return false;
						break;
					case 'true':
						return true;
						break;
				}
				break;
			case 'boolean':
				return mxTest;
				break;
		}

	},
	

	/**
	 * Sets an error message in our error reporter
	 * @param {String} strErrMsg the error message we want to record
	 */
	__recordError:function(strErrMsg){
		//we'll only worry about recording errors if we are debugging
		if(this.debug){
			//if we havent created our error reporter, then we need to do that
			if(!$chk(this.errorreport)){
				this.__setUpErrorReporter();
			}
			
			this.errorreport.RecordError(strErrMsg);
		}
	},
	
	/**
	 * Sets up our error reporter and sets the Error Entry Message text
	 * @TODO reword the error message and general update
	 */
	__setUpErrorReporter:function(){
		if(typeof(objErrorReporter)!= 'undefined'){
			this.errorreport = new objErrorReporter();
			this.errorreport.SetErrorHeader(this.errMsgHeaderText);
			
			if(this.strRotatorContainID != ''){
				var strErrorMsgEntry =  this.errMsgIntroText + ' for the textarea ' + this.objToObserveID;	
			} else {
				var strErrorMsgEntry = this.errMsgIntroText + ' for unknown textarea ID';
			}
			
			this.errorreport.SetErrorEntryMsg(strErrorMsgEntry);								
		} else {
			strText = 'I have encountered errors while setting up the ' + this.name + '.  However, the code for the Error '
				+ 'Reporter is missing or unavailable.  You will need to either include the Error Reporter code, or debug '
				+ 'these issues manually.';
			alert(strText);
		}
		
	},
	
	/**
	 *  Indicates if an error was encountered
	 *  @return {Boolean} whether or not errors were encountered 
	 */
	__errorsEncountered:function(){
		if(this.debug && $chk(this.errorreport)){
			return this.errorreport.ErrorsEncountered();	
		} else {
			return false;
		}
	},

	/**
	 *  Instructs the Error Reporter to display Errors
	 */
	__buildErrors:function(){
		this.errorreport.DisplayErrors();
	}				
});