// Updated by Richard Wong (richard.wong@virginmedia.co.uk)
// Reference on VM VERSION 1.1 by Sbastien Gruhier (http://VM.com, http://itseb.com)

// VM namespace
if(typeof VM == 'undefined') {
	var VM = {};
}
// VM.Component namespace
if(typeof VM.Component == 'undefined') {
	VM.Component = {};
}

/** 
 * The MyLinks Module
 * The MyLinks Module provide a component to allow user to creating a editable 
 * list of links dynamically and store those data in cookie
 *
 * @module My Links
 * @namespace VM.Component
 * @require Prototyp, Scriptaculous ( Effect )
 */

/**
 * The My Links Component.
 *		TODOS: 	- Serialization of the list
 *				- Save to cookie				
 * @class ListMaker
 */
VM.Component.MyLinks = Class.create({
	
	/**
     * Create an element, set its class name and prepare the DOM
     *
     * @constructor
     * @param element {String/Object} the id of the element or the actually element object
     * @param options {Object} Configuration of callbacks, class names.
     */
	initialize: function(element, options) {
		this._element = $(element);
		
		this.options = Object.extend({
			cookieName: 'vmhp-links'
		}, options);
		
		this.formState = {
			defaultName : 'e.g. Mapache',
			defaultLink : 'e.g. www.mapache.com.br'
		};
		
		this._form = this._element.select('form.addForm')[0];
		this._addButton = this._element.select('a.add-links')[0];	
		this._setAddForm();
		
		this._element.select('ul.list-mylinks > li').each( this.setListItem.bind(this) );
	},
	
	/**
	 * Set the list Item with edit and remove buttons
	 * 
	 * @param listElem {String/Object} the id of the element or the actually element object
	 */
	setListItem: function(listElem) {
		listElem = $(listElem);
		
		listElem.select('a.edit-list-item')[0].observe('click', 
			this.onEditItem.bindAsEventListener(this));
		
		listElem.select('a.remove-list-item')[0].observe('click', 
			this.onRemoveItem.bindAsEventListener(this));
	},
	
	/**
	 * Add an item to the list
	 *
	 * @param name {string} 
	 * @param link {string} 
	 */
	addItem: function(name, link) {
		var listItem = new Element('li');
		
		listItem.insert( new Element('a', { 
			'href': 	link,
			'target':	'_blank'
		}).update(name));
		listItem.insert( new Element('a', { 
			'class':	'edit-list-item', 
			'href': 	'#edit-list-item',
			'title': 	'edit'
		}).update("Edit"));
		listItem.insert( new Element('a', {
			'class':	'remove-list-item', 
			'href': 	'#remove-list-item',
			'title': 	'remove'
		}).update('X'));

		this._element.select('ul.list-mylinks')[0].insert({ bottom: listItem });
	
		this.setListItem(listItem);
		
		return this;
	},
	
	/**
	 * Update item in the list
	 */
	updateItem: function(id, name, link) {
		listItemLink = $(id);
		
		listItemLink.update(name);
		listItemLink.writeAttribute({ href: link });
	},
	
	/**
	 * Edit an item from the list
	 *
	 * @param event {Event Object}
	 */
	onEditItem: function(event) {
		linkElem = Event.element(event).previous('a');
		
		$('listItemId').value = linkElem.identify();
		$('listItemName').value = linkElem.innerHTML;
		$('listItemLink').value = linkElem.readAttribute('href'); 
		
		this._addButton.hide();
		this._form.show();
		
		return this;
	},
	
	/**
	 * Remove an item from the list
	 *
	 * @param item {Item Object}
	 */
	onRemoveItem: function(event) {	
		Event.element(event).up().remove();
		
		if(typeof cookieUtility != 'undefined') {
			cookieUtility.add(this.options.cookieName, this.toString());
		}
		
		return this; 
	},
	
	/**
	 * On Form Save
	 * process the form to add or update accordingly
	 *
	 * @param item {Item Object}
	 */
	onFormSave: function(event) {
		Event.stop(event);
		
		var form = event.target;
		
		var itemNameInput = $('listItemName');
		var itemLinkInput = $('listItemLink');
		
		var valid = itemNameInput.present() && itemLinkInput.present();
		
		if (itemNameInput.getValue() == this.formState.defaultName &&
				itemLinkInput.getValue() == this.formState.defaultLink) {
			valid = false;
		}
		
		if (valid) {
			var name = $('listItemName').getValue();
			var link = $('listItemLink').getValue();
			
			name = name.replace(/\:|\}/ , '');
			link = link.replace("http://" , '');
			link = link.replace(/\:|\}/ , '');
			
			link = 'http://' + link;
			
			var idField = $('listItemId');
			
			if (idField.present()) {
				this.updateItem(idField.value, name, link);
			} else {
				this.addItem(name, link);
			}
			
			if(typeof cookieUtility != 'undefined') {
				cookieUtility.add(this.options.cookieName, this.toString());
			}
		}

		this.formReset();
		
		this._addButton.show();
		this._form.hide();
	},
	
	/**
	 * Reset Form to original state
	 */
	formReset: function() {
		this._form.listItemId.value = '';
		
		this._form.listItemName.value = this.formState.defaultName;
		this._form.listItemLink.value = this.formState.defaultLink;
		
		this._form.listItemName.style.color = this.formState.defaultColor;
		this._form.listItemLink.style.color = this.formState.defaultColor;
		
	},
	
	/**
	 * ToString provide a way to convert the List into a String
	 * 
	 * @return {String} String containing all the info about the List
	 */ 
	toString: function() {
		var string = '';
		
		this._element.select('ul.list-mylinks > li').each( function(itemElem) {
			var name = itemElem.select('a:first')[0].innerHTML;
			var link = itemElem.select('a:first')[0].readAttribute('href');
			
			string += name + ":" + link.replace("http://", '') + "}"; 
		});

		return string;
	},
	
	/**
	 * Set AddForm 
	 * 	- Apply observer to add button
	 * 	- Apply observer to submit and cancel buttons in the form 
	 * and make sure it is hidden by default
	 * 
	 * @return element form
	 */
	_setAddForm: function() {

		this._addButton.observe('click', function(event) {
			Event.stop(event);
			this._addButton.hide();
			this._form.show();
		}.bindAsEventListener(this));
		
		this._form.hide();
		
		this.formReset();
	
		this._form.select('a.btn-close')[0].observe('click', function(event) {
			this._form.hide();
			this._addButton.show();
			
			this._form.listItemId.value = '';
			this._form.listItemLink.value = this.formState.defaultLink;
			this._form.listItemName.value = this.formState.defaultName;
		}.bindAsEventListener(this));
		
		this._form.observe('submit', 
			this.onFormSave.bindAsEventListener(this));
	}
});


/**
 * The Component module provides a set of UI component implementation
 *
 * @module Component
 * @requires draggable
 */ 

/* The List Class
 * A widget that allows showing or hiding items in a list via two control
 *
 * @namespace Component
 * @class List
 */
VM.Component.List = Class.create({
	initialize: function(element, options) {
		this.options = Object.extend({                  	
			onUpdate: null     
		}, options);

		this._itemNo = 0;
		this._element = null;
		
		var element = $(element);

		if ( element ) {
			this._element = element;
			this.setAddRemove();
			this._itemNo = this._element.select('li:not(.hide)').size();
		}
	},
		
	setAddRemove: function() {	
		this._contentControl = this._element.select('div.content-controls')[0];
		
		if (this._contentControl) {
			this._contentControl.style.display = 'block';
			
			this._addButton = this._element.select('div.content-controls > a.more-content')[0];
			this._removeButton = this._element.select('div.content-controls > a.less-content')[0];
			
			if (this._addButton) {
				this._addButton.observe('click', this.onAddItem.bindAsEventListener(this));
			}
			if (this._removeButton) {
				this._removeButton.observe('click', this.onRemoveItem.bindAsEventListener(this));
			}
			
			if (this._removeButton && this._addButton){
				this._updateButtons();
			}
		}

		return this;
	},
	
	onAddItem: function(event) {
		Event.stop(event);
		
		if (!this._addButton.hasClassName('disabled')) {
			var listItem = this._element.select('li.hide')[0];
			
			if (listItem != null) {
				listItem.removeClassName('hide');
				this._itemNo++;
			}
			
			this._updateButtons();
			
			if (this.options.onUpdate != 'null') {
				this.options.onUpdate();
			}
		}
	},
		
	onRemoveItem: function(event) {
		Event.stop(event);
		
		if (!this._removeButton.hasClassName('disabled')) {
			var listItem = this._element.select('li:not(.hide)').last();
			
			if ( this._element.select('li:not(.hide)').size() > 1 ) {
				if (listItem != null) {
					listItem.addClassName('hide');
					this._itemNo--;
				} 
			}
			
			this._updateButtons();
			
			if (this.options.onUpdate != 'null') {
				this.options.onUpdate();
			}
		}
	},
	
	_updateButtons: function() {
		this._removeButton.removeClassName('disabled');
		this._addButton.removeClassName('disabled');
		
		if ( this._element.select('li:not(.hide)').size() == 1 ) {	
			this._removeButton.addClassName('disabled');
		}
		
		if (this._element.select('li.hide')[0] == null) {
			this._addButton.addClassName('disabled');	
		}
	},
	
	toString: function() {
		return this._itemNo;
	}
});


/* The WindowComponent Class 
 * This is a Base class for components within a window component
 * It will contain the component it is representing
 *
 * @class WindowComponent
 */
VM.Component.WindowComponent = Class.create({

	initialize: function(element, options) {
		this._element = $(element) || false;
		
		this.id = this._element.identify();
		
		this.options = Object.extend({
			onUpdate:		null,
			editableList: 	'collapsible-list',
			collapsibleDiv:	'collapsible-div',
			listMaker:		'editable-list'
		}, options);
		
		this._component = this._assignComponent();
	},
	
	toStateJSON: function() {
		var value = '';
		
		if (this._component != null) {
			value = this._component.toString();
		} 
		
		return {
			id: this.id,
			value: value
		};
	},
	
	onUpdate: function() {
		VM.Component.WindowMgrHelper.updateCookie();
	},
	
	_assignComponent: function() {
		if ( this._element.hasClassName(this.options.editableList) ) {
			return new VM.Component.List(this._element, { 
				onUpdate: this.onUpdate
			});
		} 
		
		return null;
	}
});


/* The Window Class 
 * A Window Component has the ability to have mutlipe state ( collapse at the monent )
 * It consist 2 blocks - title bar and the content area. The Title bar have controls for 
 * collapse and edit. In edit mode, an option panel will show with custom form or a list 
 * to allow user to add / remove Components in the window
 * 
 * TODOS:	- Edit Panel should be allow to extend from component
 *			- Allow AJAX call for window component
 * 
 * @class Window
 */
VM.Component.Window = Class.create({

	initialize: function(element, options) {
		var element = $(element);
		
		this._id = element.identify();
		
		this.options = Object.extend({ 
			draggable:			true,
			collapsible:		false,                                                       
			editable:			true,
			className:  		'hp-component', 
			componentClassName:	'component-module'  
		}, options);
 	 
 	 	this.state = { 
			collapsed: false
		};
 	 
		this._setElement(element);
		
		if (this.options.collapsible && this._titleDiv) {
			this.setCollapseButton();
		}
		if (this.options.editable && this._titleDiv) {
			this.setEditButton();
		}
		
		this.components = [];
		
		if (this._contentDiv) {
			var components = this._contentDiv.select('div.'+this.options.componentClassName);
			components.each( function( component, i) {
				this.addComponent(component);
			}.bind(this));
		}
		
		this._element.component = this;
		
		return this;
	},    
  	
	_setElement: function(element) {
		if (element != null) {
			this._element = element;
			this._titleDiv = element.select( '.component-title' )[0];
			
			if (this.options.draggable) {
				this._titleDiv.select('h3')[0].style.cursor = 'move';
				
				var titleLinkElem = this._titleDiv.select('h3 > a')[0];
				if (titleLinkElem) {
					titleLinkElem.observe('click', function(event) {
						if (this.isOnDrag) Event.stop(event);	
					}.bind(this));
				}
			}
			
			this._contentDiv = element.select( '.editable-content' )[0];
		}
	},
	
	getComponent: function(componentId) {
		this.components.each( function(component) {
			if (component._id == componentId) {
				return component;
			}	
		});
	},
	
	addComponent: function(componentId) {
		this.components.push(new VM.Component.WindowComponent(componentId));
		
		return this;
	},
	
	removeComponent: function(componentId) {
		var componentIndex = null; 
		this.components.each( function(component, index) {
			if (component.id == componentId) {
				componentIndex = index;
			}
		});
		
		this.components.splice(componentIndex);
		
		return this;
	},

	setEdit: function(optionHtml) {

		if ( optionHtml != null && this._editDiv == null ){
			
			this._editDiv = new Element('DIV', {'class': 'edit-panel clearfix' });
									
			this._titleDiv.insert( { bottom: this._editDiv });
			
			$(this._editDiv).update(optionHtml).hide(); 

		}
		
		this._element.select('form').each( function(form) {
		
			var submitButton = form.select('input[name="submit"]')[0];
			if (submitButton) {
				submitButton.observe('click', this.onEditSubmit.bindAsEventListener(this));
			}
			
			var resetButton = form.select('input[name="reset"]')[0];
			if (resetButton) {
				resetButton.observe('click', this.onEdit.bindAsEventListener(this));
			}
			
		}.bind(this));

		return this;
	},
	
	getEdit: function() {
		if (this._editDiv == null) {
			this._editDiv = this._titleDiv.select('div.edit-panel')[0];
			this.setEdit();
		}
		
		return this._editDiv;
	},
	
	setCollapseButton: function() {
	
		this._collapseButton = this._titleDiv.select('a.shutter-control')[0];
		
		Event.observe(this._collapseButton, 'click', this.onCollapse.bindAsEventListener(this));
	},
	
	setEditButton: function() {
	
		if ( this._titleDiv.select('a.edit-modules').size() > 0 ) {
			this._editButton = this._titleDiv.select('a.edit-modules')[0];
			this._editButton.style.display = 'block';
			
			Event.observe(this._editButton, 'click', this.onEdit.bindAsEventListener(this));
		} else {
			this.options.editable = false;
		}
		
		return this;
	},
	
	onEditReset: function(event) {
			
		new Effect.toggle(this.getEdit(), 'slide', { duration: 0.3 });
		
		Event.stop(event);
	},
	
	/**
	 * Submit the edit form and update the subcomponents for the component
	 *
	 */
	onEditSubmit: function(event) {
		Event.stop(event);
		
		if (typeof this.beforeEditSubmit != 'undefined') {
			this.beforeEditSubmit();
		}
		
		
		var componentComponents = [];
		
		var form = this.getEdit().select('form')[0];
		
		var sidString = '';
		
		form.getInputs('checkbox').each( function(input, i) {
			var sid = input.readAttribute('value');
			
			if ( $(sid) && !input.getValue() ) {
				$(sid).hide();
			} else if ( $(sid) && input.getValue() ) {
				$(sid).show();
			} else if ( !$(sid) && input.getValue() ) {
				sidString += sid + ',';
			}
			
			if (input.getValue()) {
				componentComponents.push({ id: sid });
			}
		}.bind(this));
		
		this.componentComponents = componentComponents;
		
		if (sidString != '') {
			this.getEdit().addClassName('loading');

			var url = this.options.baseAJAXurl + '?type=content&id='+this._id+'&sid='+sidString;
			
			new Ajax.Request(url, {
				method: 'get',
				onComplete: function(response) {
					if ( response.responseText != '' || response.responseText != 'null' ) {
						this._contentDiv.insert( { bottom: response.responseText });
					}
					sidString.split(",").each( function(sid) {
						if(sid != '' && $(sid)) {
							this.addComponent(sid);
						}
					}.bind(this)); 
					
					VM.Component.WindowMgrHelper.updateCookie();
						
					this._editDiv.removeClassName('loading');
					
					new Effect.toggle(this._editDiv, 'slide', { 
						duration: 0.3
					});
					
				}.bind(this)
			});
			return this;
		} else {
			VM.Component.WindowMgrHelper.updateCookie();
			
			return this.onEdit(event);
		}
	},
	
	onEdit: function(event) {
		Event.stop(event);
		
		var url = this.options.baseAJAXurl + '?type=edit&id='+this._id;
		
		if (this.getEdit()) {
			new Effect.toggle(this.getEdit(), 'slide', { 
				duration: 0.3
			});
			this.getEdit().removeClassName('loading');
		} else {
			new Ajax.Request(url, {
				method: 'get',
				onSuccess: function(response) {
					this.setEdit(response.responseText);

					if (this._editDiv) {
		    			this._editDiv.select('input[type="checkbox"]').each( function(elem) {
		    				if ($(elem.readAttribute('value')) && $(elem.readAttribute('value')).visible()) {
		    					elem.checked = true;
		    				} else {
		    					elem.checked = false;
		    				}
		    			});
		    		}
					
					//TODO's BIG HACK NEED FIXING
					if (typeof crir != 'undefined') {
						crir.init();crir.init();
					}
					
			    	new Effect.toggle(this.getEdit(), 'slide', { 
			    		duration: 0.3, 
			    		afterFinish: function() {
				    		
			    		}
			    	});
			    }.bind(this)
			});
		}
		
		if (this._editDiv) {
			this._editDiv.select('input[type="checkbox"]').each( function(elem) {
				if ($(elem.readAttribute('value')) && $(elem.readAttribute('value')).visible()) {
					elem.checked = true;
				} else {
					elem.checked = false;
				}
			});
		}
		
		//Update fancy checkbox state using an external class from crir.js
		if (typeof crir != 'undefined') {
			crir.init();
		}
		
		return this;
	},
	
	onCollapse: function(event) {
		
		if ( !this._contentDiv.visible() && this.state.collapsed ) { 
			this.state.collapsed = false;
			this._element.removeClassName('collapsed');
		} else {
			this.state.collapsed = true;
			this._element.addClassName('collapsed');
		}
		
		new Effect.toggle(this._contentDiv, 'slide', { duration: 0.5, queue: {scope:'collapse', limit:1} });

		VM.Component.WindowMgrHelper.updateCookie();
		
		Event.stop(event);
	},
	
	toStateJSON: function() {
	
		var content = [];
		
		this.components.each( function(component) {
			if (component._element.visible()) {
				var componentState = component.toStateJSON();
				var replaceStr = this._id + "-";
				componentState.id = componentState.id.replace(replaceStr, '');
				content.push( componentState );
			}
		}.bind(this));

		return { 
			id:			this._id.replace("hp-", ''), 
			state: 		this.state,
			content: 	content
		};
	}
});


/* The WindowMgr Class 
 * This Class manages and tracks the interaction of Windows. 
 * At the moment, it has the ability to add and remove windows with drag-n-drop functionality
 * There is also an initializer to put everything into position according to a array	
 * 
 * @class Window
 */
VM.Component.WindowMgr = Class.create({  
	
	initialize: function(options) {  
		this.options = Object.extend({
			containerId:		'content',
			columnClassName:	'column',
			windowClassName: 	'hp-component',
			noneDragDrop:		'no-dragnndrop',
			baseAJAXurl:		''
		}, options);
		
		this._container = null;
		
		this.windows = [];
		
		this._container = $(this.options.containerId);
		
		this._columns = this._container.select('div.' + this.options.columnClassName);
		
		this._columns.each(function(element, columnIndex) {
			Droppables.add(element, {
				onHover: this.onHover.bind(this), 
				overlap: "vertical",
				greedy: false
			});
			
			//Attaching index to a column
			this._columns[columnIndex].index = columnIndex;
			
			//Initialise the windows array for a column
			this._columns[columnIndex].windows = [];
		}.bind(this));                                                   
		
		Draggables.addObserver({ 
			onEnd: this.endDrag.bind(this), 
			onStart: this.startDrag.bind(this) 
		});
			
		VM.Component.WindowMgrHelper = new VM.Component.WindowMgrHelper(this._columns);		
		
		this._initializeComponents();
	},
	
	add: function(component, columnIndex) { 
		noneDragDrop = component.options.noneDragDrop;
		
		// Add to components list
		this.windows.push(component);
		
		//Attach a window component to the column
		this._columns[columnIndex].windows.push(component);
	
		// Add element to column
		this._columns[columnIndex].appendChild(component._element);
	
		// Make header draggable   
		if (noneDragDrop) {	
			var handle = component._titleDiv.select('h3')[0];
			component.draggable = new Draggable(component._element,{ 
				handle: handle,
				scroll: window,
				starteffect: null,
				endeffect: null
			});
			  
			handle.observe('mousedown', function(event) {
				component._element.addClassName('on-drag');
			});
			handle.observe('mouseup', function(event) {
				component._element.removeClassName('on-drag');
			});
		}
	},
	      
	remove: function(component) {
		// Remove from the list
		this.windows.reject(function(w) { return w == component; });
		
		// Remove draggable
		if (component.draggable) {
			component.draggable.destroy();
		}
		  
		// Remove from the dom
		component.destroy();
	},
	
	// DRAGGABLE OBSERVER CALLBACKS
	startDrag: function(event, draggable) { 
	
		var component = draggable.element;
		
		component.component.isOnDrag = true;
		
		this._addColumnHeight();
	
		var column = component.parentNode;
		
		//Remove the Window Component from the data array
		windowIndex = this._columns[column.index].windows.indexOf(component.component);
		this._columns[column.index].windows.splice(windowIndex, 1);
		
		// Create and insert ghost component
		var ghost = new Element( 'DIV' , {'class': 'component-ghost'}); 
		$(ghost).setStyle({height: component.getHeight()  + 'px'});
		
		column.insertBefore(ghost, component);  
		
		// IE Does not absolutize properly the component, needs to set width before
		component.setStyle({width: component.getWidth() + "px"});
		
		// Absolutize and move component on body
		component.absolutize();  
		document.body.appendChild(component);   
		
		// Store ghost to drag component for later use
		draggable.element.ghost = ghost;
	},   
	
	endDrag: function(event, draggable) {
		var component = draggable.element;      
		
		var column = component.ghost.parentNode;

		//Add the Window Component back to the data array
		windowIndex = component.ghost.previousSiblings().size();
	
		var left_offset = component.ghost.positionedOffset()[0];
		var top_offset = component.ghost.positionedOffset()[1] - 10;
		
		var dur = Math.sqrt(Math.abs(left_offset - component.positionedOffset()[0] + top_offset - component.positionedOffset()[1]))*0.04;
		var mgr = this;
		new Effect.Move(component, { 
			x: left_offset, y: top_offset, mode: 'absolute', duration: dur,
			queue: {scope:'drop', limit: dur}, 
			afterFinish: function() {
					
				//Add the Window Component back to the data array
				windowIndex = component.ghost.previousSiblings().size();
				mgr._columns[column.index].windows.splice(windowIndex, 0, component.component);

				column.insertBefore(draggable.element, component.ghost); 
				component.ghost.remove();   

				component.writeAttribute({ style: '' });
								
				component.ghost = null;    
				
				VM.Component.WindowMgrHelper.updateCookie();
				
				component.component.isOnDrag = false;
			}
		});

		this._removeColumnHeight();
	},
	
	onHover: function(dragComponent, dropon, overlap) {  
		var offset = dropon.cumulativeOffset();
		var x = offset[0] + 10;
		var y = offset[1] + (1 - overlap) * dropon.getHeight();
		
		// Check over ghost component
		if (Position.within(dragComponent.ghost, x, y)) {
			return;
		}
		 
		// Find if it's overlapping a component
		// TODO: very inefficient loop. specially for IE
		var found = false;
		var moved = false;
		for (var index = 0, len = this.windows.length; index < len; ++index) {
			var cElem = this.windows[index]._element;
		  	if (cElem ==  dragComponent || cElem.parentNode != dropon) {
		    	continue;
		    }
		
		  	if (Position.within(cElem, x, y)) {    
		    	var overlap = Position.overlap( 'vertical', cElem);     
		    	// Bottom of the component
		    	if (overlap < 0.5) {         
			      	// Check if the ghost component is not already below this component
			      	if (cElem.next() != dragComponent.ghost) {
			      		cElem.parentNode.insertBefore(dragComponent.ghost, cElem.next());

			        	moved = true;
			      	}
				} 
		    	// Top of the component
		    	else {       
		      		// Check if the ghost component is not already above this component
		      		if (cElem.previous() != dragComponent.ghost) {      
		      			cElem.parentNode.insertBefore(dragComponent.ghost, cElem);  

		        		moved = true;
		      		}
		    	}
		    	
		    	found = true;
		    	break;
		  	} 
		}
		// Not found a component
		if (! found) {        
			// Check if dropon has ghost component
		  	if (dragComponent.ghost.parentNode != dropon) {
		    	// Get last component bottom value
		    	var last = dropon.immediateDescendants().last();
		    	var yLast = last ? Position.cumulativeOffset(last)[1] + last.getHeight() : 0; 
		    	if (y > yLast && last != dragComponent.ghost) {
		      		dropon.appendChild(dragComponent.ghost);
		      		
		      		moved = true;
		    	}
		  	}
		}
	},
	
	_addColumnHeight: function() {
		var height = 0;
		this._columns.each( function(column) {
			column.writeAttribute({style : ''});
			height = Math.max(height, column.getHeight());
		});
		this._columns.each( function(column) {
			column.setStyle({ height: height + 'px' });
		});
	},
	
	_removeColumnHeight: function() {
		$$('.column').each( function(column) {
			column.writeAttribute({style : ''});
		});
	},
	
	_initializeComponents: function() {
		var divNames = this.divNames;
		
		this._columns.each( function(column, columnIndex) {
			column.select('.'+this.options.windowClassName).each( function(component, componentIndex) {
				if (!component.hasClassName(this.options.noneDragDrop)) {
					var window = new VM.Component.Window(component.identify(), this.options);
					this.add(window, columnIndex);
				}
			}.bind(this));
		}.bind(this));
	},
	
	/** 
	 * Update Layout from a layout array
	 */
	updateLayout: function(layout) {
		if (typeof layout != 'undefined') {	
			var columns = this._columns;
			layout.each( function(col, colIndex) {
				col.each( function(componentId, componentIndex){
						var componentDiv = $( 'hp-' + componentId );
				
						var column = componentDiv.parentNode;
						//Remove the Window Component from the data array
						windowIndex = this._columns[column.index].windows.indexOf(componentDiv.component);
						this._columns[column.index].windows.splice(windowIndex, 1); 
						
						this._columns[colIndex].insert( componentDiv );

						//Add the Window Component back to the data array
						windowIndex = componentDiv.previousSiblings().size();
						this._columns[colIndex].windows.splice(windowIndex, 0, componentDiv.component);
				}.bind(this));
			}.bind(this));
		}
	}
}); 

/* This should be a helper class to store window detail in the cookie
 * 
 * @class Window
 */ 
VM.Component.WindowMgrHelper = Class.create({

	initialize: function(columns, options) {
		this.options = Object.extend({
			cookieName: 		'vmhp',
			cookieExpireDays: 	2
		}, options);
		
		this.columns = columns;
	},
	
	updateCookie: function() {
		var windowClassName = this.options.windowClassName;
		var snapshot = [];

		this.columns.each( function(column) {
			var col = [];
			column.immediateDescendants().each( function(window) {
				if (window.hasClassName('hp-component') && !window.hasClassName('no-dragnndrop')) {
					col.push(window.component.toStateJSON());
				}
			});
			snapshot.push(col);
		});
		
		encodedSnapshot = this.encodeSnapshot(snapshot);

		if(typeof cookieUtility != 'undefined') {
			cookieUtility.add('vmhp', encodedSnapshot, 360);
		}
	},
	
	encodeSnapshot: function(snapshot) {	
		var string = '';
		
		snapshot.each( function(column) {
			column.each( function(window) {
				string += window.id + '=';
				
				var windowString = '';
				
				if (window.state.collapsed) windowString += 'c';
				
				windowString += ',';
				window.content.each( function(component) {
					windowString += component.id + '$' + component.value + '~';
				});
				
				string += windowString + '|';
			});
			string += '*';
		});
		
		return string;
	},
	
	decodeSnapshotToLayout: function(serializeString) {
		var layout = new Array();
	
		serializeString.split('*').each( function(columnString) {
			if (columnString != '') {
				var column = new Array();
				
				columnString.split('|').each( function(windowString) {
					if (windowString != '') {
						var id = windowString.split('=')[0];
						column.push(id);
					}
				});
				layout.push(column);
			}
		});
		return layout;
	}
});
