/*	CloudGenerator Class and Cloud Class
 *	Author: Tim Dupree, tdupree.com
 *	Date: 3/3/2011
 *	License: MIT Open Source License
	The MIT License
	
	Copyright (c) 2011 Tim Dupree
	
	Permission is hereby granted, free of charge, to any person obtaining a copy
	of this software and associated documentation files (the "Software"), to deal
	in the Software without restriction, including without limitation the rights
	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the Software is
	furnished to do so, subject to the following conditions:
	
	The above copyright notice and this permission notice shall be included in
	all copies or substantial portions of the Software.
	
	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
	THE SOFTWARE.
 */

var CloudGenerator = new Class({
	// Implement the Events and Options utility classes
	Implements: [Events, Options],
	
	// Initialize our defualt values for the class options passed in
	options: {
		totalClouds:  10,		// Total number of clouds on screen at a given time (int)
		minDuration: 50000,		// Minimum travel time for a cloud across the screen (milliseconds)
		maxDuration: 12000,	// Maximum tracel time for a cloud across the screen (milliseconds)
		checkInterval: 10000,	// The interval used to check if new clouds are needed (milliseconds)
		autoStart: true,		// Automatically starts the cloud generator by default (bool)
		sky: $("sky"),			// Default sky target resides in an element named "sky" (element)
		cloudImg: "cloud.png",	// Define default cloud image (path/url)
		cloudDirection: 0,		// 0 = left to right, 1 = right to left (int)
		cloudWidth: 1088,		// Cloud width (px)
		cloudHeight: 323,		// Cloud height (px)
		cloudScales: [1, 0.8, 0.6, 1.2],	// Define an array containing the sizes the cloud will be scaled to (%)
		maxAltitude: 250, 		// This defines the vertical space you allow clouds to appear within the sky (px)
		cloudTransition: Fx.Transitions.linear	//Define the transition algorithm for the cloud movement
	},
	
	cloudCheck: null,			// Initialize the vairable to hold the setInterval declaration
	cloudsInSky: 0,				// Keep track of number of clouds in sky
	cloudSky: null,				// A reference to the cloudSky generated and injected into the sky element

	
	// Our constructor for the CloudGenerator class
	// It takes in the options passed to it and uses the implemented Options
	// utility class to modify any defualt options in our options object
	initialize: function(options){
		// Modify any defaults with the passed in options
		this.setOptions(options);
		
		// Create Cloud Sky
		this.cloudSky = new Element('div', {
			id: 'cloudSky',
			src: this.options.cloudImg,
			styles: {
				position: 'absolute',
				width: (this.options.sky.getDimensions().x + (2*this.options.cloudWidth)),
				left: -this.options.cloudWidth	
			}
		});
		
		// Place the cloud container within the sky
		// This lets us ensure that the clouds can smoothly enter and exit the 
		// boundaries of the sky element
		this.options.sky.grab(this.cloudSky);
		
		// autostat the cloud generator by default
		if(this.options.autoStart){
			this.startGenerator();
		}
	},
	
	// Check if there are less than the max number of clouds in the sky
	// If there is room, deploy another cloud, if not, do nothing
	deploy: function(){
		var cloudScale = (Math.floor(Math.random()*this.options.cloudScales.length));
		cloudScale = this.options.cloudScales[cloudScale];
		
		var cloudDuration = Math.floor(Math.random() * (this.options.maxDuration + 1 - this.options.minDuration)) 
							+ this.options.minDuration;
		
		var cloudAltitude = Math.floor(Math.random() * (this.options.maxAltitude - (cloudScale * this.options.cloudHeight)));
		
		if(this.cloudsInSky < this.options.totalClouds && !this.cloudsFull){
			this.cloudsInSky++;
			new Cloud({
				width: Math.floor(this.options.cloudWidth * cloudScale),
				height: Math.floor(this.options.cloudHeight * cloudScale),
				altitude: cloudAltitude,
				duration: cloudDuration,
				direction: this.options.cloudDirection,
				cloudImg: this.options.cloudImg,
				cloudTransition: this.options.cloudTransition,
				onComplete: function(){
					this.removeCloud();
				}.bind(this)
			});
		}
	},
	
	// Decrement cloudsInSky variable
	removeCloud: function(){
		if(this.cloudsInSky > 0){
			this.cloudsInSky--;
		}
	},
	
	// Stop the cloudGenerator
	stopGenerator: function(){
		clearInterval(this.cloudCheck);
	},
	
	// Start the cloudGenerator
	startGenerator: function(){
		this.deploy();
		this.cloudCheck = this.deploy.periodical(this.options.checkInterval, this);
	}
	
});


var Cloud = new Class({
	// Implement the Events and Options utility classes
	Implements: [Events, Options],
	
	cloudId: "",	// hold a reference to this cloud's DOM id property
	
	options: {
		duration: 4000,			// Duration of the clouds movement across the sky (milliseconds)
		direction: 0,			// Direction of the clouds movement, 0 = left to right and vice versa (int)
		altitude: 200,			// Altitude of the cloud in the sky
		width: 573,				// Width of the cloud (px)
		height: 262,			// Height of the cloud (px)
		cloudImg: "cloud.png",	// Cloud image (path/url)
		sky: $("cloudSky"),		// CloudSky element that the cloud will be injected into (element)
		cloudTransition: Fx.Transitions.linear	//Define the transition algorithm for the cloud movement
	},
	
	initialize: function(options){
		// modify any defaults with the passed in options
		this.setOptions(options);
		
		// Firefox is not getting the sky reference, lets check for null and reset the option
		if(this.options.sky === null){
			this.options.sky = $("cloudSky");
		}
		
		// create and animate the cloud element
		this.createCloud();
	},
	
	createCloud: function(){
		this.cloudId = 'cloud-' + (new Date().getTime());
		
		// determine if cloud will be moving left to right or right to left
		// the position cloud offscreen to begin movement
		var cloudStyle = { 
			position: 'absolute',
			top: this.options.altitude,
			width: this.options.width,
			height: this.options.height 
		};
		
		var skyPosition = 'upperRight'; // Move the cloud to the right, ignore the 'upper'
		var cloudEdge = 'upperLeft';	// Align the edge of the cloud to the edg edge of the sky
		
		// Determine the direction of the cloud and set styles and positions
		if(this.options.direction === 0){
			cloudStyle.left = (0 - this.options.width);
		}
		else {
			cloudStyle.right = (0 - this.options.width);
			skyPosition = 'upperLeft';
			cloudEdge = 'upperRight';
		}
		
		// Create the image element for the cloud
		var cloud = new Element('img', {
			id: this.cloudId,
			src: this.options.cloudImg,
			styles: cloudStyle
		});
		
		// Add the cloud image element to the cloudSky div
		this.options.sky.grab(cloud);
		
		// Move the cloud across the sky
		new Fx.Move(cloud, {
			relativeTo: this.options.sky,
			position: skyPosition,
			edge: cloudEdge,
			offset: {x: 0, y: this.options.altitude}, 
			duration: this.options.duration,
			transition: this.options.cloudTransition,
			onComplete: function(){
				this.complete();
			}.bind(this)
		}).start();
		
	},
	
	complete: function(){
		$(this.cloudId).destroy();	// Remove the cloud element from the DOM
		this.fireEvent('complete');	// fire the onComplete event, this is picked up
									// by the cloudGenerator class
	}
});


