dojo.provide("dojox.mdnd.dropMode.OverDropMode");

dojo.require("dojox.mdnd.AreaManager");

dojo.declare(
	"dojox.mdnd.dropMode.OverDropMode",
	null,
{
	// summary:
	//		Default class to find the nearest target only if the mouse is over an area.

	// _oldXPoint: Integer
	//		used to save a X position
	_oldXPoint: null,

	// _oldYPoint: Integer
	//		used to save a Y position
	_oldYPoint: null,

	// _oldBehaviour: Integer
	//		see getDragpoint()
	_oldBehaviour: "up",

	constructor: function(){
		//console.log("dojox.mdnd.dropMode.OverDropMode ::: constructor");
		this._dragHandler = [
			dojo.connect(dojox.mdnd.areaManager(), "onDragEnter", function(coords, size){
				var m = dojox.mdnd.areaManager();
				if(m._oldIndexArea == -1){
					m._oldIndexArea = m._lastValidIndexArea;
				}
			})
		];

	},

	addArea: function(/*Array*/areas, /*Object*/object){
		// summary:
		//		Add a D&D Area into an array sorting by the x position.
		// areas:
		//		array of areas
		// object:
		//		data type of a DndArea
		// returns:
		//		a sorted area

		//console.log("dojox.mdnd.dropMode.OverDropMode ::: addArea");
		var length = areas.length,
			position = dojo.position(object.node, true);
		object.coords = {'x':position.x, 'y':position.y};
		if(length == 0){
			areas.push(object);
		}
		else{
			var x = object.coords.x;
			for(var i = 0; i < length; i++){
				if(x < areas[i].coords.x){
					for(var j = length-1; j >= i; j--)
						areas[j + 1] = areas[j];
					areas[i] = object;
					break;
				}
			}
			if(i == length){
				areas.push(object);
			}
		}
		return areas;	// Array
	},

	updateAreas: function(/*Array*/areaList){
		// summary:
		//		refresh areas position and size to determinate the nearest area to drop an item
		// description:
		//		the area position (and size) is equal to the postion of the domNode associated.
		// areaList:
		//		array of areas

		//console.log("dojox.mdnd.dropMode.OverDropMode ::: updateAreas");
		var length = areaList.length;
		for(var i = 0; i < length; i++){
			this._updateArea(areaList[i]);
		}
	},

	_updateArea : function(/*Object*/area){
		// summary:
		//		update the D&D area object (i.e. update coordinates of its DOM node)
		// area:
		// 		the D&D area.
		// tags:
		//		protected

		//console.log("dojox.mdnd.dropMode.OverDropMode ::: addArea");
		var position = dojo.position(area.node, true);
		area.coords.x = position.x;
		area.coords.x2 = position.x + position.w;
		area.coords.y = position.y;
	},

	initItems: function(/*Object*/area){
		// summary:
		//		initialize the horizontal line in order to determinate the drop zone.
		// area:
		//		the D&D area.

		//console.log("dojox.mdnd.dropMode.OverDropMode ::: initItems");
		dojo.forEach(area.items, function(obj){
			//get the vertical middle of the item
			var node = obj.item.node;
			var position = dojo.position(node, true);
			var y = position.y + position.h/2;
			obj.y = y;
		});
		area.initItems = true;
	},

	refreshItems: function(/*Object*/area, /*Integer*/indexItem, /*Object*/size, /*Boolean*/added){
		// summary:
		//		take into account the drop indicator DOM element in order to compute horizontal lines
		// area:
		//		a D&D area object
		// indexItem:
		//		index of a draggable item
		// size:
		//		dropIndicator size
		// added:
		//		boolean to know if a dropIndicator has been added or deleted

		//console.log("dojox.mdnd.dropMode.OverDropMode ::: refreshItems", area, indexItem, size, added);
		if(indexItem == -1){
			return;
		}
		else if(area && size && size.h){
			var height = size.h;
			if(area.margin){
				height += area.margin.t;
			}
			var length = area.items.length;
			for(var i = indexItem; i < length; i++){
				var item = area.items[i];
				if(added){
					item.y += height;
				}
				else{
					item.y -= height;
				}
			}
		}
	},

	getDragPoint: function(/*Object*/coords, /*Object*/size, /*Object*/mousePosition){
		// summary:
		//		return coordinates of the draggable item.
		//		- For X point : the x position of mouse
		//		- For Y point : the y position of mouse
		// returns:
		//		an object of coordinates
		// 		examples:{'x':10,'y':10}
		// coords:
		//		an object encapsulating X and Y position
		// size:
		// 		an object encapsulating width and height values
		// mousePosition:
		// 		coordinates of mouse

		//console.log("dojox.mdnd.OverDropMode ::: getDragPoint");
		return {			// Object
			'x': mousePosition.x,
			'y': mousePosition.y
			}
	},


	getTargetArea: function(/*Array*/areaList, /*Object*/ coords, /*integer*/currentIndexArea ){
		// summary:
		//		get the nearest D&D area.
		// areaList:
		// 		a list of D&D areas objects
		// coords:
		//		coordinates [x,y] of the dragItem (see getDragPoint())
		// currentIndexArea:
		//		an index representing the active D&D area
		//returns:
		//		the index of the D&D area

		//console.log("dojox.mdnd.dropMode.OverDropMode ::: getTargetArea");
		var index = 0;
		var x = coords.x;
		var y = coords.y;
		var end = areaList.length;
		var start = 0, direction = "right", compute = false;
		if(currentIndexArea == -1 || arguments.length < 3){
			// first time : Need to search the nearest area in all areas.
			compute = true;
		}
		else{
			// check if it's always the same area
			if(this._checkInterval(areaList, currentIndexArea, x, y)){
				index = currentIndexArea;
			}
			else{
				if(this._oldXPoint < x){
					start = currentIndexArea + 1;
				}
				else{
					start = currentIndexArea - 1;
					end = 0;
					direction = "left";
				}
				compute = true;
			}
		}
		if(compute){
			if(direction === "right"){
				for(var i = start; i < end; i++){
					if(this._checkInterval(areaList, i, x, y)){
						index = i;
						break;
					}
				}
				if(i == end){
					index = -1;
				}
			}
			else{
				for(var i = start; i >= end; i--){
					if(this._checkInterval(areaList, i, x, y)){
						index = i;
						break;
					}
				}
				if(i == end-1){
					index = -1;
				}
			}
		}
		this._oldXPoint = x;
		return index; // Integer
	},

	_checkInterval: function(/*Array*/areaList, /*Integer*/index, /*Coord*/x, /*Coord*/y){
		// summary:
		//		check if the dragNode is in the interval.
		// returns:
		//		true if the dragNode is in intervall
		// areaList:
		//		a list of D&D areas objects
		// index:
		//		index of a D&D area (to get the interval)
		// x:
		//		coordinate x, of the dragNode (see getDragPoint())
		// tags:
		//		protected

		//console.log("dojox.mdnd.dropMode.OverDropMode ::: _checkInterval");
		var area = areaList[index];
		var node = area.node;
		var coords = area.coords;
		var startX = coords.x;
		var endX = coords.x2;
		var startY = coords.y;
		var endY = startY + node.offsetHeight;
		if(startX <= x && x <= endX && startY <= y && y <= endY){
			return true;
		}
		return false; // Boolean
	},

	getDropIndex: function(/*Object*/ targetArea, /*Object*/ coords){
		// summary:
		//		Return the index where the drop has to be placed.
		// targetArea:
		//		a D&D area object.
		// coords:
		//		coordinates [x,y] of the draggable item.
		// returns:
		//		a number or -1 if the area has no children or the drop index represents the last position in to the area

		//console.log("dojox.mdnd.dropMode.OverDropMode ::: getDropIndex");
		var length = targetArea.items.length;
		var coordinates = targetArea.coords;
		var y = coords.y;
		if(length > 0){
			// course all children in the target area.
			for(var i = 0; i < length; i++){
				// compare y value with y value of children
				if(y < targetArea.items[i].y){
					return i;	// integer
				}
				else{
					if(i == length-1){
						return -1; // integer
					}
				}
			}
		}
		return -1;	//integer
	},

	destroy: function(){
		dojo.forEach(this._dragHandler, dojo.disconnect);
	}
});

(function(){
	dojox.mdnd.areaManager()._dropMode = new dojox.mdnd.dropMode.OverDropMode();
}());
