/* This file is automatically generated */

/*

Copyright (c) 2008 Rizqi Ahmad

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. 

*/

/* core.js */
(function($){

$.Interaction = 
{
	services: {},
	
	add: function(name, proto)
	{
		var services = $.Interaction.services;
		
		services[name] = $.extend({}, this.base, proto);
		
		$.fn[name] = function(options)
		{
			var service = this.data('interaction-'+name);
		
			if(typeof options != 'string')
			{
				if(service)
					service.$destroy();
			
				this.data('interaction-'+name, $.extend({element:this, name:name}, services[name]));
				service = this.data('interaction-'+name);
				service.init(options);
				
				return this;
			}
		
			else
			{
				var command = options;
				options = Array.prototype.slice.call(arguments, 1);
				
				if(command == '?')
					return !!service;
				else if(service && typeof service['$'+command] == 'function')
					return service['$'+command].apply(service, options);
				else
					return services[name]['$'+command].apply({isEnabled:false, dummy:true}, options);
			}
		}
	},
	
	extend: function(name, proto)
	{
		if(this.services[name])
			this.services[name] = $.extend(this.services[name], proto);
	},
	
	listeners: {},
	
	listen: function(service, name, fn)
	{
		if(!this.listeners[service])
			this.listeners[service] = {};
		
		var obj = {};
		
		if(typeof name == 'string')
			obj[name] = fn;
		else if(typeof name == 'object')
			obj = name;
		
		for(var n in obj)
		{
			if(!this.listeners[service][n])
				this.listeners[service][n] = [];
			
			this.listeners[service][n].push(obj[n]);
		}
	},
	
	defaults: function(service, defaults)
	{
		if(this.services[service])
			$.extend(this.services[service].defaults, defaults);
	}
};

$.Interaction.base =
{
	init: function()
	{
		this.base();
	},

	base: function()
	{
		this.setting = $.extend({}, (typeof this.defaults == 'function') ? this.defaults() : this.defaults || {});
		this.functionWrappers = [];
		this.temp = {};
		this.isEnabled = true;
		
		this.listeners = {};
		var listeners = $.Interaction.listeners[this.name] || {};
		for(var i in listeners)
			this.listeners[i] = [].concat(listeners[i]);
	
		this.element.addClass('interaction-'+this.name);
		var self = this;
		this.element.chain('plugin', this.name, function(){
			self.builder($(this));
		});
		this.element.bind('destroy', function(){
			self.$destroy();
		});
	},

	wrap: function(fn)
	{
		var self = this;
		var args = Array.prototype.slice.call(arguments, 1);
		var array = this.functionWrappers;
		var wrap;
	
		if(typeof fn == 'string')
			fn = self[fn];
	
		for(var i=0; i<array.length; i++)
		{	
			if(array[i].src == fn)
			{
				wrap = array[i];
				break;
			}
		}
	
		if(!wrap)
		{
			wrap = {src:fn, fn:function(){
				return fn.apply(self, Array.prototype.slice.call(arguments).concat(args));
			}};
			array.push(wrap);
		}
	
		return wrap.fn;
	},

	builder: function(item)
	{
	
	},
	
	addListener: function(name, fn)
	{
		if(!this.listeners[name])
			this.listeners[name] = [];
		
		this.listeners[name].push(fn);
	},
	
	removeListener: function(name, fn)
	{
		if(!this.listeners[name])
			this.listeners[name] = [];
		
		if(fn)
		{
			var res = [];
			for(var i=0; i<this.listeners[name].length; i++)
				if(this.listeners[name][i] != fn)
					res.push(this.listeners[name][i]);
			this.listeners[name] = res;
		}
		else
		{
			this.listeners[name] = [];
		}
	},
	
	extractListener: function()
	{
		for(var i=0; i<arguments.length; i++)
		{
			if(this.setting[arguments[i]])
				this.addListener('$'+arguments[i], this.setting[arguments[i]]);
		}
	},
	
	callListener: function(name)
	{
		if(!this.listeners[name])
			this.listeners[name] = [];
			
		if(!this.listeners['$'+name])
			this.listeners['$'+name] = [];
		
		var args = Array.prototype.slice.call(arguments, 1);
		
		for(var i=0; i<this.listeners[name].length; i++)
			this.listeners[name][i].apply(this, args);
			
		for(var i=0; i<this.listeners['$'+name].length; i++)
			this.listeners['$'+name][i].apply(this.element, [this].concat(args));
	},

	destroy: function()
	{
		this.element.unbind('.'+this.name);
		this.element.removeData('interaction-'+this.name);
		this.element.removeClass('interaction-'+this.name);
	
		this.element.chain('plugin', this.name, null);
	
		this.element.items().each(function(){
			$(this).unbind('.'+this.name+'-item');
		});
		
		this.callListener('destroy');
	},
	
	$listen: function(name, fn)
	{
		if(this.dummy) return this.element;
		
		var obj = {};
		
		if(typeof name == 'string')
			obj[name] = fn;
		else if(typeof name == 'object')
			obj = name;
		
		for(var n in obj)
			this.addListener('$'+n, obj[n]);
		
		return this.element;
	},
	
	$unlisten: function(name, fn)
	{
		if(this.dummy) return this.element;
		
		this.removeListener('$'+name, fn);
		
		return this.element;
	},
	
	$service: function()
	{
		return this.dummy ? null : this;
	},

	$destroy: function()
	{
		if(!this.dummy)
			this.destroy();
		
		return this.element;
	},
	
	
	$enable: function()
	{
		if(this.dummy) return this.element;
		
		this.isEnabled = true;
		this.callListener('enable');
		
		return this.element;
	},
	
	$disable: function()
	{
		if(this.dummy) return this.element;
		
		if(this.mouseUp)
			this.mouseUp(this.mouseDownEvent);
		this.isEnabled = false;
		this.callListener('disable');
		
		return this.element;
	}
};

// Adaptation of ui.mouse (c) Paul Bakaus
$.Interaction.mouse =
{
	mouseDown: function(event)
	{
		var self = this;
		if(this.isMouseStarted)
			this.mouseUp(event);
	
		this.mouseDownEvent = event;
		
		var cancel = (typeof this.setting.cancel == 'string'
			&& $(event.target).parents().add(event.target).filter(this.setting.cancel).length);
	
		if(event.which != 1 || this.mouseCapture(event) || cancel)
			return false;
	
		this.isMouseDelayMet = false;
		setTimeout(function(){self.isMouseDelayMet = true;}, this.setting.delay);
	
		if(event.preventDefault)
			event.preventDefault();
		
		if($.browser.msie)
			document.onselectstart = function(){return false};
	
		$(document)
			.bind('mousemove.'+this.name, this.wrap('mouseMove'))
			.bind('mouseup.'+this.name, this.wrap('mouseUp'));
	
		return true;
	},

	mouseMove: function(event)
	{
		// IE mouseup check - mouseup happened when mouse was out of window
		if ($.browser.msie && !event.button)
		{
			this.mouseUp(event);
			return false;
		}
		
		this.mouseMoveEvent = event;
	
		if(this.isMouseStarted)
		{
			this.mouseDrag(event);
		}
		else if(this.mouseDistanceMet(event) && this.mouseDelayMet(event))
		{
			this.isMouseStarted = this.mouseStart(event);
			if(this.isMouseStarted)
				this.mouseDrag(event);
			else
				this.mouseUp(event);
		}
	
		return this.isMouseStarted;
	},

	mouseUp: function(event)
	{
		$(document)
			.unbind('mousemove.'+this.name, this.wrap('mouseMove'))
			.unbind('mouseup.'+this.name, this.wrap('mouseUp'));
		
		if($.browser.msie)
			document.onselectstart = function(){return true;};
	
		if(this.isMouseStarted)
		{
			this.isMouseStarted = false;
			this.mouseStop(event);
		}
	},

	mouseDistanceMet: function(e) {
		return (Math.max(
				Math.abs(this.mouseDownEvent.pageX - e.pageX),
				Math.abs(this.mouseDownEvent.pageY - e.pageY)
			) >= this.setting.distance
		);
	},

	mouseDelayMet: function(e) {
		return this.isMouseDelayMet;
	},

	// These are placeholder methods, to be overriden by extending plugin
	mouseStart: function() {return false;},
	mouseDrag: function() {return false;},
	mouseStop: function() {return false;},
	mouseCapture: function() {return false;}
};

})(jQuery);


/* draggable.js */
(function($){
	
$.Interaction.add('draggable', $.extend({}, $.Interaction.mouse, {
	defaults: 
	{
		helper: function(e){return $(e).clone();},
		handle: null,
		classPrefix: 'drag-',
		container: null,
		cancel: ':input',
		cursorAt: null,
		axis: 'xy',
		delay: 0,
		distance: 0
	},
	
	init: function(setting)
	{
		this.base();
		$.extend(this.setting, setting);
		if(!$('#interaction-draggable-container').length)
			$('<div>')
				.attr('id', 'interaction-draggable-container')
				.css('position', 'absolute')
				.hide()
				.appendTo(document.body);
		
		this.container = $(this.setting.container || '#interaction-draggable-container');
		
		this.cursor = null;
		this.position = {x:0, y:0};
		
		this.extractListener('start', 'drag', 'stop');
		
		this.callListener('init');
	},
	
	builder: function(item)
	{
		var self = this;
		
		this.getHandle(item).bind('mousedown.draggable-item', function(event){
			if(self.isEnabled)
			{
				self.item = item;
				self.mouseDown(event);
			}
		});
		
		this.callListener('build', item);
	},
	
	mouseStart: function(event)
	{
		if(!this.item || !this.item.length)
			return this.mouseUp(event);
		
		var offset = this.item.eq(0).offset();
		
		if(!this.cursor)
		{
			this.cursor = {};
			if(this.setting.cursorAt)
			{
				this.cursor.left = this.setting.cursorAt.left;
				this.cursor.top = this.setting.cursorAt.top;
			}
			else
			{
				this.cursor.left = event.pageX - offset.left;
				this.cursor.top = event.pageY - offset.top;
			}
		}
		
		if(this.setting.axis == 'y')
			this.container[0].style.left = offset.left + 'px';
		else if(this.setting.axis == 'x')
			this.container[0].style.top =  offset.top + 'px';
		
		this.mouseDrag(event);
		
		this.container
			.empty()
			.append(this.setting.helper(this.item))
			.show();
		
		this.callListener('start');
		
		return true;
	},
	
	mouseDrag: function(event)
	{
		this.position.x = event.pageX;
		this.position.y = event.pageY;
		
		if(this.setting.axis != 'y')
			this.container[0].style.left = (this.position.x - this.cursor.left) + 'px';
		if(this.setting.axis != 'x')
			this.container[0].style.top =  (this.position.y - this.cursor.top) + 'px';
		
		this.callListener('drag');
		
		return true;
	},
	
	mouseStop: function(event)
	{
		this.container.empty().hide();
		
		this.callListener('stop');
		this.cursor = null;
		
		return true;
	},
	
	getHandle: function(item)
	{
		return this.setting.handle ? item.find(this.setting.handle) : item;
	}
}));

// Cursor Listener
$.Interaction.listen('draggable',{
	start: function()
	{
		if(!this.setting.cursor)
			return;
		var body = $('body');
		this.temp.bodyCursor = body.css('cursor');
		body.css('cursor', this.setting.cursor);
		this.container.css('cursor', this.setting.cursor)
			.children().css('cursor', this.setting.cursor);
	},
	
	stop: function()
	{
		if(!this.setting.cursor)
			return;
		$('body').css('cursor', this.temp.bodyCursor);
	}
});

// Opacity Listener
$.Interaction.listen('draggable', {
	init: function()
	{
		if(this.setting.opacity)
			this.container.css('opacity', this.setting.opacity);
	}
})

// Scroll Defaults
$.Interaction.defaults('draggable', {
	scroll: true,
	scrollArea: 20,
	scrollSpeed: 20
});

// Scroll Listener
$.Interaction.listen('draggable', {
	start: function()
	{
		if(!this.setting.scroll)
			return;
		
		var self = this;
		
		var el = this.setting.scrollElement
			? $(this.setting.scrollElement)[0] : this.element.chain('anchor')[0];
		var offset = $(el).offset();
		$.extend(offset, {
			scrollHeight:0, 
			scrollWidth:0, 
			height:el.offsetHeight,
			width:el.offsetWidth
		});
	
		$(el).children().each(function(){
			offset.scrollHeight += this.offsetHeight;
			offset.scrollWidth += this.offsetWidth;
		});
		
		this.temp.scrollInt = setInterval(function(){
			var s = self.setting;
			var pos = self.position;
			var doc = $(document);
	
			if(offset.scrollHeight > offset.height && Math.abs(pos.y - offset.top) < s.scrollArea)
				el.scrollTop -= s.scrollSpeed;
			if(offset.scrollHeight > offset.height && Math.abs(offset.top + offset.height - pos.y) < s.scrollArea)
				el.scrollTop += s.scrollSpeed;
	
			if(offset.scrollWidth > offset.width && Math.abs(pos.x - offset.left) < s.scrollArea)
				el.scrollLeft -= s.scrollSpeed;
			if(offset.scrollWidth > offset.width && Math.abs(offset.left + offset.width - pos.x) < s.scrollArea)
				el.scrollLeft += s.scrollSpeed;
	
			if(pos.y - doc.scrollTop() < s.scrollArea)
				doc.scrollTop(doc.scrollTop() - s.scrollSpeed);
			if(window.innerHeight - (pos.y - doc.scrollTop()) < s.scrollArea)
				doc.scrollTop(doc.scrollTop() + s.scrollSpeed);
				
			if(pos.x - doc.scrollLeft() < s.scrollArea)
				doc.scrollLeft(doc.scrollLeft() - s.scrollSpeed);
			if(window.innerWidth - (pos.x - doc.scrollLeft()) < s.scrollArea)
				doc.scrollLeft(doc.scrollLeft() + s.scrollSpeed);
		}, 200);
	},
	
	stop: function()
	{
		if(!this.setting.scroll)
			return;
		
		clearInterval(this.temp.scrollInt);
	}
});

})(jQuery);


/* droppable.js */
(function($){

$.Interaction.ddmanager = ddmanager =
{
	droppables: [],
	draggable: null,
	status: '',
	
	getAllDroppables: function()
	{
		return $('.interaction-droppable').map(function(){return this.data('interaction-droppable')}).get();
	}
};

$.Interaction.add('droppable', {
	defaults:
	{
		accept: function(){return true;},
		classPrefix: 'drop-',
		activeClass: 'active',
		hoverClass: 'hover',
		dynamic: true,
		nested: false
	},
	
	init: function(setting)
	{
		this.base();
		this.setting = $.extend(this.setting, setting);
		this.droppables = [];
		this.isOver = false;
		this.childOver = false;
		
		if(typeof this.setting.accept == 'string')
		{
			var className = this.setting.accept;
			this.setting.accept = function(element){return element.hasClass(className)};
		}
		
		this.extractListener('over', 'out', 'active', 'deactive', 'drop');
		this.updateParent();
		this.refreshOffset();
		this.callListener('init');
	},
	
	refreshOffset: function()
	{
		var element = this.element.get(0);
		var offset = this.element.offset();
		
		this.offset =
		{
			width: element.offsetWidth,
			height: element.offsetHeight,
			top: offset.top,
			left: offset.left
		};
	},
	
	intersect: function(draggable)
	{
		if(this.setting.dynamic)
			this.refreshOffset();
		
		return draggable.position.x >= this.offset.left
			&& draggable.position.y >= this.offset.top
			&& draggable.position.x <= this.offset.left + this.offset.width
			&& draggable.position.y <= this.offset.top + this.offset.height;
	},
	
	updateParent: function()
	{
		var oldparent = this.parent || ddmanager;
		
		var parent = this.element.parents('.interaction-droppable').eq(0);
		this.parent = parent.length ? parent.data('interaction-droppable') : false;
		
		if(this.parent != oldparent)
		{
			var droppables = [];
			for(var i=0; i<oldparent.droppables.length; i++)
				if(oldparent.droppables[i] != this)
					droppables.push(oldparent.droppables[i]);
			
			oldparent.droppables = droppables;
			
			(this.parent || ddmanager).droppables.push(this);
		}
	},
	
	setStatus: function(stat)
	{
		ddmanager.status = stat;
	},
	
	mouseStart: function()
	{
		$.each(this.droppables, function(){
			this.mouseStart();
		});
		
		if(!this.isEnabled) return;
		
		this.updateParent();
		
		if(this.setting.accept(ddmanager.draggable.element, ddmanager.draggable.item))
		{
			this.isActive = true;
			this.dragActive();
		}
	},
	
	mouseDrag: function()
	{
		$.each(this.droppables, function(){
			if(!this.setting.nested)
				this.mouseDrag();
		});
		
		var intersect = false;
		
		if(this.isEnabled && this.isActive)
		{
			intersect = this.intersect(ddmanager.draggable);
			
			if(intersect)
				$.each(this.droppables, function(){
					if(this.setting.nested)
						this.mouseDrag();
				});
			
			if((!intersect || (intersect && this.childOver)) && this.isOver)
			{
				this.dragOut();
				this.isOver = false;
				if(this.parent && this.setting.nested && !this.childOver)
					this.parent.childOver = false;
			}
			else if(!this.isOver && intersect && !this.childOver)
			{
				this.dragOver();
				this.isOver = true;
				if(this.parent && this.setting.nested)
					this.parent.childOver = true;
			}
			else if(this.childOver && this.parent && this.setting.nested)
				this.parent.childOver = true;
		}
		
	},
	
	mouseStop: function()
	{
		$.each(this.droppables, function(){
			this.mouseStop();
		});
		
		var intersect = this.intersect(ddmanager.draggable);
		if(this.isActive && intersect && !this.childOver)
			this.dragDrop();
		
		this.dragDeactive();
		
		this.isActive = false;
		this.isOver = false;
		this.childOver = false;
	},
	
	dragActive: function()
	{
		this.callListener('active', ddmanager.draggable.item);
	},
	
	dragDeactive: function()
	{
		
		this.callListener('deactive', ddmanager.draggable.item);
	},
	
	dragOver: function()
	{
		this.callListener('over', ddmanager.draggable.item);
	},
	
	dragOut: function()
	{
		this.callListener('out', ddmanager.draggable.item);
	},
	
	dragDrop: function()
	{
		this.callListener('drop', ddmanager.draggable.item);
	},
	
	$destroy: function()
	{
		if(!this.dummy)
		{
			var droppables = [];
			var parent = this.parent || ddmanager;
			for(var i=0; i<parent.droppables.length; i++)
				if(parent.droppables[i] != this)
					droppables.push(parent.droppables[i]);
			
			parent.droppables = droppables;
			this.destroy();
		}
		
		return this.element;
	}
});

// Track Draggable
$.Interaction.listen('draggable', {
	start: function()
	{
		ddmanager.draggable = this;
		$.each(ddmanager.droppables, function(){
			this.mouseStart();
		})
	},
	
	drag: function()
	{
		if(ddmanager.status != this.lastDragStatus)
		{
			if(this.lastDragStatus)
				this.container.removeClass(this.setting.classPrefix+this.lastDragStatus);
			if(ddmanager.status)
				this.container.addClass(this.setting.classPrefix+ddmanager.status);
			this.lastDragStatus = ddmanager.status;
		}
		
		$.each(ddmanager.droppables, function(){
			this.mouseDrag();
		})
	},
	
	stop: function()
	{
		$.each(ddmanager.droppables, function()
		{
			this.mouseStop();
		});
		
		ddmanager.draggable = null;
		ddmanager.status = '';
	}
});

// Class Tracker
$.Interaction.listen('droppable', {
	active: function()
	{
		this.element.addClass(this.setting.classPrefix+this.setting.activeClass);
	},
	
	deactive: function()
	{
		this.element.removeClass(this.setting.classPrefix+this.setting.activeClass);
		this.element.removeClass(this.setting.classPrefix+this.setting.hoverClass);
	},
	
	over: function()
	{
		this.element.addClass(this.setting.classPrefix+this.setting.hoverClass);
	},
	
	out: function()
	{
		this.element.removeClass(this.setting.classPrefix+this.setting.hoverClass);
	}
});

})(jQuery);


/* sortable.js */
(function($){

$.Interaction.add('sortable', {
	defaults:
	{
		marker: 'transparent',
		boundary: 6,
		align: 'vertical',
		accept: function(){return false},
		method: 'move'
	},
	
	init: function(setting)
	{
		this.base();
		$.extend(this.setting, setting);
		
		this.parseMarker();
		
		if(!this.element.data('interaction-draggable'))
			this.element.draggable({
				start: this.wrap('mouseStart'),
				drag: this.wrap('mouseDrag'),
				stop: this.wrap('mouseStop')
			});
		else
			this.element.draggable('listen', {
				start: this.wrap('mouseStart'),
				drag: this.wrap('mouseDrag'),
				stop: this.wrap('mouseStop')
			});
		
		if(this.setting.accept)
		{
			if(typeof this.setting.accept == 'string')
			{
				var className = this.setting.accept;
				this.setting.accept = function(element){return element.hasClass(className)};
			}
			
			if(!this.element.data('interaction-droppable'))
				this.element.droppable({
					over: this.wrap('dragOver')
				});
			else
				this.element.droppable('listen', {
					over: this.wrap('dragOver')
				});
			
			this.element.data('interaction-droppable').setting.dynamic = true;
		}
		
		this.draggable = this.element.data('interaction-draggable');
		
		this.extractListener('reorder', 'transfer');
		
		this.currentIndex = -1;
		this.lastIndex = -1;
		this.isActive = false;
		
		this.callListener('init');
	},
	
	parseMarker: function()
	{
		if(typeof this.setting.marker == 'function')
			return;
		
		var marker = this.setting.marker;
		
		if(marker == 'transparent')
			marker = function(item){
				return item.eq(0).clone().css('visibility', 'hidden');
			};
		else if(marker == 'separator')
			marker = function(item, align){
				return $('<div></div>')
					.css('overflow', 'hidden')
					.addClass('interaction-sortable-separator')[(align == 'vertical' ? 'height' : 'width')](0);
			};
		else
			marker = function(item){
				return item.clone();
			}
		
		this.setting.marker = marker;
	},
	
	mouseStart: function()
	{
		this.isActive = true;
		this.item = this.draggable.item;
		this.marker = this.setting.marker(this.item, this.setting.align);
		this.marker.removeClass('chain-item').addClass('interaction-sortable-marker');
		this.item.eq(0).before(this.marker);
		this.item.hide();
		this.currentIndex = this.marker.parent().children(':visible').index(this.marker);
		this.lastIndex = this.currentIndex;
	},
	
	mouseDrag: function()
	{
		if(this.item)
		{	
			var pos = this.draggable.position;
			var setting = this.setting;
			var item = this.item;
			var marker = this.marker;
			var self = this;
			
			var offset = this.element.offset();
			offset.height = this.element[0].offsetHeight;
			offset.width = this.element[0].offsetWidth;
			
			if(pos.y < offset.top || pos.y > (offset.top + offset.height)
				|| pos.x < offset.left || pos.x > (offset.left + offset.width))
			{
				item.eq(0).before(marker);
				return;
			}
			
			var items = this.element.items();
			var markerIndex = marker.parent().children(':visible').index(marker);
			
			for(var i=0; i<items.length; i++)
			{
				var hover = $(items[i]);
				var offset = hover.offset();
				
				offset.height = hover[0].offsetHeight;
				offset.width = hover[0].offsetWidth;
				
				if(setting.align == 'vertical')
				{ var xy = 'y';var tl = 'top';var hw = 'height'; }
				else
				{ var xy = 'x';var tl = 'left';var hw = 'width'; }
				
				self.currentIndex = markerIndex;
				var moved = self.currentIndex != self.lastIndex;
			
				if(hover.prev()[0] != marker[marker.length-1]
					&& pos[xy] - offset[tl] > 0 && pos[xy] - offset[tl] < setting.boundary)
					hover.before(marker);
				else if(hover.next()[0] != marker[0]
					&& offset[tl] + offset[hw] - pos[xy] > 0 && offset[tl] + offset[hw] - pos[xy] < setting.boundary)
					hover.after(marker);
				
				if(moved)
				{
					self.callListener('reorder', item);
					self.lastIndex = self.currentIndex;
					break;
				}
			}
			this.element.items().each(function(){
				
			});
		}
	},
	
	mouseStop: function()
	{
		if(this.item && $.Chain.jidentic(this.item.item('root'), this.element))
		{
			this.marker.before(this.item);
			this.item.show();
		}
		this.marker.remove();
		
		
		this.isActive = false;
		this.item = null;
		this.marker = null;
		this.element.update();
	},
	
	dragOver: function(droppable, item, bypass)
	{
		if(bypass || item.item('root')[0] == this.element[0])
			return;
		
		var sortable = item.item('root').data('interaction-sortable');
		
		if(this.setting.accept(sortable.element, item))
		{
			var cursor = sortable.draggable.cursor;
			
			var newItem = $().eq(-1);
			var data = item.map(function(){return $(this).item();}).get();
			this.element.items('merge', data);
			for(var i=0; i<data.length; i++)
				newItem = newItem.add(this.element.items(data[i]));
			
			this.callListener('transfer', item, newItem);
			
			if(sortable.setting.method == 'move')
			{
				item.each(function(){
					$(this).item('remove', true);
				});
			}
			item.item('root').update();
				
			this.draggable.item = newItem;
			this.draggable.cursor = cursor;
			
			sortable.draggable.mouseUp(sortable.draggable.mouseDownEvent);
			
			var event = sortable.draggable.mouseMoveEvent || sortable.draggable.mouseDownEvent;
			this.draggable.mouseDown(event);
			this.draggable.isMouseStarted = this.draggable.mouseStart(event);
			droppable.callListener('over', item, true);
		}
	},
	
	$destroy: function()
	{
		this.element.draggable('unlisten', 'start', this.wrap('mouseStart'));
		this.element.draggable('unlisten', 'drag', this.wrap('mouseDrag'));
		this.element.draggable('unlisten', 'stop', this.wrap('mouseStop'));
	}
});

})(jQuery);


/* selectable.js */
(function($){

$.Interaction.add('selectable', {
	defaults:
	{
		multiple: false,
		required: false,
		selected: null,
		handle: null,
		selectClass: 'selected',
		nested: false,
		drag: false
	},
	
	init: function(setting)
	{
		this.base();
		$.extend(this.setting, setting);
		
		this.selected = this.setting.selected ? $(this.setting.selected) : $().eq(-1);
		
		var self = this;
		this.element.items('collection', 'selected', function(){
			return self.getSelected().filter(':visible');
		});
		
		this.element.items('collection', 'selected-all', function(){
			return self.getSelected();
		});
		
		this.extractListener('select', 'unselect', 'change');
		this.callListener('init');
	},
	
	builder: function(item)
	{
		var handle, self = this;
		
		if(this.setting.handle)
			handle = item.find('> '+this.setting.handle+', *:not(.chain-element) '+this.setting.handle).eq(0);
		
		if(!handle)
			handle = item;
		
		item
			.bind('mousedown.selectable-item', function(event){
				if(self.isEnabled
					&& $(event.target).parents().add(event.target).filter(function(){return handle[0] == this;}).length)
					return self.mouseDown(event, item);
			})
			.bind('click.selectable-item', function(event){
				if(self.isEnabled
					&& $(event.target).parents().add(event.target).filter(function(){return handle[0] == this;}).length)
					return self.mouseClick(event, item);
			});
		
		if(this.setting.required && !this.selected.length && item.parent().children(':visible').index(item) == 0)
			this.select(item);
		else if(this.selected.index(item) > -1)
			this.select(item);
	},
	
	mouseDown: function(event, item)
	{
		this.mouseDownEvent = event;
		var draggable = this.element.draggable('service');
		if(draggable && this.$selected(item) && this.setting.drag)
		{
			draggable.mouseUp(draggable.mouseDownEvent);
			draggable.item = this.selected.filter(':visible');
			draggable.mouseDown(event);
		}
	},
	
	mouseClick: function(event, item)
	{
		if($.browser.msie && this.mouseDownEvent);
			event = this.mouseDownEvent;
		
		if(event.which != 1)
			alert(event.which);
		
		if(event.metaKey)
		{
			if(this.$selected(item) && (!this.setting.required || this.selected.length > 1))
				this.$unselect(item);
			else
				this.$select(item);	
		}
		else if(event.shiftKey)
		{
			var selected = this.selected.eq(0);
			
			if(selected.length && !$.Chain.jidentic(item, selected))
			{
				var items = selected.parent().children(':visible');
				var dir = items.index(selected) < items.index(item) ? 'next' : 'prev';
				var next = selected[dir]();
				while(next.length)
				{
					selected = selected.add(next);
					if($.Chain.jidentic(next, item))
						break;
					next = next[dir]();
				}
			}
			
			this.clear();
			this.$select(selected.length ? selected : item);
		}
		else
		{
			this.clear();
			this.$select(item);
		}
	},
	
	getParent: function()
	{
		return this.setting.nested ? this.element.parents('.interaction-selectable')
			.eq(0) : $().eq(-1);
	},
	
	getAncestor: function()
	{
		var parent = this.getParent();
		
		if(parent.length)
			return parent.data('interaction-selectable').getAncestor();
		else
			return this.element;
	},
	
	getNested: function(recursive)
	{
		var selectable = this.element
			.find('.interaction-selectable')
			.not(this.element.find('.interaction-selectable .interaction-selectable'))
			.filter(function(){
				var sel = $(this).data('interaction-selectable');
				return sel ? sel.setting.nested : false;
			});
		
		if(!recursive)
			return selectable;
		
		var res = [];
		selectable.each(function(){
			res.push(this);
			$(this).data('interaction-selectable').getNested(true).each(function(){
				res.push(this)
			});
		});
		
		return $(res);
	},
	
	getSelected: function()
	{
		var anchor = this.element.chain('anchor')
		var selected = this.selected.filter(function(){
			return ($(this).parent()[0] == anchor[0]);
		});
		this.getNested().each(function(){
			var selectable = $(this).data('interaction-selectable');
			selected = selected.add(selectable.getSelected());
		});
		
		return selected;
	},
	
	select: function()
	{
		var args = Array.prototype.slice.call(arguments);
		var self = this;
		
		var selected = this.selected;
		
		this.getAncestor().data('interaction-selectable').clear();
		
		$.each(args, function(){
			if(this && typeof this != 'boolean')
				selected = selected.add(self.element.items(this));
		});
		
		if(!this.setting.multiple)
			selected = selected.eq(selected.length - 1);
		
		selected.addClass(this.setting.selectClass);
		
		this.selected = selected;
	},
	
	unselect: function()
	{
		var args = Array.prototype.slice.call(arguments);
		var self = this;
		
		this.selected.removeClass(this.setting.selectClass);
		
		$.each(args, function(){
			if(this && typeof this != 'boolean')
				self.selected = self.selected.not(self.element.items(this));
		});
		
		this.selected.addClass(this.setting.selectClass);
	},
	
	clear: function()
	{
		this.selected.removeClass(this.setting.selectClass);
		this.selected = $().eq(1);
		
		this.getNested().each(function(){
			$(this).data('interaction-selectable').clear();
		});
	},
	
	$select: function()
	{
		if(!this.isEnabled) return this.element;
		
		this.select.apply(this, Array.prototype.slice.call(arguments));
		
		this.callListener('select');
		this.callListener('change');
		
		return this.element;
	},
	
	$unselect: function()
	{
		if(!this.isEnabled) return this.element;
		
		this.unselect.apply(this, Array.prototype.slice.call(arguments));
		
		this.callListener('unselect');
		this.callListener('change');
		
		return this.element;
	},
	
	$clear: function()
	{
		if(!this.isEnabled) return this.element;
		
		this.clear();
		
		this.callListener('unselect');
		this.callListener('change');
		
		return this.element;
	},
	
	$selected: function(item)
	{
		if(!this.isEnabled) return $().eq(-1);
		
		if(item === true)
			return this.getSelected();
		else if(arguments.length && typeof item != 'boolean' && item !== null)
			return this.selected.index(this.element.items(item)) > -1;
		else
			return this.getSelected().filter(':visible');
	}
});

// Update element on selection change
$.Interaction.listen('selectable',{
	change: function()
	{
		this.element.update();
	}
});

})(jQuery);


