var Nested = new Class({
	Implements : [Events,Options],

	options: {
		childTag: 'li',
		ghost: true,
		indent: 30,
		handleClass: null, 
		serializeCallback:$empty
	},

	initialize: function(list, options) {
		this.setOptions(options);

		this.options.parentTag = $(list).get('tag');
		this.options.parentClass = $(list).get('class');
		this.bound = {
			start:this.start.bind(this)
		};
		this.list = $(list);
		this.attach();
		this.idle = true;
	},
	
	attach: function(){
		this.list.getElements(this.options.childTag).each(function(li){
			var start = li.retrieve('nested:start',this.start.bindWithEvent(this,li));
			(li.getElement('.'+this.options.handleClass) || li).addEvent('mousedown',start);
		},this)
	},
	
	append:function(element){
		var start = element.retrieve('nested:start',this.start.bindWithEvent(this,element));
		(element.getElement('.'+this.options.handleClass) || element).addEvent('mousedown',start);
	},

	start: function(event,li) {
		if (event.rightClick || !this.idle) return true;
		event.stop();
		this.idle = false;

		var el = this.element = $(li);
		var par = this.element.getParent();
		if(Browser.Engine.trident && $$('.navigation_leftnav')[0]){
			while(par != document.body){
				par.setStyle('position','static');
				par = par.getParent();
			}
		}
		var pos = this.element.getPosition(Browser.Engine.trident && $$('.navigation_leftnav')[0]? document.body : (this.options.offset || this.list));
		var size = this.element.getSize();
		this.offset = {
			x:event.page.x-pos.x,
			y:event.page.y-pos.y
		};
		
		if(Browser.Engine.trident && $$('.navigation_leftnav')[0]){
			$('main_container').setStyle('position','static');
			$('subcontainer').setStyle('position','static');
			$$('.navigation_leftnav')[0].setStyle('position','static');
			$$('.navigation_leftnav')[0].getElement('ul.leftnav').setStyle('position','static');
			$$('.navigation_leftnav')[0].getElements('ul,li').each(function(e){e.setStyle('position','static');});
			$$('.navigation_leftnav')[0].getElements('img.edit').each(function(e){e.setStyle('visibility','hidden');});
		}

		if (this.options.ghost) { // Create the ghost
			this.ghost = el.clone().setStyles({
				'opacity': 0.7,
				'position': 'absolute',
				'top': event.page.y-this.offset.y,
				'left': event.page.x-this.offset.x,
				'width' : size.x,
				'height' : size.y
			}).injectInside(this.list);
		}
		el.depth = this.getDepth(el);
		el.moved = false;
		this.bound.movement = this.movement.bindWithEvent(this,el);
		this.bound.end = this.end.bindWithEvent(this,el);
		document.addEvent('mousemove', this.bound.movement);
		document.addEvent('mouseup', this.bound.end);
		this.fireEvent('onStart', [el,event]);
	},
	
	getDepth: function(el, add) {
		var counter = (add) ? 1 : 0;
		while (el != this.list) {
			if (el.get('tag') == this.options.parentTag) counter += 1;
			el = el.getParent();
		}
		return counter;
	},
	posFinder: function(list,mouse){
		var coords;
		var children = $(list).getChildren();

		for (var i=0;i<children.length;i++){
			coords = children[i].getCoordinates(Browser.Engine.trident && $$('.navigation_leftnav')[0] ? document.body : null);
			if (coords.top<mouse.y && mouse.y<coords.bottom){
				var childList = children[i].getElement(this.options.parentTag);
				if (childList){
					var result = this.posFinder(childList,mouse);
					return (result) ? result : {element:children[i],'coords':coords,position:((coords.height/2)>mouse.y-coords.top)?'before':'after'};
				}else
					return {element:children[i],'coords':coords,position:((coords.height/2)>mouse.y-coords.top)?'before':'after'};
			}
		}

		return false;
	},
	
	//safely inject element insde of the container
	safeInject: function(container,element){
		if (container == element) return;
		var childList = container.getElement(this.options.parentTag);
		if (childList){
			childList.adopt(element);
		}else if (!this.options.preserve){
			container.adopt(new Element(this.options.parentTag,{'class':this.options.parentClass}).adopt(element));
		}
	},
	
	movement: function(event,el) {
		var inside = false;
		if (this.options.ghost) { // Position the ghost
			this.ghost.setStyles({
				'top': event.page.y-this.offset.y,
				'left': event.page.x-this.offset.x
			});
		}
		var result = this.posFinder(this.list,event.page);
		
		if (result && result.element!=this.element && !this.element.hasChild(result.element)){
			var previousParent = this.element.getParent();
			if (event.page.x<result.coords.left+this.options.indent)
				this.element.inject(result.element,result.position);
			else if (result.position=='before')
				inside = result.element.getPrevious();
			else
				inside = result.element;
			if (inside) this.safeInject(inside,this.element);
			if (previousParent!=this.list && previousParent.getChildren().length==0 && !this.options.preserve) previousParent.destroy();
		}else if (result.element==this.element){
			var prev = result.element.getPrevious();
			var elParent = this.element.getParent()

			if (event.page.x<result.coords.left){
				if (elParent.getChildren().getLast()==this.element)
					this.element.inject(elParent.getParent(),'after');
				if (elParent.getChildren()==0 && !this.options.preserve) elParent.destroy();
			}else if(event.page.x>= result.coords.left+this.options.indent){
				if (prev)
					this.safeInject(prev,this.element);
			}
		}
		event.stop();
		this.fireEvent('onMousemove',[el,event]);
		return;
	},

	serialize: function(listEl) {
		var serial = [];
		var children;
		if (!listEl) listEl = this.list;
		$splat(listEl).each(function(list){
			list.getChildren().each(function(child, i) {
				if (child == this.ghost) return;
				children = child.getElement(this.options.parentTag.toLowerCase());
				serial.push({
					id: this.options.serializeCallback.attempt(child) || child.getProperty('id'),
					children: (children) ? this.serialize(children) : []
				});
			},this);
		},this);
		return serial;
	},

	end: function(event,el) {
		if (this.options.ghost) this.ghost.destroy();
		document.removeEvent('mousemove', this.bound.movement);
		document.removeEvent('mouseup', this.bound.end);
		this.fireEvent('onComplete', [el,event]);
		this.idle = true;
		
		if(Browser.Engine.trident && $$('.navigation_leftnav')[0]){
			$$('.navigation_leftnav')[0].getElements('li').each(function(e){e.setStyle('position','relative');});
			$$('.navigation_leftnav')[0].getElements('img.edit').each(function(e){e.setStyle('visibility','visible');});
		}
	}
});