/* The window manager will control all movement, addition,
 * removal and other control of the windows.  The windows
 * themselves are moved by changing values in the window manager
 * and redrawing.  This should reduce DOM calls, increasing 
 * performance.*/ 
function WindowManager(){
    
    if(theWindowManager)
	return theWindowManager;

    this.windows = new Array();
    this.activeWindow = null;
    
}

WindowManager.prototype = {

    /* Returns the selected active window currently in use by the
     * user.  This can ignore certain windows as they might not need
     * to be selected. */
    getActiveWindow : function(name,x,y) {
	return this.activeWindow;
    },
    
    /* Add a new window to the current browser window.  Requires
     * name, height, width, and an x,y point to add at, usually a
     * mouse location or a standard location (i.e. top left for
     * new files).*/
    addWindow : function(name,x,y,width,height) {
	win = new Window(name,x,y,width,height);
	this.windows.push(win);	
	win.window.style.zIndex = this.windows.length;
	win.setupHandlers();
	this.makeActive(win);
    },

    /* Make a window active.  If no active window exists, usually when
     * only one window exists, make it active and give it zindex of the
     * length of the window list.  If other windows exists and the
     * window is taking focus away from a different active window,
     * reduce zindex of all windows with higher zindex and make them
     * inactive, then make the window active and give it the highest
     * zindex.*/
    makeActive : function(window) {
	if(this.activeWindow == null){
	    window.window.style.zIndex = this.windows.length;
	    this.activeWindow = window;
	    return;
	}

	zIdx = window.window.style.zIndex;
	for (i=0;i<this.windows.length;i++){
	    if(win.window.style.zIndex > zIdx){
		win.window.style.zIndex -= 1;
	    }
	}
	this.activeWindow.titleBar.className = "inactiveTitleBar";
	window.titleBar.className = "activeTitleBar";	
	this.activeWindow = window;
	window.window.style.zIndex = this.windows.length;
    },
    
    /* Removes a window from the windowManager */
    removeWindow : function(name) {
	
    },

}

var theWindowManager = new WindowManager();

/* Window, the heart of this file.  A window is created by specifying
 * a set of values and using a template for colors/images to use as
 * buttons and borders.*/

function Window(name,x,y,width,height){
    
    this.window = document.createElementNS("http://www.w3.org/1999/xhtml", "div");
    this.status = "open";
    this.height = height;
    this.width = width;
    this.minWindowWidth = 100;
    this.minWindowHeight = 100;
    this.x = x;
    this.y = y;
    this.name = name;

    /*Setup class, mouse movement handler of window*/
    this.window.className = "openWindow";

    /* Create title bar div, assign titleBar class*/
    this.titleBar = document.createElementNS("http://www.w3.org/1999/xhtml", "div");
    this.titleBar.setAttribute('class', 'activeTitleBar');

    /* Setup the window area where canvas, text, etc.
     * will be located.*/
    this.windowArea = document.createElementNS("http://www.w3.org/1999/xhtml", "div");
    this.windowArea.className = 'windowArea';
    
    /*Create buttons for closing and minimizing a window.*/
    this.closeButton = document.createElementNS("http://www.w3.org/1999/xhtml", "img");
    this.closeButton.setAttribute("src", "./close.gif");
    this.closeButton.className = "titleBarButtons";

    this.minMaxButton = document.createElementNS("http://www.w3.org/1999/xhtml", "img");
    this.minMaxButton.src = "./min.gif";
    this.minMaxButton.className = "titleBarButtons";

    /*Set name and add buttons to window.*/
    this.titleBarText = document.createElementNS("http://www.w3.org/1999/xhtml", "span");
    var text = document.createTextNode(this.name);
    this.titleBarText.className = "titleBarText";
    this.titleBarText.appendChild(text);

    /* Finally, set name, append child windows 
     * and append it into document.*/
    this.titleBar.appendChild(this.titleBarText);
    this.titleBar.appendChild(this.minMaxButton);
    this.titleBar.appendChild(this.closeButton);
    this.window.appendChild(this.titleBar);
    this.window.appendChild(this.windowArea);

    this.draw();
    var rootNode = document.getElementById('rootNode');
    rootNode.appendChild(this.window);
}

Window.prototype = {

    /* Setup the event handlers, so we don't need to create
     * them again later*/
    setupHandlers : function(){
	this.startWinResize = this.makeStartWinResize(this);
	this.winResize = this.makeWinResize(this);
	this.stopWinResize = this.makeStopWinResize(this);
	this.setCursor = this.makeSetCursor(this);
	this.startWinMove = this.makeStartWinMove(this);
	this.close = this.makeClose(this);
	this.minimize = this.makeMinimize(this);
	this.winMove = this.makeWinMove(this);
	this.stopWinMove = this.makeStopWinMove(this);
	this.startWinMove = this.makeStartWinMove(this);
	this.restore = this.makeRestore(this);

	/* Initialize event handlers */
	this.window.onmousemove = this.setCursor;
	this.titleBar.onmousedown = this.startWinMove;
	this.closeButton.onmousedown = this.close;
	this.minMaxButton.onmousedown = this.minimize;

    },

    /* Set min height and width, if not executed, default 
     * values are used*/
    setMinHeightWidth : function(minWidth, minHeight){
	this.minWindowHeight = minHeight;
	this.minWindowWidth = minWidth;
    },
    
    /*Redraws the window after all attributes are set.*/
    draw : function(){
	/* Area hieght is the height of the window content area
	 * textWidth is the width of the span containing the title
	 * on the title bar of the window */
	this.areaHeight = (this.height-37) + "px";
	this.textWidth = (this.width-34) + "px"; 

	/* Set window width, x, y location*/
	this.window.style.width = this.width + "px";
	this.window.style.top = this.y+"px";
	this.window.style.left = this.x+"px";
	
	/* Set window height by setting height of inner
	 * content div.*/
	this.windowArea.style.height = this.areaHeight;
	/* Set title text width to accomidate min/max 
	 * and close buttons*/
	this.titleBarText.style.width = this.textWidth;
	//done drawing.
    },

    /* Change mouse cursor according to location on window, 
     * also sets resize direction*/
    makeSetCursor : function(win) {
	return function(e) {
	    win.offsetX = win.window.offsetLeft - e.pageX;
	    win.offsetY = win.window.offsetTop - e.pageY;
	    win.resizeDirection = "";
	    if( Math.abs(win.offsetY) <= 8)
		win.resizeDirection += "n";
	    else if (Math.abs(win.offsetY) >= (win.height-8))
		win.resizeDirection += "s";
	    if( Math.abs(win.offsetX) <= 8)
		win.resizeDirection += "w";
	    else if (Math.abs(win.offsetX) >= (win.width-8))
		win.resizeDirection += "e";
	    if(win.resizeDirection != ""){
		document.body.style.cursor = win.resizeDirection + "-resize";
		document.onmousedown = win.startWinResize;
	    }
	    else{
		document.body.style.cursor = "";
		document.onmousedown = null;
	    }
	}
    },

    /* Mouse down event handler for resizing a given window*/
    makeStartWinResize : function(win) {
	return function(e) {
	    var wm = new WindowManager();
	    wm.makeActive(win);
	    
	    win.startX = e.pageX;
	    win.startY = e.pageY;

	    win.window.onmousemove = null;
	    document.onmousemove = win.winResize;
	    document.onmouseup = win.stopWinResize;
	}
    },
    
    /*Handles mouse movements as window resizing directions*/
    makeWinResize : function(win) {
	return function(e){
	    var dy = e.pageY - win.startY;
	    var dx = e.pageX - win.startX;
	    win.startY = e.pageY;
	    win.startX = e.pageX;

	    if(win.resizeDirection.indexOf('n') != -1){
		var newHeight = (win.height - dy);
		if(newHeight >= win.minWindowHeight){
		    win.height = newHeight;
		    win.y = (e.pageY + win.offsetY);
		}
	    }
	    else if(win.resizeDirection.indexOf('s') != -1){
		var newHeight = (win.height + dy);
		if(newHeight >= win.minWindowHeight){
		    win.height = newHeight;
		}
	    }
	    if(win.resizeDirection.indexOf('w') != -1){
		var newWidth = (win.width - dx);
		if(newWidth >= win.minWindowWidth){
		    win.width = newWidth;
		    win.x = win.x + dx;
		}
	    }
	    else if(win.resizeDirection.indexOf('e') != -1){
		var newWidth = (win.width + dx);
		if(newWidth >= win.minWindowWidth){
		    win.width = newWidth;
		}
	    }
	    win.draw();
	}
    },

    /* Stops the mouse move listener after mouse comes up 
     * on window resize */
    makeStopWinResize : function(win) {
	return function(e){
	    win.resizeDirection = "";
	    document.body.style.cursor = "";
	    win.window.onmousemove = win.setCursor;
	    document.onmousemove = null;
	    document.onmouseup = null;
	}
    },	    

    /* Mouse down event handler for title bar*/
    makeStartWinMove : function(win) {
	return function(e) {
	    var wm = new WindowManager();
	    wm.makeActive(win);
	    
	    win.offsetX = win.window.offsetLeft - e.pageX;
	    win.offsetY = win.window.offsetTop - e.pageY;

	    win.window.onmousemove = null;
	    document.onmousemove = win.winMove;
	    document.onmouseup = win.stopWinMove;
	}
    },

    makeWinMove : function(win) {
	return function(e) {
	    win.y = (e.pageY + win.offsetY);
	    win.x = (e.pageX + win.offsetX);
	    win.draw();
	}
    },

    /* Mouse down event handler for title bar*/
    makeStopWinMove : function(win) {
	return function(e) {
	    win.window.onmousemove = win.setCursor;
	    document.onmousemove = null;
	    document.onmouseup = null;
	}
    },

    /* Add a child node to a windowArea, basically
     * a way to set content to any generated, selected
     * node.*/
    addChild : function(node) {
	this.windowArea.appendChild(node);
    },

    /* Set the name of a window as it appears in the 
     * title bar of that window. */
    setName : function(name) {
	this.name = name;
	this.draw();
    },
    
    /* Open the window by changing the class to 
     * openWindow.*/
    open : function() {
	if(this.status != "open"){
	    this.status = "open";
	    this.window.className = "openWindow";
	}
	else
	    return;
    },
    
    /* Closes a window in that it's invisible, but not 
     * deleted from the DOM or window manager.*/
    makeClose : function(win){
	return function(e) {
	    if(win.status != "closed"){
		win.status = "closed";
		win.window.className = "closedWindow";
	    }
	    else
		return;
	}
    },

    /* Hide window content so only the title bar is showing.*/
    makeMinimize : function(win) {
	return function(e) {
	    if(win.status != "minimized"){
		win.minMaxButton.src = "./max.gif";
		win.minMaxButton.onmousedown = win.restore;
		win.status = "minimized";	
		win.windowArea.style.height = 0+"px";
		win.windowArea.className = "minWindowArea";
	    }
	    else
		return;
	}
    },
    
    /* Restore a window to its normal content displaying mode.*/
    makeRestore : function(win) {
	return function(e) {
	    if(win.status == "minimized"){
		win.status = "open";
		win.minMaxButton.src = "./min.gif";
		win.minMaxButton.onmousedown = win.minimize;
		win.windowArea.style.height = win.areaHeight;
		win.windowArea.className = "windowArea";
	    }
	    else
		return;
	}
    },
    
    /* Make the window active in the window manager */
    makeActive : function() {
	var wm = new WindowManager();
	wm.makeActive(this);
    },
}
