function Point(x, y) {
	this.x = x;
	this.y = y;
	return this;
}

var fps = 24;
//---
var fl = 1000.0 / fps;
var twoPi = 6.28318;
var staticScene = new Image();
staticScene.src = '/gennth-theme/images/intro/phase6.png';

var Sprite = function() {
	
	function init(height, options) {
		if (!height) return this;
		if (!options || !options.url) return this;
		
		this.done = false;
		this.ready = false;
		this.frame = 0;
		this.realFrame = 0;
		this.image = new Image();
		this.image.parent = this;
		this.image.onload = function() { this.parent.ready = true; };
		this.image.src = options.url;
		this.canvasHeight = height;
		this.duration = 500;
		this.elapsed = 0;
		this.delay = 0;
		this.position = new Point(0,0);
		if (options.position) {
			this.position.x = options.position.x;
			this.position.y = options.position.y;
		}
		this.startPosition = new Point(this.position.x, this.position.y);
		this.endPosition = new Point(0,0);
		if (options.endPosition) {
			this.endPosition.x = options.endPosition.x;
			this.endPosition.y = options.endPosition.y;
		}
		
		this.path = function(frame) { return new Point(this.position.x, this.canvasHeight - (this.endPosition.y * (frame * fl / this.duration))); };
		if (options.path)
			this.path = options.path;
		
		this.repeats = false;
		if (options.repeats)
			this.repeats = options.repeats;
		
		this.frameCount = 10;
		if (options.frameCount) 
			this.frameCount = options.frameCount;
		
		if (options.duration) {
			this.duration = options.duration;
		}
		
		if (options.delay) {
			this.delay = options.delay;
		}
		
		return this;
	}
	
	function draw(context) {
		if (this.ready == true) {
			if (this.done == false) {
				if ((this.realFrame * fl) >= this.delay) {
					this.elapsed = this.frame * fl;
					this.frame++;
					if (this.path) 
						this.position = this.path(this.elapsed);
				}
				this.realFrame++;				
				
				if (this.elapsed >= this.duration) {
					if (this.repeats == true) {
						this.elapsed = 0;
						this.frame = 0;
					} else {
						this.done = true;
						this.position = this.endPosition;
					}
				}
			}
			context.drawImage(this.image, this.position.x, this.position.y);
		}
		return this.done;
	}
	return {
		init: init,
		draw: draw
	};
}; // end Sprite.

var WiggleSprite = function() {
	function init(height, options) {
		if (!height) return this;
		if (!options || !options.url) return this;
		
		this.done = false;
		this.ready = false;
		this.frame = 0;
		this.realFrame = 0;
		this.image = new Image();
		this.image.parent = this;
		this.image.onload = function() { this.parent.ready = true; };
		this.image.src = options.url;
		if (options.transitionImg) {
			this.transitionImg = new Image();
			this.transitionImg.src = options.transitionImg;
			this.transitionImg.parent = this;
			this.transitionImg.onload = function() { this.parent.ready = true; }
		}
		this.canvasHeight = height;
		this.duration = 500;
		this.elapsed = 0;
		this.delay = 0;
		this.position = new Point(0,0);
		this.pathIndex = 0;
		if (options.position) {
			this.position.x = options.position.x;
			this.position.y = options.position.y;
		}
		this.startPosition = new Point(this.position.x, this.position.y);
		this.endPosition = new Point(0,0);
		if (options.endPosition) {
			this.endPosition.x = options.endPosition.x;
			this.endPosition.y = options.endPosition.y;
		}
		
		this.paths = new Array();
		
		this.path = function(frame) { return new Point(this.position.x, this.canvasHeight - (this.endPosition.y * (frame * fl / this.duration))); };
		if (options.path)
			this.path = options.path;
		
		this.repeats = false;
		if (options.repeats)
			this.repeats = options.repeats;
		
		this.frameCount = 10;
		if (options.frameCount) 
			this.frameCount = options.frameCount;
		
		if (options.duration) {
			this.duration = options.duration;
		}
		
		if (options.delay) {
			this.delay = options.delay;
		}
		
		if (options.paths) {
			this.paths = options.paths;
			this.path = this.paths[0].path;
			this.endPosition = this.paths[0].endPosition;
			this.duration = this.paths[0].duration;
			
			for (var i = 0; i < this.paths.length; i++) {
				if (! this.paths[i].delay) {
					this.paths[i].delay = 0;
				}
			}
			this.delay = this.paths[0].delay;
		} else {
			this.paths.push({path:this.path, endPosition: this.endPosition, duration: this.duration, delay: this.delay });
		}
		
		return this;
	}
	
	function draw(context) {
		var currImg = this.transitionImg != undefined ? this.transitionImg : this.image;
		if (this.ready == true) {
			if (this.done == false) {
				if ((this.realFrame * fl) >= this.delay) {
					this.elapsed = this.frame * fl;
					this.frame++;
					if (this.path) 
						this.position = this.path(this.elapsed);
				}
				this.realFrame++;				
				
				if (this.elapsed >= this.duration) {
					if (this.pathIndex < this.paths.length-1) {
						this.path = this.paths[++this.pathIndex].path;
						this.startPosition = this.endPosition;
						this.position = this.endPosition;
						this.endPosition = this.paths[this.pathIndex].endPosition;
						this.duration = this.paths[this.pathIndex].duration;
						this.delay =  this.paths[this.pathIndex].delay;
						this.frame = 0;
					} else if (this.repeats == true) {
						this.elapsed = 0;
						this.frame = 0;
					} else {
						//if (console) console.debug('wiggle sprite done.');
						this.done = true;
						this.position = this.endPosition;
						currImg = this.image;
						this.transitionImg = null;
					}
				}
			}
			//if (console && this.image.src == 'http://72.44.219.139/gennth-theme/images/intro/phase2-4.png') console.debug(this.position.x+','+this.position.y+' @ '+ this.elapsed);
			context.drawImage(currImg, this.position.x, this.position.y);
		}
		return this.done;
	}
	return {
		init: init,
		draw: draw
	};
} // end WiggleSprite.

var FadeIn = function() {
	function init(options) {
		if (!options || !options.url) return this;
		
		this.done = false;
		this.ready = false;
		this.frame = 0;
		this.realFrame = 0;
		this.image = new Image();
		this.image.parent = this;
		this.image.onload = function() { this.parent.ready = true; };
		this.image.src = options.url;
		this.duration = 500;
		this.elapsed = 0;
		this.delay = 0;
		this.opacity = 0;
		this.position = new Point(0,0);
		if (options.duration) {
			this.duration = options.duration;
		}
		
		if (options.delay) {
			this.delay = options.delay;
		}
		return this;
	}
	
	function draw(context) {
		if (this.ready == true) {
			if (this.done == false) {
				if ((this.realFrame * fl) >= this.delay) {
					this.elapsed = this.frame * fl;
					this.frame++;
					this.opacity = this.elapsed / this.duration;
				}
				this.realFrame++;				
				
				if (this.elapsed >= this.duration) {
					if (this.repeats == true) {
						this.elapsed = 0;
						this.frame = 0;
					} else {
						this.done = true;
						this.opacity = 1.0;
						
					}
				}
			} // done == false
			context.save();
			context.globalAlpha = this.opacity; 
			context.drawImage(this.image, this.position.x, this.position.y);
			context.restore();
		}
		return this.done;
	}
	return {
		init:init,
		draw:draw
	};
};

var GlowSprite = function() {
	function init(options) {
		if (!options || !options.url) return this;
		
		this.done = false;
		this.ready = false;
		this.frame = 0;
		this.realFrame = 0;
		
		this.image = new Image();
		this.image.parent = this;
		this.image.onload = function() { this.parent.ready = true; };
		this.image.src = options.url;
		
		this.duration = 500;
		this.pauseBetweenRepeats = 0;
		this.elapsed = 0;
		this.delay = 0;
		this.opacity = 0;
		this.position = new Point(0,0);
		this.maxRepeats = 0;
		this.repeatCount = 0;
		
		if (options.duration) {
			this.duration = options.duration;
		}
		
		if (options.pauseBetweenRepeats) {
			this.pauseBetweenRepeats = options.pauseBetweenRepeats;
		}
		
		if (options.delay) {
			this.delay = options.delay;
		}
		if (options.position) {
			this.position = options.position;
		}
		
		this.repeats = false;
		if (options.repeats)
			this.repeats = options.repeats;		
			
		if (options.maxRepeats) {
			this.maxRepeats = options.maxRepeats;
		}
		
		return this;
	}
	
	function draw(context) {
		if (this.ready == true && context) {
			if (this.done == false) {
				if ((this.realFrame * fl) >= this.delay) {
					this.elapsed = this.frame * fl;
					this.frame++;
					
					// Determine the opacity.
					var opa = Math.sin(this.elapsed / this.duration * 180 * Math.PI / 180.0);
					this.opacity = Math.abs(opa);
				}
				this.realFrame++;
				
				if (this.elapsed >= this.duration) {
					if (this.repeats == true) {
						this.opacity = 0;
						
						if (this.maxRepeats > 0) {
							if (this.repeatCount >=  this.maxRepeats) {
								this.done = true;
								this.opacity = 0.0;
							}
						}
						
						if (this.elapsed >= (this.duration+this.pauseBetweenRepeats)) {
							this.elapsed = 0;
							this.frame = 0;
							this.repeatCount += 1;
						}
						
					} else {
						this.done = true;
						this.opacity = 0.0;
						
					}
				}
			} // done == false
			
			if (this.opacity > 0) {
				context.save();
				context.globalAlpha = this.opacity; 
				context.drawImage(this.image, this.position.x, this.position.y);
				context.restore();
			}
		}
		return this.done;
	}
	
	function stop() {
		this.elapsed = this.duration + this.pauseBetweenRepeats;
		this.draw();
	}
	
	return {
		init:init,
		draw:draw,
		stop:stop
	};
};

var GlowFadeSprite = function() {
	function init(options) {
		if (!options || !options.url || !options.fadeUrl) return this;
		
		this.done = false;
		this.ready = false;
		this.frame = 0;
		this.realFrame = 0;
		
		this.glowImage = new Image();
		this.glowImage.parent = this;
		this.glowImage.onload = function() { this.parent.ready = true; };
		this.glowImage.src = options.url;
		this.fadeImage = new Image();
		this.fadeImage.parent = this;
		this.fadeImage.onload = function() { this.parent.ready = true; };
		this.fadeImage.src = options.fadeUrl;
		
		this.image = this.glowImage;
		
		this.duration = 500;
		this.pauseBetweenRepeats = 0;
		this.elapsed = 0;
		this.delay = 0;
		this.opacity = 0;
		this.position = new Point(0,0);
		if (options.duration) {
			this.duration = options.duration;
		}
		
		if (options.pauseBetweenRepeats) {
			this.pauseBetweenRepeats = options.pauseBetweenRepeats;
		}
		
		if (options.delay) {
			this.delay = options.delay;
		}
		if (options.position) {
			this.position = options.position;
		}
		
		this.repeats = false;
		if (options.repeats)
			this.repeats = options.repeats;		
		
		return this;
	}
	
	function draw(context) {
		if (this.ready == true) {
			if (this.done == false) {
				if ((this.realFrame * fl) >= this.delay) {
					this.elapsed = this.frame * fl;
					this.frame++;
					
					// Determine the opacity.
					if (this.elapsed >= this.duration) {
						this.opacity = 0.0;
						
					} else { // still running.
						
						var opa = Math.sin(this.elapsed / this.duration * 360 * Math.PI / 180.0);
						this.opacity = Math.abs(opa);
						
						if (opa < 0) {
							this.image = this.fadeImage;
						}
					}
				}
				this.realFrame++;				
				
				if (this.elapsed >= this.duration + this.pauseBetweenRepeats) {
					if (this.repeats == true) {
						this.elapsed = 0;
						this.frame = 0;
						this.image = this.glowImage;
						this.opacity = 0;
					} else {
						this.done = true;
						this.opacity = 0.0;
						
					}
				}
			} // done == false
			
			if (this.opacity > 0) {
				context.save();
				context.globalAlpha = this.opacity; 
				context.drawImage(this.image, this.position.x, this.position.y);
				context.restore();
			}
		}
		return this.done;
	}
	return {
		init:init,
		draw:draw
	};
};

var Scene = function() { 
	function init(canvasId, sprites, options) {
		if (!canvasId) return this;
		if (!sprites) return this;
		this.name = options.name;
		this.callback = options.callback;
		this.clearBeforeDrawing = true;
		if (options.clearBeforeDrawing != undefined) {
			this.clearBeforeDrawing = options.clearBeforeDrawing;
		}
		this.onFinish = options.onFinish;
		this.canvas = document.getElementById(canvasId);
		this.doubleBuffer = false;
		if (options.doubleBuffer) {
			this.doubleBuffer = options.doubleBuffer;
		}
		this.backBuf = document.getElementById('backbuffer');
		this.canvases = [this.canvas, this.backBuf];
		this.currBuffer = 0;
		if (this.doubleBuffer == true) {
			this.currBuffer = 1;
		}		
		this.context = this.canvases[this.currBuffer].getContext('2d');
		this.sprites = sprites;
		this.imageData = null;this.context.getImageData(0, 0, this.canvas.width, this.canvas.height);
		return this;
	}
	function draw() {
		//console.debug('drawing ' + this.name);
		if (this.clearBeforeDrawing == true) {
			//console.debug('clearing canvas ' + this.name);
			this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
		} else if (this.imageData) {
			this.context.putImageData(this.imageData, 0, 0);
		}
		
		var done = true;
		for (var i = 0; i < this.sprites.length; i++) {
			var spriteDone = this.sprites[i].draw(this.context);
			// Ignore repeating sprites in the done calculation.
//			if (this.sprites[i].repeats == true) spriteDone = true;
			done = spriteDone && done;
		}
		
		/*if (this.doubleBuffer == true) {
			this.canvases[1-this.currBuffer].style.visibility='hidden';
			this.canvases[this.currBuffer].style.visibility='visible';
			this.currBuffer = 1 - this.currBuffer;
			this.context = this.canvases[this.currBuffer].getContext('2d');
		}*/
		
		if (done == true && this.timer) {
			//if (console) console.debug('scene ' + this.name + ' is ending');
			this.context = this.canvas.getContext('2d');
			//this.backBuf.style.visibility='hidden';
			//this.canvas.style.visibility='visible';
			this.stop();
			if (this.callback) this.callback(this.name);
			
			if (this.onFinish) {
				this.onFinish(this.name);
			}
		}
		return done;
	}
	function start() {
		//if (console) console.debug('starting scene ' + this.name);
		this.timer = setInterval(this.name+".draw();", fl);
	}
	
	function stop() {
		if (this.timer) {
			//if (console) console.debug('stopping scene ' + this.name);
			clearInterval(this.timer);
			this.timer = null;
			for (i = 0; i < this.sprites.length; i++) {
				this.sprites[i].elapsed = this.sprites[i].duration;
				if (this.sprites[i].stop) {
					this.sprites[i].stop();
				}
			}
			this.draw();
		}
	}
	
	function isRunning() {
		return this.timer != null;
	}
	
	return {
		init:init,
		draw:draw,
		start:start,
		stop:stop,
		isRunning:isRunning
	};
}; // end Scene.

function pulseDegree(semaphore) {
	if (semaphore) {
		jQuery('#degree-glow').fadeIn(500, "linear", function() {
			jQuery('#degree-glow').fadeOut(500, "linear", function() { 
				pulseDegree(semaphore-1); 
			});
		});
	}
}
