var Motate = Class.create();

	Motate.prototype = {

		classname: "Motate",

		version: "2.0b",
		
		initialize: function($container, $sourcelist, $background) {

			this.$currentSource = 0;
			this.$pollinginterval = 2;
			this.$delay = 8000;
			this.$sizer = null;
			this.$frameheight = 0;
			this.$framewidth = 0;
			this.$cached = [];
			this.$init = 0;
			
			/* quit if ANY arguments are not supplied */
			if ($container == null || $sourcelist == null || $background == null) {

				trace("missing required argument(s) for Motate, canceling instantiation");
				return false;

			} else {
			
				/* initialize variables */

 				// possibly cheaper just to use topframe and bottomframe here?
 				this.$frames = [];				
				this.$sources = [];
				this.$container = $($container);
				this.$containerParent = this.$container.ancestors()[0];
				
				/* apply background color */
				this.$container.setStyle({"backgroundColor":$background});

				this.parseSourceList($sourcelist);

				this.createUI();

				this.$pollFrameHeight = new PeriodicalExecuter(
					this.pollFrameHeight.bind(this),this.$pollinginterval
				);

				Event.observe(window, "resize", this.scaleit.bindAsEventListener(this));
	
			}

		},

		pollFrameHeight: function() {		
			/* check to make sure we don't already have a "good" value for frameheight -
				this should be anything non-zero, since frameheight will only be set
				from this function */
			if (this.$frameheight) {
				this.$pollFrameHeight.stop();
				this.doFramePositions();
			}

			if (this.$sizer) {
				var $height = this.$sizer.getDimensions()['height'];
				if ($height != "0") {
					this.$frameheight = $height;
					this.$framewidth = this.$sizer.getDimensions()['width'];
					this.$pollFrameHeight.stop();
					this.doFramePositions();
				} else {
					return false;
				}

			} else {
			
				var $contents = this.$container.descendants();
				var $height;
				$contents.each(
					function($el) {
						if ($el.tagName == "IMG") {
							this.$sizer = $el;
							$height = $el.getDimensions()['height'];
							if ($height != "0") {
								this.$frameheight = $height;
								this.$pollFrameHeight.stop();
								this.doFramePositions();
							} else {
								return false;
							}
						}
					}
					,this
				);
				
			}
		
		},

		createUI: function() {
		
			/* need to create and insert 2 divs to hold incoming content */
			var $tmp = document.createElement("DIV");
			$tmp.id = "motate2";
			this.$container.insert({"top":$tmp});

			$tmp = document.createElement("DIV");
			$tmp.id = "motate1";
			this.$container.insert({"top":$tmp});
			
			this.$frames['bottom'] = $("motate1");
			this.$frames['top'] = $("motate2");
			
			this.$frames['bottom'].setStyle({"opacity":"0"});
			this.$frames['top'].setStyle({"opacity":"0"});
			
			/* load the first source into top frame */
			this.loadContent(this.$frames['top'], this.$sources[0]);
		
		},
		
		initscale: function() {

			this.$width = this.$containerParent.getWidth();
			$position = this.$containerParent.cumulativeOffset();
			this.$frames['top'].setStyle("width:"+(this.$width-1)+"px");
			this.$frames['top'].setStyle("left:"+$position[0]+"px");
			this.$frames['bottom'].setStyle("width:"+(this.$width-1)+"px");
			this.$frames['bottom'].setStyle("left:"+$position[0]+"px");
			this.setFrameHeight(this.getContentHeight());

		},

		loadContent: function($div,$source) {
		
			/* check for cached content and insert if we have it */
			if (this.$cached[this.$currentSource]) {

				$div.update(this.$cached[this.$currentSource]);
				$div.setStyle({"opacity":"1"});
	
			} else {
	
				/* otherwise get content from source URL, 
					cache it for next call, and update requested frame */
			
				/* begin ajax post request */
				var $ajx = new Ajax.Request(
					$source,
						{
							method:'get',
							onFailure: function(response) {
								trace("ajax request failed");
								trace(enumerate(response));
								return false;
							},
							onComplete: function(response) {
								this.$cached.push(response.responseText);
								$div.update(response.responseText);
								$div.setStyle({"opacity":"1"});
								if (this.$init > 0) {
									this.$scaledelay = setTimeout(this.initscale.bind(this),500);
								} else {
									this.$init++;
								}
							}.bind(this)	
						}
					);
				/* end ajax post request */

			}
			
		},

		/* this function may now be redundant, or could be optimized
			or eliminated in light of getContentHeight and setFrameHeight
			below. I'm going to leave that for another day... */
		doFramePositions: function() {
		
			/*  - get dimensions of top (first loaded) frame
				- apply dimensions to container
				- absolutize both frames
				- match top position of bottom frame to top frame
				- probably need to remove loadContent call and use loadNext instead
			*/
			
			/* apply dims to container */
			this.$container.setStyle({"height":this.$frameheight+"px"});
			this.$container.setStyle({"marginBottom":"50px"});
			this.$container.setStyle({"marginTop":"-10px"});
			
			/* absolute position both frames */
			this.$frames['top'].absolutize();
			this.$frames['bottom'].absolutize();

			/* get top position of top frame */
			var $top = this.$frames['top'].getStyle("top");
			
			/* apply topframe "top" position to bottom frame */
			this.$frames['bottom'].setStyle({"top":$top});
			
			this.loadNext();

		},

		setFrameHeight: function($height) {
			this.$container.setStyle({"height":$height+"px"});
			this.$heightset = true;
		},
		
		getContentHeight: function() {
			var $contents = this.$container.descendants();
			return($contents.find(
				function($el) {
					if ($el.tagName == "IMG") {
						return true;
					}
				}.bind(this)
			)).getDimensions()['height'];
		},
		
		scaleit: function(e) {
		
			/* this fixes IE's onresize inifinite loop */
			if (this.$lastHeight) {
				if (this.$lastHeight == document.viewport.getHeight()) {
					return false;
				}
			} else {
				this.$lastHeight = document.viewport.getHeight();
			}
						
			/* clear all current timers / periodic executors */
			if (typeof(this.$timer)=="number") {
				clearTimeout(this.$timer);
				delete this.$timer;
			}
			
			if (typeof(this.$fader)=="object") {
				this.$fader.stop();
				delete this.$fader;
			}

			this.$width = this.$containerParent.getWidth();
			$position = this.$containerParent.cumulativeOffset();
			this.$frames['top'].setStyle("width:"+(this.$width-1)+"px");
			this.$frames['top'].setStyle("left:"+$position[0]+"px");
			this.$frames['bottom'].setStyle("width:"+(this.$width-1)+"px");
			this.$frames['bottom'].setStyle("left:"+$position[0]+"px");
			
			this.setFrameHeight(this.getContentHeight());
			
			this.reset();

		},

		loadNext: function() {
		
			/* load currentSource to top frame */
			this.loadContent(this.$frames['top'], this.$sources[this.$currentSource]);
			
			/* get next source */			
			if (this.$currentSource == this.$sources.length-1) {
				this.$currentSource = 0;
			} else {
				this.$currentSource++;
			}

			/* load currentSource to bottom frame */
			this.loadContent(this.$frames['bottom'], this.$sources[this.$currentSource]);
						
			/* call startFade in a few seconds */
			this.$timer = setTimeout(

				function() {
					this.startFade.call(this,arguments);
				}.bind(this)
			
				,this.$delay

			);
			
		},
		
		reset: function() {
			this.$sizer = null;
			delete this.$frameheight;
			this.restart();			
		},

		restart: function() {

			/* call startFade in a few seconds */
			this.$frames['top'].setStyle({"opacity":1});

			/* call startFade in a few seconds */
			this.$timer = setTimeout(

				function() {
					this.startFade.call(this,arguments);
				}.bind(this)
			
				,this.$delay

			);

		},
		
		startFade: function() {
			this.$fader = new PeriodicalExecuter(this.updateFrameOpacity.bind(this),10);
		},
		

		updateFrameOpacity: function() {
			var $temp = this.$frames['top'].getStyle("opacity");
			$temp = Math.round($temp*10)/10;
			if ($temp <= 0) {
				if (typeof(this.$fader)=="object") {
					this.$fader.stop();
					delete this.$fader;
				}
				this.loadNext();
			} else {
				this.$frames['top'].setStyle("opacity:"+($temp-.1));
			}
			return false;
		},
		
		parseSourceList: function($sourcelist) {		
			this.$sources = $sourcelist.split(',');
		}
	}

/*  END class definition */