/**
 * Cactusbunker Framework
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Open Software License (OSL 3.0)
 * that is bundled with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://opensource.org/licenses/osl-3.0.php
 *
 * @category   Cactusbunker
 * @package    Cactusbunker
 * @copyright  Copyright (c) 2009 Cactusbunker Inc. Cactusbunker (http://www.cactusbunker.com)
 * @license    http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
 * @version    $Id: library.js 20 2010-04-21 18:26:45Z Andy $
 */

var Profiler = new Log();
Profiler.enableLog();

/**
 * Setup default namespace.
 */
if ($type(Cactusbunker) === false) {
	var Cactusbunker = {
		Version: "0.1.1"
	};
};

/**
 * Methods to extend the window object.
 */
Window.implement({

	/**
	 * Get information about an object.
	 *
	 * @access public
	 * @param Object array
	 * @param Boolean output
	 * @return void|string
	 */
	dump: function(obj, output)
	{    
		// Initialize the variables
		var output_string = "";
		var spacer = " ";
		var indent = 4;
		var output = output || false;
		
		// Internal function for formatting arrays/objects
		var formatObject = function(obj, depth, indent, spacer)
		{
			// Check the current depth
			if (depth > 0)
			{
				depth++;
			}
			
			// Initialize the string and padding variables
			var base_pad = repeat_char(indent * depth, spacer);
			var thick_pad = repeat_char(indent * (depth + 1), spacer);
			var str = "";
			
			// Check for objects
			if (obj instanceof Object)
			{
				str += $type(obj).ucfirst() + "\n" + base_pad + "(\n";
				
				// Loop through the object properties
				for (var key in obj)
				{
					switch ($type(obj[key]))
					{
						// Check for nested arrays
						case 'array':
							// Recurse through the array properties
							str += thick_pad + "[" + key + "] => " + formatObject(obj[key], depth + 1, indent, spacer);
						break;
						
						// Check for nested objects
						case 'object':
							// Recurse through the object properties
							str += thick_pad + "[" + key + "] => " + formatObject(obj[key], depth + 1, indent, spacer);
						break;
						
						// Check for functions
						case 'function':
							// Add the function
							str += thick_pad + "[" + key + "] => " + formatFunction(obj[key], depth + 1, indent, spacer);
						break;
						
						// Just add the property
						default:
							// Add the property
							str += thick_pad + "[" + key + "] => " + obj[key] + "\n";
						break;
					}
				}
				
				str += base_pad + ")\n";
			
			}
			// Check if the object is null
			else if (obj == null || obj == undefined)
			{
				str = "\n";
			}
			// Run the object's default toString method
			else
			{
				str = obj.toString();
			}
			
			return str;
		};
		
		var formatFunction = function(obj, depth, indent, spacer)
		{
			// Check the current depth
			if (depth > 0)
			{
				depth++;
			}
			
			// Initialize the string and padding variables
			var base_pad = repeat_char(indent * depth, spacer);
			var thick_pad = repeat_char(indent * (depth + 1), spacer);
			
			// Start the function declaration
			var str = "Function\n" + base_pad + "(\n";
			
			// Get the function definition and split into lines
			var lines = obj.toString().split("\n")
			
			// Loop through the lines and format them
			for (var i = 0; i < lines.length; i++)
			{
				str += thick_pad + lines[i] + "\n";
			}
			
			// End the function declaration
			str += base_pad + ")\n";
			
			return str;
		};
		
		// Internal string padding function
		var repeat_char = function(len, spacer)
		{
			var str = "";
			
			for (var i = 0; i < len; i++)
			{
				str += spacer;
			}
			
			return str;
		};
		
		// Get the output string
		output_string = formatObject(obj, 0, indent, spacer);
		
		// Should we output the result directly?
		if (output === true)
		{
			document.write("<pre>" + output_string + "</pre>");
			return true;
		}
		else
		{
			return output_string;
		}
	}
});

/**
 * Methods to extend the string object.
 */
String.implement({

	/**
	 * Capitalize the first letter of the string.
	 *
	 * @return string
	 */
	ucfirst: function()
	{
		return this[0].toUpperCase() + this.substring(1);
	},

	/**
	 * Convert newline characters to html <br /> in a string.
	 *
	 * @return string
	 */
	nl2br: function()
	{
		return this.replace(/\n/g, "<br />");
	}
});

/**
 * Mutator to provide protected properties and methods in classes.
 */
Class.Mutators.Protected = function(items){
	
	$each(items, function(fn, index){
		if ($type(fn) == 'function' && !fn._protected){
			fn.protect();
		}
	});
	
	this.implement(items);
};

Cactusbunker.Fx = {};

/**
 * A text ticker widget.
 *
 * @author Andy Cox <andy@cactusbunker.com>
 */
Cactusbunker.Fx.Ticker = new Class({
	
	Extends: Fx,

	/**
	 * Various options to alter functionality.
	 */
	options: {
		cssClass: 'fxTickerLink',
		duration: 5000,
		delay: 50,
		tickOne: '_',
		tickTwo: '-'
	},

	/**
	 * Class constructor.
	 * @param HTML Element element
	 * @param object options
	 * @return void
	 */
	initialize: function(element, options)
	{
		this.element = this.subject = $(element);
		this.parent(options);
		this.index = -1, this.items = [], this.length = 0;
		
		// Get any links from within the ticker html element
		this.element.getElements('a').each((function(item){
			this.addItem(item.get('html'), item.get('href'));
		}).bind(this));
		
		// Clear the html from the ticker element
		this.element.empty();
		
		// Create a container for the ticker text
		this.container = new Element('div').inject(this.element);
		
		// Create the link element
		this.link = new Element('a', {
			'class': this.options.cssClass,
			'styles': {
				'outline': 'none'
			}
		}).inject(this.container);
	},
	
	/**
	 * Add items to display in the ticker.
	 * @param string title
	 * @param string link
	 * @return void
	 */
	addItem: function(title, link)
	{
		this.items.push({title: title, link: link});
	},
	
	/**
	 * Start the ticker running.
	 * @return void
	 */
	start: function()
	{
		// Initialize the new link
		if (this.length === 0)
		{
			this.index++;
			this.index = this.index % this.items.length;
			this.title = this.items[this.index].title.replace(/&quot;/g, '"');
			this.link.set('href', this.items[this.index].link);
		}
		
		// Add the current ticker text into the link
		this.link.set('html', this.title.substring(0, this.length));
		
		// Modify the length for the substring and define the timer
		if (this.length !== this.title.length)
		{
			this.length++;
			
			// Add the tick character to the end of the string
			this.link.appendText(((this.length % 2) === 1) ? this.options.tickOne : this.options.tickTwo);
			
			// Short delay to quickly move onto the next character in the string
			this.timer = this.start.delay(this.options.delay, this);
		}
		else
		{
			// Reset the length for the next item
			this.length = 0;
			
			// Delay to show the full link
			this.timer = this.start.delay(this.options.duration, this);
		}
	}
});

/**
 * A image rotating widget.
 *
 * @author Andy Cox <andy@cactusbunker.com>
 */
Cactusbunker.Fx.ImageRotator = new Class({
	
	Extends: Fx,
	
	/**
	 * Various options to alter functionality.
	 */
	options: {
		delay:      2000,
		height:     150,
		transition: Fx.Transitions.Quart.easeInOut,
		width:      150
	},
	
	/**
	 * Class constructor.
	 * @param HTML Element element
	 * @param object options
	 * @return void
	 */
	initialize: function(element, options)
	{
		this.element = this.subject = $(element);
		this.parent(options);
		this.element.set({
			'styles': {
				'height': this.options.height,
				'overflow': 'hidden',
				'position': 'relative',
				'width': this.options.width
			}
		});
		this.index = 0;
		this.running = false;
		this.elements = this.getElements();
	},

	getElements: function()
	{
		var elements = [];
		var self = this;
		this.element.getElements('img').each(function(item, i){
			item.set({
				'events': {
					'mouseover': self.pause.bind(self),
					'mouseout': self.start.bind(self)
				},
				'styles': {
					'height': self.options.height,
					'left': 0,
					'opacity': (i !== 0) ? 0 : 1,
					'position': 'absolute',
					'top': 0,
					'width': self.options.width
				},
				'tween': {
					duration: self.options.delay,
					transition: self.options.transition
				}
			});
			elements.push(item);
		});
		return elements;
	},
	
	start: function()
	{
		this.running = true;
		this.timer = this.rotate.periodical(this.options.delay * 2, this);
	},
	
	pause: function()
	{
		this.running = false;
		$clear(this.timer);
	},
	
	rotate: function()
	{
		this.elements[this.index].fade();
		this.index = ((this.index + 1) !== this.elements.length) ? this.index + 1 : 0;
		this.elements[this.index].fade();
	}

});





