/**
 * @author Francuzov A. V.
 */

Drag.Move = Drag.Move.extend({
	drag: function(event) {
		this.dragFlag = true;
		
		this.parent(event);
		var overed = this.droppables.filter(this.checkAgainst, this).getLast();
		if (overed) {
			var elover = this.checkAgainst(overed);
	
			if ((this.overed != overed) || (this.elover != elover)) {
				this.elover = this.checkAgainst(overed);

				if (this.overed) this.overed.fireEvent('leave', [this.element, this]);
				this.overed = overed ? overed.fireEvent('over', [this.element, this, this.elover]) : null;
			}
		}
		return this;
	},
	
	stop: function() {
		this.dragFlag = false;
		this.parent();
	},
	
	start: function(event) {
		var eventObject = new Event(event);

		if (!this.dragFlag && !eventObject.rightClick) {
			this.parent(event);
		}
	},
	
	checkAgainst: function(el) {
		el = el.getCoordinates(this.options.overflown);
		var now = this.mouse.now;
		return (now.x > el.left && now.x < el.right && now.y < el.bottom && now.y > el.top) ? ((now.y < (el.bottom - el.height/2)) ? 1 : -1) : false;
	}
});

var iBlockSort = new Class({
	options: {
		ghostElementClass: 'iGhostItem',
		changeOrderFunction: null,
		mouseOverItemFunction: null,
		mouseOutItemFunction: null
	},

	dragElements: [],
	
	initialize: function(options) {
		this.setOptions(options);
		this.dragElements = new Array();
	},
	
	addDragItem: function(element, itemId) {
		var fx = new Fx.Styles(element,
		{
			duration: 0,
			wait: false,
			onComplete: function(element) {
				element.setStyle('z-index','1');
			}
		});
		var mouseOverItemFunction = this.options.mouseOverItemFunction;
		var mouseOutItemFunction = this.options.mouseOutItemFunction;
		var dragFunction = this.options.dragFunction;
		
		element.onmouseover = function() {
			mouseOverItemFunction(itemId);
		}
		element.onmouseout = function() {
			mouseOutItemFunction(itemId);
		}

		var droppables = [];
		for (var i=0; i<this.dragElements.length; i++) {
			droppables[droppables.length] = this.dragElements[i].element;
		}

		var changeOrderFunction = this.options.changeOrderFunction;
		var dragOptions = {
			droppables: droppables,
			snap: 10,
			onDrag: function(element) {
				dragFunction();
			}.bind(this),
			onStart: function(element) {
				fx.stop();
				
				for (var i=0; i<this.dragElements.length; i++) {
					if (this.dragElements[i].id == itemId) {
						this.dragElements[i].posX = element.getPosition().x;
						this.dragElements[i].posY = element.getPosition().y;
					}
					
					this.dragElements[i].element.onmouseover = null;
					this.dragElements[i].element.onmouseout = null;
				}
				
				var elCoord = element.getCoordinates();
				var elHeight = elCoord.height + 'px';
				var ghostElement = new Element('div', {
					'class': this.options.ghostElementClass,
					'styles': {
						'height': elHeight.toInt() - 2,
						'margin': element.getStyle('margin'),
						'border-width': '1px'
					}
				});
				ghostElement = ghostElement.injectBefore(element);
				element.injectInside(ghostElement);
				
				for (var i=0; i<this.dragElements.length; i++) {
					if (this.dragElements[i].id == itemId) {
						this.dragElements[i].ghostElement = ghostElement;
					}
				}
				
				element.setStyle('position','relative');
				element.setStyle('margin', '0px');
				element.setStyle('z-index','1');
				element.setOpacity('0.7');
			}.bind(this),
			onComplete: function(element) {
				var dragElement = null;
				for (var i=0; i<this.dragElements.length; i++) {
					if (this.dragElements[i].id == itemId) {
						dragElement = this.dragElements[i];
						element.injectBefore(dragElement.ghostElement);
						element.setStyle('margin', dragElement.ghostElement.getStyle('margin'));
						dragElement.ghostElement.remove();
					}
					
					this.dragElements[i].element.onmouseover = this.dragElements[i].mouseover;
					this.dragElements[i].element.onmouseout = this.dragElements[i].mouseout;
				}
				
				fx.start({
					'left': 0,
					'top': 0,
					'opacity': '1'
				}).chain(function() {
					element.setStyle('position','static');
					element.setStyle('z-index','0');
					if (dragElement.currentOvered) {
						if (!((dragElement.posX == element.getPosition().x) && (element.getPosition().y == dragElement.posY))) {
							changeOrderFunction(dragElement.id, dragElement.currentOvered, dragElement.inject);
						}
					}
					dragElement.posX = element.getPosition().x;
					dragElement.posY = element.getPosition().y;
					dragElement.currentOvered = 0;
					dragElement.inject = 0;
				});
			}.bind(this)
		};
		
		var dragElement = new Drag.Move(element, dragOptions);
		
		var dragElements = this.dragElements;
		element.addEvents({
			'over': function(element, obj) {
				if ($chk(arguments[2])) {
					for (var i=0; i<dragElements.length; i++) {
						if (dragElements[i].element == element) {
							var dragTopPosition = element.getStyle('top');
							var dragLeftPosition = element.getStyle('left');
							var oldDragPosition = element.getPosition();
							var ghostElement = dragElements[i].ghostElement;

							if (arguments[2] == 1) {
								ghostElement.injectBefore(this);
								dragElements[i].inject = 1;
							} else {
								ghostElement.injectAfter(this);
								dragElements[i].inject = -1;
							}
							var newDragPosition = element.getPosition();
							var inflexion = 0;
							var xInflexion = newDragPosition.x.toInt() - oldDragPosition.x.toInt();
							var yInflexion = newDragPosition.y.toInt() - oldDragPosition.y.toInt();
							
							element.setStyle('left', (dragLeftPosition.toInt() - xInflexion) + 'px');
							dragElements[i].dragElement.mouse.pos.x = dragElements[i].dragElement.mouse.pos.x + xInflexion;
							element.setStyle('top', (dragTopPosition.toInt() - yInflexion) + 'px');
							dragElements[i].dragElement.mouse.pos.y = dragElements[i].dragElement.mouse.pos.y + yInflexion;
							
							dragElements[i].currentOvered = itemId;
						}
					}
				}
			}
		});
		
		for (var i=0; i<this.dragElements.length; i++) {
			this.dragElements[i].dragElement.droppables[this.dragElements[i].dragElement.droppables.length] = element;
		}
		
		this.dragElements[this.dragElements.length] = {
			id: itemId,
			element: element,
			mouseover: element.onmouseover,
			mouseout: element.onmouseout,
			dragElement: dragElement
		};

		// Bug in IE (unnecessary margin in the bottom of each element)
		element.setStyle('position','static');
	}
});

iBlockSort.implement(new Events); // Implements addEvent(type, fn), fireEvent(type, [args], delay) and removeEvent(type, fn)
iBlockSort.implement(new Options); // Implements setOptions(defaults, options)
