/*
Script: CanvasUL.js
	Canvas Underlayer

License:
	MIT-style license.

Copyright:
	Copyright (c) Maksim Horbachevsky (http://fantactuka.net/)

Code & Documentation:
	http://fantactuka.net/canvasul/
*/

var CanvasUL = new Class({
	options: {
		x: 0,
		y: 0,
		glow: 0,
		shadow: 0,
		border: 0,
		width: 100,
		height: 100,
		corners: [5, 5, 5, 5],
		borderStartColor: [240, 240, 240, 1],
		borderStopColor: [240, 240, 240, 1],
		bodyStartColor: [255, 255, 255, 1],
		bodyStopColor: [255, 255, 255, 1],
		glowColor: [0, 0, 0],
		shadowColor: [0, 0, 0],
		gradientMode: 'vertical',
		zindex: -1
	},

	Implements: [Events, Options],

	initialize: function() {
		var params = Array.link(arguments, {'options': Object.type});
		this.setOptions(params.options || {});
		this.canvas = new Canvas({
			'class': 'canvasUnderlayer',
			'height': this.options.height,
			'width': this.options.width,
			'styles': {
				'position': 'absolute',
				'left': this.options.x,
				'top': this.options.y,
				'z-index': this.options.zindex
			}
		});
		
		$extend(this.options, {
			bodyWidth: this.options.width - this.options.glow - Math.max(this.options.glow, this.options.shadow),
			bodyHeight: this.options.height - this.options.glow - Math.max(this.options.glow, this.options.shadow)
		});

		/* Glow drawing. */
		if(this.options.glow > 0) {
			for(var i = 0; i < this.options.glow; i ++) {
				this.options.glowColor[3] = 0.2 / this.options.glow * i;
				this.drawRectangle({
					x: i,
					y: i,
					width: this.options.bodyWidth + (this.options.glow - i) * 2,
					height: this.options.bodyHeight + (this.options.glow - i) * 2,
					gradientStartColor: this.options.glowColor,
					gradientStopColor: this.options.glowColor,
					corners: this.options.corners.map(function(item) { return item + i + this.options.border }, this)
				});
			}
		}
		
		/* Shadow drawing. */
		if(this.options.shadow > 0) {
			for(var i = 0; i < this.options.shadow; i ++) {
				this.options.shadowColor[3] = 0.2 * (1 - i / this.options.shadow);
				this.drawRectangle({
					x: this.options.glow + 1 + i,
					y: this.options.glow + 1 + i,
					width: this.options.bodyWidth,
					height: this.options.bodyHeight,
					gradientStartColor: this.options.shadowColor,
					gradientStopColor: this.options.shadowColor,
					corners: this.options.corners.map(function(item) { return item + i + this.options.border }, this)
				});
			}
		}		
		
		/* Border drawing. */
		if(this.options.border > 0) {
			this.drawRectangle({
				x: this.options.glow,
				y: this.options.glow,
				width: this.options.bodyWidth,
				height: this.options.bodyHeight,
				gradientStartColor: this.options.borderStartColor,
				gradientStopColor: this.options.borderStopColor,
				corners: this.options.corners.map(function(item) { return item > 0 ? item + this.options.border : 0 }, this)
			});
		}
		
		/* Body drawing. */
		this.drawRectangle({
			x: this.options.glow + this.options.border,
			y: this.options.glow + this.options.border,
			width: this.options.bodyWidth - this.options.border * 2,
			height: this.options.bodyHeight - this.options.border * 2,
			gradientStartColor: this.options.bodyStartColor,
			gradientStopColor: this.options.bodyStopColor,
			corners: this.options.corners
		});

		return this.canvas;
	},
	
	drawRectangle: function(options) {
		var o = $merge(this.options, options);
		var c = this.canvas.getContext('2d');
		c.beginPath();
		if(o.gradientMode == 'vertical') { this.fillStyle = c.createLinearGradient(0, 0, 0, o.height); } 
		else { this.fillStyle = c.createLinearGradient(0, 0, o.width, 0); }
		this.fillStyle.addColorStop(0, this.getRGBA(o.gradientStartColor));
		this.fillStyle.addColorStop(1, this.getRGBA(o.gradientStopColor));
		c.fillStyle = this.fillStyle;
		c.moveTo(o.x + o.corners[0], o.y);
		c.lineTo(o.x + o.width - o.corners[1], o.y);
		c.quadraticCurveTo(o.x + o.width, o.y, o.x + o.width, o.y + o.corners[1]);
		c.lineTo(o.x + o.width, o.y + o.height - o.corners[2]);
		c.quadraticCurveTo(o.x + o.width, o.y + o.height, o.x + o.width - o.corners[2], o.y + o.height);
		c.lineTo(o.x + o.corners[3], o.y + o.height);
		c.quadraticCurveTo(o.x, o.y + o.height, o.x, o.y + o.height - o.corners[3]);
		c.lineTo(o.x, o.y + o.corners[0]);
		c.quadraticCurveTo(o.x, o.y, o.x + o.corners[0], o.y);
		c.fill();
	},
	
	getRGBA: function(rgba) {
		if(rgba.length == 3) return 'rgba(' + rgba.join(', ') + ', 1)';
		if(rgba.length == 4) return 'rgba(' + rgba.join(', ') + ')';
		return null
	}	
});


var CanvasULElemet = new Class({

	Implements: [Events, Options],
	
	Extends: CanvasUL,
	
	initialize: function() {
		var params = Array.link(arguments, {'element': $defined, 'options': Object.type});
		this.element = params.element;
		if(!['relative', 'absolute', 'fixed'].contains(this.element.getStyle('position'))) this.element.setStyle('position', 'relative');
		if(!params.options.width) params.options.width = this.element.getSize().x;
		if(!params.options.height) params.options.height = this.element.getSize().y;
		this.canvas = this.parent(params.options);
		this.canvas.inject(this.element, 'bottom');
		return this;
	}
	
});

Element.implement({
	
	CanvasULElemet: function(options) {
		var init = function() { 
			new CanvasULElemet(this, options);
		}.bind(this);
		
		if(Browser.Engine.trident4) init.delay(100, this);
		else init();
		
		return this;
	}
	
});