Components.utils['import']('resource://livemargins/utils.jsm');

var dockable = {
//dock handling
	debug : false,
	_hidding: true,
	get hiding() {
		return this._hidding;
	},
	set hiding(hidding) {
		this._hidding = hidding;
		return this._hidding;
	},
	hideTimeout : 1000,
	mouseoutHideTime : 100,
	showTimeout : 500,
	dragoverShowtime : 100,
	_docked: false,
	_lastWindowLayer: 0,
	get docked() {
		return this._docked;
	},
	set docked(docking) {
		if (docking) {
			if (!this._docked) {
				this._docked = true;
				this._lastWindowLayer = windowTools.windowLayer;
				windowTools.windowLayer = 2;
				// Make sure use can not set window not on top.
				document.getElementById("ontop-button").setAttribute("disabled", "true");
			}
		} else {
			if (this._docked) {
				windowTools.windowLayer = this._lastWindowLayer;
				this._docked = false;
				document.getElementById("ontop-button").setAttribute("disabled", "false");
			}
		}
	},
	dockDirection : 0, // 1 for top , 2 for right, 3 for bottom, 4 for left
	directions: {none: 0, top: 1, right: 2, bottom: 3, left: 4},
	dockTimeout : null,	//this one is the timeout ID that was planed to happen
	dockDistance : 20,
	moveStepDistance : 30,
	LOG : function(msg) {
		if (this.debug){
			try{
				var consoleService = Components.classes["@mozilla.org/consoleservice;1"].getService(Components.interfaces.nsIConsoleService);
				consoleService.logStringMessage("livemargins: Dockable functions " + msg);
			} catch(e){}
		}
	},
	
	logger: utils.logger('LM4.docable'),
	
	showAndHideDockable : function (withoutAnime) {
		var domChromeWindow = window.QueryInterface(Components.interfaces.nsIDOMChromeWindow);
		if (domChromeWindow.windowState == domChromeWindow.STATE_MINIMIZED) {
			this.logger.trace('Window has been minimized, ignore dockable.');
			return;	
		}
		
		var screenMan = Components.classes["@mozilla.org/gfx/screenmanager;1"]
                          .getService(Components.interfaces.nsIScreenManager);
		var newScreen = screenMan.screenForRect(window.screenX,window.screenY,window.innerWidth,window.innerHeight);
		var left = {}, top = {}, width = {}, height = {};
		newScreen.GetRect(left, top, width, height);
		var curScreen = {left: left.value, top: top.value, width: width.value, height: height.value};
		if (window.screenX > curScreen.left && window.screenY > curScreen.top &&
				window.screenX + window.innerWidth < curScreen.left + curScreen.width &&
				window.screenY + window.innerHeight < curScreen.top + curScreen.height) {
			// inside the current screen. No docking!
			this.docked = false;
			return;
		}
		//this.LOG("the window is in screen with : " +[left.value, top.value, width.value, height.value]);
		if (withoutAnime) {
			if (this.docked == true) {
				if (this.hiding == true) {
					if (this.dockDirection == this.directions.right) {
						window.moveTo(curScreen.left + curScreen.width - 5,window.screenY);
					} else if (this.dockDirection == this.directions.left) {
						window.moveTo(curScreen.left + 5 - window.outerWidth,window.screenY);
					} else if (this.dockDirection == this.directions.top) {
						window.moveTo(window.screenX,curScreen.top + 5 - window.outerHeight);
					} else if (this.dockDirection == this.directions.bottom) {
						window.moveTo(window.screenX,curScreen.top + curScreen.height - 5);
					}
				}
				else {
					if (this.dockDirection == this.directions.right) {
						window.moveTo(curScreen.left + curScreen.width - window.outerWidth + 2,window.screenY);
					}else if (this.dockDirection == this.directions.left) {
						window.moveTo(curScreen.left,window.screenY);
					}else if (this.dockDirection == this.directions.top) {
						window.moveTo(window.screenX,curScreen.top);
					}else if (this.dockDirection == this.directions.bottom) {
						window.moveTo(window.screenX,curScreen.top + curScreen.height - window.outerHeight);
					}
				}
			}
		} else {
			if (this.docked == true) {
				if (this.hiding == true) {
					if (this.dockDirection == this.directions.right) {
						if (window.screenX < curScreen.left + curScreen.width -5) {
							window.moveTo(Math.min(curScreen.left + curScreen.width - 5, window.screenX +dockable.moveStepDistance),window.screenY);
							window.setTimeout(function () {dockable.showAndHideDockable();},20);
						}
					}else if (this.dockDirection == this.directions.left) {
						if (window.screenX + window.outerWidth > curScreen.left + 5) {
							window.moveTo(Math.max(curScreen.left + 5 - window.outerWidth, window.screenX - dockable.moveStepDistance),window.screenY);
							window.setTimeout(function () {dockable.showAndHideDockable();},20);
						}
					}else if (this.dockDirection == this.directions.top) {
						if (window.screenY > curScreen.top + 5 - window.outerHeight) {
							window.moveTo(window.screenX,Math.max(window.screenY - dockable.moveStepDistance, curScreen.top + 5 - window.outerHeight));
							window.setTimeout(function () {dockable.showAndHideDockable();},20);
						}
					}else if (this.dockDirection == this.directions.bottom) {
						if (window.screenY < curScreen.top + curScreen.height - 5) {
							window.moveTo(window.screenX,Math.min(window.screenY + dockable.moveStepDistance, curScreen.top + curScreen.height - 5));
							window.setTimeout(function () {dockable.showAndHideDockable();},20);
						}
					}
				} else {
					if (this.dockDirection == this.directions.right) {
						if (window.screenX + window.outerWidth > curScreen.left + curScreen.width + 2) {
							window.moveTo(Math.max(curScreen.left + curScreen.width - window.outerWidth + 2, window.screenX - dockable.moveStepDistance),window.screenY);
							window.setTimeout(function () {dockable.showAndHideDockable();},20);
						}
					}else if (this.dockDirection == this.directions.left) {
						if (window.screenX < curScreen.left) {
							window.moveTo(Math.min(curScreen.left, window.screenX + dockable.moveStepDistance),window.screenY);
							window.setTimeout(function () {dockable.showAndHideDockable();},20);
						}
					}else if (this.dockDirection == this.directions.top) {
						if (window.screenY < curScreen.top) {
							window.moveTo(window.screenX,Math.min(window.screenY + dockable.moveStepDistance,curScreen.top));
							window.setTimeout(function () {dockable.showAndHideDockable();},20);
						}
					}else if (this.dockDirection == this.directions.bottom) {
						if (window.screenY > curScreen.top + curScreen.height - window.outerHeight) {
							window.moveTo(window.screenX,Math.min(window.screenY - dockable.moveStepDistance, curScreen.top + curScreen.height - window.outerHeight));
							window.setTimeout(function () {dockable.showAndHideDockable();},20);
						}
					}
				}
			}
		}
	},
	moveHandlerOld : function(event) {
//		this.LOG("move handler");
		if (dockable) {
	//if window is outside the screen, get it back
			var screenMan = Components.classes["@mozilla.org/gfx/screenmanager;1"]
                          .getService(Components.interfaces.nsIScreenManager);
			var newScreen = screenMan.screenForRect(window.screenX,window.screenY,window.innerWidth,window.innerHeight);
			var left = {}, top = {}, width = {}, height = {};
			newScreen.GetRect(left, top, width, height);
			var curScreen = {left: left.value, top: top.value, width: width.value, height: height.value};
			//this.LOG("the window is in screen with : " +[left.value, top.value, width.value, height.value]);
			var newX = window.screenX;
			var newY = window.screenY;
			var newDocked = false;
			var newDockDirection = 0;
			if (window.screenY + window.outerHeight >= curScreen.top + curScreen.height) {  // dock to bottom
				newY = curScreen.top + curScreen.height - window.outerHeight;
				newDocked = true;
				newDockDirection = dockable.directions.bottom;
			}
			if (window.screenY <= curScreen.top) {	// dock to top
				newY = curScreen.top;
				newDocked = true;
				newDockDirection = dockable.directions.top;
			}
			if (window.screenX >= curScreen.left + curScreen.width - window.outerWidth) {		//dock to right
				newX = curScreen.left + curScreen.width - window.outerWidth + 2;
				newDocked = true;
				newDockDirection = dockable.directions.right;
			}
			if (window.screenX <= curScreen.left) {	// dock to left
				newX = curScreen.left;
				newDocked = true;
				newDockDirection = dockable.directions.left;
			}
			
			window.moveTo(newX,newY);
			if (dockable.docked != newDocked || dockable.dockDirection != newDockDirection) {
				dockable.docked = newDocked;
				dockable.dockDirection = newDockDirection;
				this.sendUIEvent("dockChanged");
			}
		}
	},
	guessDockedOld: function() {
//		this.LOG("move handler");
		if (dockable) {
	//if window is outside the screen, get it back
			var screenMan = Components.classes["@mozilla.org/gfx/screenmanager;1"]
                          .getService(Components.interfaces.nsIScreenManager);
			var newScreen = screenMan.screenForRect(window.screenX,window.screenY,window.innerWidth,window.innerHeight);
			var left = {}, top = {}, width = {}, height = {};
			newScreen.GetRect(left, top, width, height);
			var curScreen = {left: left.value, top: top.value, width: width.value, height: height.value};
			//this.LOG("the window is in screen with : " +[left.value, top.value, width.value, height.value]);
			var newX = window.screenX;
			var newY = window.screenY;
			var newDocked = false;
			var newDockDirection = 0;
			if (window.screenY + window.outerHeight >= curScreen.top + curScreen.height) {  // dock to bottom
				newY = curScreen.top + curScreen.height - window.outerHeight;
				newDocked = true;
				newDockDirection = dockable.directions.bottom;
			}
			if (window.screenY <= curScreen.top) {	// dock to top
				newY = curScreen.top;
				newDocked = true;
				newDockDirection = dockable.directions.top;
			}
			if (window.screenX >= curScreen.left + curScreen.width - window.outerWidth) {		//dock to right
				newX = curScreen.left + curScreen.width - window.outerWidth + 2;
				newDocked = true;
				newDockDirection = dockable.directions.right;
			}
			if (window.screenX <= curScreen.left) {	// dock to left
				newX = curScreen.left;
				newDocked = true;
				newDockDirection = dockable.directions.left;
			}
			
//			window.moveTo(newX,newY);
			if (dockable.dockDirection != newDockDirection) {
				//dockable.docked = newDocked;
				dockable.dockDirection = newDockDirection;
				//this.sendUIEvent("dockChanged");
			}
			return newDocked;
		}
	},
	moveHandler : function(event) {//handle the case that the window is not moveable
//		this.LOG("move handler");
		this.LOG(JSON.stringify(event));
		if (dockable) {
	//if window is outside the screen, get it back
			var screenMan = Components.classes["@mozilla.org/gfx/screenmanager;1"]
                          .getService(Components.interfaces.nsIScreenManager);
			var newScreen = screenMan.screenForRect(window.screenX,window.screenY,window.innerWidth,window.innerHeight);
			var left = {}, top = {}, width = {}, height = {};
			newScreen.GetRect(left, top, width, height);
			var curScreen = {left: left.value, top: top.value, width: width.value, height: height.value};
			//this.LOG("the window is in screen with : " +[left.value, top.value, width.value, height.value]);
			var newX = window.screenX;
			var newY = window.screenY;
			if (window.screenY + 10 >= curScreen.top + curScreen.height) {  //too low to drag
				newY = curScreen.top + curScreen.height - window.outerHeight;
			}
			if (window.screenY + 10 <= curScreen.top) {	// too high to drag
				newY = curScreen.top;
			}
			if (window.screenX + 30 >= curScreen.left + curScreen.width) {		// right
				newX = curScreen.left + curScreen.width - window.outerWidth + 2;
			}
			if (window.screenX + window.outerWidth - 80 <= curScreen.left) {	// left
				newX = curScreen.left;
			}
			if (dockable.docked == true) {
				dockable.hiding = true;
				dockable.showAndHideDockable();
			}
			if (newX != window.screenX || newY != window.screenY) {
				window.moveTo(newX,newY);
			}
		}
	},
	mouseMoveHandler : function(event) {
//		this.LOG("move handler that handles mouse move event while mouse is down");
//		this.LOG(JSON.stringify(event));
		if (dockable) {
	//if window is outside the screen, get it back
			var screenMan = Components.classes["@mozilla.org/gfx/screenmanager;1"]
                          .getService(Components.interfaces.nsIScreenManager);
			var newScreen = screenMan.screenForRect(window.screenX,window.screenY,window.innerWidth,window.innerHeight);
			var left = {}, top = {}, width = {}, height = {};
			newScreen.GetRect(left, top, width, height);
			var curScreen = {left: left.value, top: top.value, width: width.value, height: height.value};

			var newDocked = false;
			var newDockDirection = 0;
//			if (dockable.docked == false) {
				if (event.screenY > curScreen.top + curScreen.height - dockable.dockDistance) {
					newDocked = true;
					newDockDirection = dockable.directions.bottom;
				}
				//top is special, has to detect whether the window is outside the screen.
				if (event.screenY < curScreen.top + dockable.dockDistance && window.screenY < curScreen.top) {
					newDocked = true;
					newDockDirection = dockable.directions.top;
				}
				if (event.screenX < curScreen.left + dockable.dockDistance) {
					newDocked = true;
					newDockDirection = dockable.directions.left;
				}
				if (event.screenX >= curScreen.left + curScreen.width - dockable.dockDistance) {
					newDocked = true;
					newDockDirection = dockable.directions.right;
				}
//			} else {
//				newDocked = dockable.guessDockedOld();
//				newDockDirection = dockable.dockDirection;	//guessDockedOld change dockedDirection already.
//			}
//			window.moveTo(newX,newY);
			if (dockable.docked != newDocked || dockable.dockDirection != newDockDirection) {
				dockable.docked = newDocked;
				dockable.dockDirection = newDockDirection;
				this.sendUIEvent("dockChanged");
				// if (newDocked == true) {
					// window.clearTimeout(dockable.dockTimout);
					// dockable.dockTimout = window.setTimeout(function() {
						// dockable.hiding = true;
						// dockable.showAndHideDockable();
					// },100);
				// }
			}
		}
	},
	sendUIEvent : function(type,detail) {
		try{
			if (detail == null) detail = 0;
			e = document.createEvent("UIEvents");
			e.initUIEvent(type, true, true, window, detail);
			window.dispatchEvent(e);
		} catch (e) {
			this.LOG(e.toString());
		}
	}
}

window.addEventListener("mouseover",function(event) {
	window.clearTimeout(dockable.dockTimout);
	dockable.dockTimout = window.setTimeout(function () {
		dockable.hiding = false;
		dockable.showAndHideDockable();
	}, dockable.showTimeout);
}, false);
		
window.addEventListener("mouseout",function(event){
	window.clearTimeout(dockable.dockTimout);
	dockable.dockTimout = window.setTimeout(function () {
		dockable.hiding = true;
		dockable.showAndHideDockable();
	}, dockable.mouseoutHideTimeout);
}, false);

window.addEventListener("dragover",function(event) {
	dockable.hiding = false;
	//dockable.mouseOver = true;
	window.clearTimeout(dockable.dockTimout);
	dockable.dockTimout = window.setTimeout(function () {dockable.showAndHideDockable();},dockable.dragoverShowTimeout);
},false);

window.addEventListener("focus",function(event) {
	window.clearTimeout(dockable.dockTimout);
	dockable.dockTimout = window.setTimeout(function () {
		dockable.hiding = false;
		dockable.showAndHideDockable();
	}, dockable.showTimeout);
},true);

window.addEventListener("blur", function(event) {
	/*if (dockable.mouseOver == true){ //most likely it's caused by click on a flash
		return;
	}*/
	window.clearTimeout(dockable.dockTimout);
	dockable.dockTimout = window.setTimeout(function () {
		dockable.hiding = true; 
		dockable.showAndHideDockable();
	}, dockable.hideTimeout);
},true);

