Logi.UI.DragNDrop = {};

Logi.UI.DragNDrop.Listener = new Class ({
	
	__construct : function (boxClassName, draggerClassName, handler, options) {
		this.options = options || {};
		this.options.listener = this.options.listener || Logi.emptyFunction; 
        this.boxClassName = boxClassName;
        this.draggerClassName = draggerClassName || boxClassName;        
        this.dragObject = undefined;
        this.handler = handler || new Logi.UI.DragNDrop.Mover();
        Logi.DOM.Event.addMainListener ('mousedown', Delegate (this, 'mouseDown'));
        Logi.DOM.Event.addMainListener ('mousemove', Delegate (this, 'mouseMove'));
		Logi.DOM.Event.addMainListener ('mouseup', Delegate (this, 'mouseUp'));
	},
        
    findRelativeObject : function (element) {
        var el = element;
        while (el.nodeName != '#document') {
            var pos = getComputedStyle (el, null).getPropertyValue ('position');
            if (pos == 'absolute' || pos == 'relative') return el;
            el = el.parentNode;
        }
        return document.body;
    },

    findDragObject : function (element, className) {
        var el = element;

        while (el.nodeName != '#document') {
            if (Logi.DOM.Element.hasClass (el, className)) return el;
            el = el.parentNode;
        }
    },

    mouseDown : function (event) {
        var dragger = this.findDragObject (event.target, this.draggerClassName);
        if (dragger) {
            var box = this.findDragObject (dragger, this.boxClassName);
        }
        if (box) {
            this.parentContainer = this.findRelativeObject (box.parentNode);
            this.dragObject = box;
        	if (this.options.zIndex && !this.dragObject.style.zIndex) {
        		this.dragObject.style.zIndex = this.options.zIndex;
        	}
            this.startX = event.screenX;
            this.startY = event.screenY;
            this.handler.storeInitialState (this);
            this.options.listener (1, this.dragObject);
        }
    },

    mouseMove : function (event) {
        if (typeof this.dragObject != 'undefined') {
            //getSelection().collapseToStart();
            
            this.handler.setCurrentState (this, event.screenX - this.startX, event.screenY - this.startY);
            this.options.listener (2, this.dragObject);
        }    
    },

    mouseUp : function (event) {
        if (typeof this.dragObject != 'undefined') {
        	if (this.options.zIndex && this.dragObject.style.zIndex) {
        		this.dragObject.style.zIndex = '';
        	}
            this.options.listener (3, this.dragObject);
            this.dragObject = undefined;
        }    
    }
	
});


Logi.UI.DragNDrop.Mover = new Class ({

	__construct : function() {
	},
	
	storeInitialState : function (listener) {
		this.dragX = parseInt (getComputedStyle (listener.dragObject, null).getPropertyValue ('left'));
		this.dragY = parseInt (getComputedStyle (listener.dragObject, null).getPropertyValue ('top'));
	},
	
	setCurrentState : function (listener, offsetX, offsetY) {
        var posX = this.dragX + offsetX;
        var posY = this.dragY + offsetY;
        
        if (posX + listener.dragObject.offsetWidth > listener.parentContainer.scrollWidth) {
            posX = listener.parentContainer.scrollWidth - listener.dragObject.offsetWidth;
        }
        if (posY + listener.dragObject.offsetHeight > listener.parentContainer.scrollHeight) {
            posY = listener.parentContainer.scrollHeight - listener.dragObject.offsetHeight;
        }
        if (posX < 0) posX = 0;
        if (posY < 0) posY = 0;
        listener.dragObject.style.left = posX + 'px';
        listener.dragObject.style.top = posY + 'px';
	}

});


Logi.UI.DragNDrop.Resizer = new Class ({

	__construct : function (directionX, directionY, minWidth, minHeight) {
		if (directionX > 1) directionX = 1;
		if (directionX < -1) directionX = -1;
		if (directionX > 1) directionY = 1;
		if (directionX < -1) directionY = -1;
		this.directionX = directionX;
		this.directionY = directionY;
		this.minWidth = minWidth;
		this.minHeight = minHeight;
	},
	
	storeInitialState : function (listener) {
		this.dragX = parseInt (getComputedStyle (listener.dragObject, null).getPropertyValue ('left'));
		this.dragY = parseInt (getComputedStyle (listener.dragObject, null).getPropertyValue ('top'));
		this.dragW = parseInt (getComputedStyle (listener.dragObject, null).getPropertyValue ('width'));
		this.dragH = parseInt (getComputedStyle (listener.dragObject, null).getPropertyValue ('height'));
	},
	
	setCurrentState : function (listener, offsetX, offsetY) {
		
        var posX = this.directionX == -1 ? this.dragX + offsetX : this.dragX;
        var posY = this.directionY == -1 ? this.dragY + offsetY : this.dragY;
        
        var sizeX = this.directionX == 0 ? this.dragW : this.dragW + offsetX * this.directionX;
        var sizeY = this.directionY == 0 ? this.dragH : this.dragH + offsetY * this.directionY;
        
        if (this.minWidth !== false && sizeX < this.minWidth) {
        	if (this.directionX == -1) {
        		posX -= this.minWidth - sizeX;
        	}
        	sizeX = this.minWidth;
        }
        if (this.minHeight !== false && sizeY < this.minHeight) {
        	if (this.directionY == -1) {
        		posY -= this.minHeight - sizeY;
        	}
        	sizeY = this.minHeight;
        }
        
        if (posX + listener.dragObject.offsetWidth > listener.parentContainer.scrollWidth) {
            posX = listener.parentContainer.scrollWidth - listener.dragObject.offsetWidth;
        }
        if (posY + listener.dragObject.offsetHeight > listener.parentContainer.scrollHeight) {
            posY = listener.parentContainer.scrollHeight - listener.dragObject.offsetHeight;
        }
        if (posX < 0) posX = 0;
        if (posY < 0) posY = 0;
        listener.dragObject.style.left = posX + 'px';
        listener.dragObject.style.top = posY + 'px';
        listener.dragObject.style.width = sizeX + 'px';
        listener.dragObject.style.height = sizeY + 'px';
	}

});

(function() {
	
	var directionMapping = {
		top : [0, -1],
		bottom : [0, 1],
		left : [-1, 0],
		right : [1, 0],
		top_left : [-1, -1],
		top_right : [1, -1],
		bottom_left : [-1, 1],
		bottom_right : [1, 1]
	};

	Logi.UI.DragNDrop.ResizerFactory = new Class ({
		
		__construct : function (container, containerClassName, options) {
			this.container = container;
			this.containerClassName = containerClassName;
			if (options === true) {
				options = {
					horizontal : true,
					vertical : true
				};
			}
			this.minWidth = options.minWidth || false;
			this.minHeight = options.minHeight || false;
			this.cssClassBase = options.cssClassBase || 'logi_ui_resizer';
			this.horizontal = options.horizontal;
			this.vertical = options.vertical;
			this.dom = [];
			this.createResizers();
			
	        /*Logi.DOM.Event.addMainListener ('mousedown', Delegate (this, 'mouseDown'));
	        Logi.DOM.Event.addMainListener ('mousemove', Delegate (this, 'mouseMove'));
			Logi.DOM.Event.addMainListener ('mouseup', Delegate (this, 'mouseUp'));*/
		},
		
		createResizers : function() {
			var hasBottom = this.vertical === true || this.vertical == 'bottom';
			var hasTop = this.vertical === true || this.vertical == 'top';
			var hasRight = this.horizontal === true || this.horizontal == 'right';
			var hasLeft = this.horizontal === true || this.horizontal == 'left';
			var hasBottomRight = hasBottom && hasRight;
			var hasBottomLeft = hasBottom && hasLeft;
			var hasTopRight = hasTop && hasRight;
			var hasTopLeft = hasTop && hasLeft;
			
			if (hasBottom) this.createResizer ('bottom');
			if (hasTop) this.createResizer ('top');
			if (hasRight) this.createResizer ('right');
			if (hasLeft) this.createResizer ('left');
			if (hasBottomRight) this.createResizer ('bottom_right');
			if (hasBottomLeft) this.createResizer ('bottom_left');
			if (hasTopRight) this.createResizer ('top_right');
			if (hasTopLeft) this.createResizer ('top_left');
		},
		
		createResizer : function (position) {
			var dom = document.createElement ('div');
			dom.className = this.cssClassBase + ' ' + this.cssClassBase + '_' + position;
			dom.innerHTML = ' ';
			var dm = directionMapping[position];
			
			var temp = new Logi.UI.DragNDrop.Listener (this.containerClassName, this.cssClassBase + '_' + position,
				new Logi.UI.DragNDrop.Resizer (dm[0], dm[1], this.minWidth, this.minHeight));
			
			this.container.appendChild (dom);
			this.dom[position] = dom;
		}
		
	});

})();

