/**
 * multi form Class
 * 
 * Create forms widget sets with a template allowing many records to be
 * created in one form.
 * 
 * 
 * @param string templateBlock DOM ID of template Block.
 * @param {Object} options
 * 
 * Options object takes a number of options
 * 	container : the dom id of the container element for the added form elements.
 * 	addButton : the dom id of the create new form button.
 *  deleteButton : set to true to have events attached to the delete button
 *  deleteButtonClass : the class name of the delete button.
 *  counter : what to start the internal instance counter at. (default 0)
 *  clearContent :  If true, will clear the original content when first form is added
 *  				also when last form is removed will replace original content.\
 *  onComplete : Call backs to run after Template block is added in. scoped to template block
 *  onFirst : Callback to run on first template block creation.  scoped to template block
 *  
 */
var multiForm = new Class({
	count : 0,
	indexCount : 0,
	
	
	originalContent : null,
	
	holderEl : null,
	
	options : {
		deleteButtonClass : '.button.delete',
		deleteButton : true,
		container : '',
		addButton : '',
		counter : 0,
		clearContent: true,
		onComplete : $lambda(true),
		onFirst : $lambda(true)
	},
	Implements : [Options],
	
	initialize : function(template, options) {
		var templateBlock = $(template);
		this.setOptions(options);
		
		this.count = options.counter;
		this.indexCount = options.counter;
		this.template = new Template(templateBlock);
		this.holderEl = $(options.container);
		var addButton = $(options.addButton);
		addButton.addEvent('click', this.buttonEvent.bind(this));
		this.attachDeleteEvent();
	},
/**
 * button Event for add button.
 * @param Event e 
 */	
	buttonEvent : function(e) {
		e = new Event(e).stop();
		//var templateData = {i : this.indexCount++ };
		var templateData = {i : new Date().getTime() };
		var filledTemplate = this.template.evaluate(templateData);
		if (this.count == 0 && this.options.clearContent) {
			this.originalContent = this.holderEl.get('html');
			this.holderEl.empty();
		}
		var el = new Element('div', {'class' : 'line-block' ,'html' : filledTemplate});
		this.holderEl.adopt(el);
		this.count++;
		if (this.count == 1) {
			this.options.onFirst.call(el);
		}
		this.attachDeleteEvent();
		this.options.onComplete.call(el);
		console.log(this.indexCount);
	},
/**
 * Run After block has been added, attach events to delete button
 */
	attachDeleteEvent : function() {
		this.holderEl.getElements('.button.delete').each(function(item) {
			item.removeEvents('click');
			var parent = item.getParent();
			var grandDad = parent.getParent();
			item.addEvent('click', function(e) {
				e = new Event(e).stop();
				grandDad.removeChild(parent);
				this.count--;
				if (this.count == 0 && this.options.clearContent) {
					this.holderEl.set('html', this.originalContent);
				}
			}.bind(this))
		}.bind(this));
	}
});

/**
 * Collection of Ajax Tools.
 * 
 * @author Mark Story
 */
var AjaxTools = {	
	flashEl : null, //$() Element reference
	dimmerEl : null, //$() Element reference
/**
 * Ajax Send a Form.
 * 
 * @param {Object} e Mouse Event object
 */
	sendForm : function (e, options){
		e = new Event(e).stop();
		this.send(options);
	},
/**
 * Replaces the content of the the current Ajax updating element with a loading indicator box
 * Good for onRequest events
 */
	displayLoading : function(resp){
		var loadingParent = $(this.options.update);	
		loadingParent.setHTML('<div class="loading"><span class="loading-spinner">Loading..</span></div>');
	},
/** 
 * Add event handlers for expanders on summary blocks 
 * @param {Object} HTMLElements Array that need the expander behaviour.  If none
 * are passed it will default to .summary-block.
 */
	expanders : function(elements){
		if(elements == undefined){
			elements = $ES('.summary-block .expand-button', document); 
		}
		elements.each(function (item){
			var container = item.getParent().getNext();
			var nameElement = $E('span', item.getParent());
			
			container.fx = new Fx.Slide(container, {duration: 300});
			container.fx.hide();
			item.addEvent('click', function(e){
				e = new Event(e).stop();
				container.fx.toggle();
			});
			
			if (nameElement) {
				nameElement.addEvent('click', function(e){
					e = new Event(e).stop();
					container.fx.toggle();
				})
			}
		});
	},
/**
 * Update element and flash the new status
 * 
 * @param {Object} element DOM element to update
 * @param {Object} message message to display. Defaults to AjaxTools.flashEl
 */
	flash : function(message, element){
		if(element == undefined){
			element = AjaxTools.flashEl;
		}
		var animate = element.effects({duration:400});		
		AjaxTools.flashEl.innerHTML = message;		
		animate.start({
			'opacity' : [0, 1]		
		}).chain(function(){
			animate.start.delay(500, this, {
				'opacity' : [1, 0]
			});
		});
	},
	setFlashEl : function(el){
		this.flashEl = el;
	},
/**
 * Dim a box and show a loading spinner
 * 
 * @param {Object} el element to dim.
 */
	dim : function(el){
		if (el == undefined) el = AjaxTools.dimmerEl;
		var dimmer = new Element('div', {'class' : 'loading-dimmer', 'html':'<span class="loading-spinner">Loading..</span>'});
		this.dimmer = dimmer;
		el.adopt(dimmer);		
	},
/**
 * Undim a box.
 * @param {Object} el
 */
	unDim : function(el, remove){
		var dimmer = this.dimmer;
		var myFx = new Fx.Tween(dimmer, {duration: 250});
		myFx.start('opacity', 1, 0).chain(function(){
			if (remove !== undefined) {
				dimmer.remove();
			}	
		});				
	},
/**
 * Make an ajax link with options passed in.
 * @param {Object} e Mouse Event
 * @param {Object} el Element to use for url
 * @param {Object} ajaxOptions Options hash for Ajax
 */
	link : function(e, el, ajaxOptions){
		e = new Event(e).stop();		
		var options = $merge({ 
			'method' : 'get',
			'onComplete' : Class.empty,
			'async' : true }, ajaxOptions);
		el.get('load', options);
		return el.load();
	},
	/**
	 * Submit a Form on an Event
	 * 
	 * @param {Object} e Mouse Event
	 * @param {Object} el  Form Element to Submit
	 * @param {Object} options  ajax Options Element
	 */
	submit : function(e, el, options){
		e = new Event(e).stop();
		if(el.nodeName !== 'FORM') return;
		el.send(options);		
	},
	/**
	 * Cookie tools
	 * 
	 * Options:
	 *   cookieLife :  The life of the cookie (in days)
	 *   name : The name of the cookie
	 */
	Cookie: function( options ){
		this.defaults = { life: 60,
						  name : 'cookie'
						 };
		this.options = $merge(this.defaults, options);			
	}	
};

AjaxTools.Cookie.prototype = {
	/**
	 * Read the last selected history data set from the cookie and set it.
	 *
	 */
	read: function(name){
		if (name == undefined) {
			name = this.options.name;
		}
		name = name + '=';
		var cookieJar = document.cookie.split(';');
		for (var i = 0; i < cookieJar.length; i++) {
			var chips = cookieJar[i];
			//trim leading spaces
			while (chips.charAt(0) == ' ') {
				chips = chips.substring(1, chips.length);
			}
			if (chips.indexOf(name) == 0) {
				return chips.substring(name.length, chips.length)
			}
		}
		return false;
	},
	
	/**
	 * Write the cookie that indicates the peristed data set to use on next page load.
	 */
	write: function(name, value){
		var date = new Date();
		date.setTime(date.getTime() + (this.options.life * 24 * 60 * 60 * 1000));
		var expires = "; expires=" + date.toGMTString();
		document.cookie = name + "=" + value + expires + "; path=/";
		return true;
	}
};

/**
 * Weighted Table Sorter
 * Allows for table forms with weight-esque inputs to be drag sorted.
 *
 */
var WeightTable = new Class({

	Extends : Sortables,
	weightWidgets : [],
/**
 * Constructor
 * @param object list Container of elements to be drag sorted.
 * @param object options List of options for WeightTable and Sortables 
 */
	initialize : function(list, options) {
		var defaults = {
			formClass : '.weight',
			onComplete : this.updateFormElements,
			ghost : false
		};
		options = $merge(defaults, options);
		this.parent(list, defaults);
		this.setFormElements();
	},
/**
 * Setup / Modify the form elements in the table
 *
 *
 */
	setFormElements : function()  {
		for (var i = 0, len = this.elements.length; i < len; i++) {
			var el = this.elements[i];
			this.addWeightElement(el);
		}
		var headingEl = this.lists[0].getPrevious().getElement(this.options.formClass);
		if (headingEl) {
			headingEl.setStyle('display', 'none');
		}
	},
/**
 * Update the weight fields to reflect the current table
 * order.
 */
	updateFormElements : function() {
		var currentOrder = this.serialize(0, function(element, index) {
			return this.elements.indexOf(element);
		});
		for (var i = 0, len = currentOrder.length; i < len; i++) {
			this.weightWidgets[currentOrder[i]].setProperty('value', i);
		}
	},
/**
 * Add a row to the table sorter.1
 *
 */
	addRow : function(row) {
		this.addItems(row);
		this.addWeightElement(row);
	},
	
/**
 * Add a Weight element.
 *
 */
	addWeightElement : function(el) {
		var weightInput = el.getElement(this.options.formClass);
		this.weightWidgets.push(weightInput);
		weightInput.getParent().setStyle('display', 'none'); 
	}
});

