// $Id: window-core.js 5100 2006-11-14 13:24:37Z slip $
/**
 *
 * Copyright (c) 2006 by SouthProjects
 * http://www.southprojects.com
 * Santiago, Chile,
 * Version 1.2 Dec 2006.
 * All rights reserved.
 */

/**
 * The Window object constructor.  Call it, for example, like this:
 *
 * \code
 *   var win = new southprojects.Window({
 *   	showResize : false
 *   });
 * \endcode
 *
 * The above creates a new Window object.  The Window isn't displayed
 * instantly; using the "win" variable, the programmer can now set certain
 * configuration variables, hook his own event handlers and then display the
 * window using southprojects.Window.create() and southprojects.Window.show().
 *
 * @param config [object] - all parameters are passed as the properties of this object.
 * 
 * Constructor recognizes the following properties of the config object
 * \code
 *    prop. name     | description
 *  -------------------------------------------------------------------------------------------------
 *   showMinButton   | whether to show minimize button (default true).
 *   showMaxButton   | whether to show maximize button (default true).
 *   showCloseButton | whether to show close button (default true).
 *   showStatus      | whether to show status bar text (default true).
 *   canResize       | whether to show resize icon (default true).
 *   raiseOnlyOnTitle| whether to raize when clicking on title or on the whole body of the created window (default true).
 *   canDrag         | whether you can drag the window (default true).
 *   modal           | if true modal window will be created (default false).
 *   onClose         | custom handler, will be called when window is closed.
 *   onRestore       | custom handler, will be called when restore button is clicked.
 *   onMinimize      | custom handler, will be called when min button is clicked.
 *   onMaximize      | custom handler, will be called when max button is clicked.
 *   onShow          | custom handler, will be called when show method is called.
 *   onHide          | custom handler, will be called when hide method is called.
 *   onResize        | custom handler, will be called when window is resized.
 *   onRaise         | custom handler, will be called when window is raized.
 *   onContentLoad   | custom handler, will be called when content is loaded.
 *   minWidth        | minimal width of the window.
 *   minHeight       | minimal height of the window.
 *   iframeContent   | type of the content element.
 *   hideOnClose     | whether we destroy the window or just close
 *   dragMin         | is minimized draggable or not (default false)
 *   bottomMinimize  | is the window minimized to the bottom or just stay at its position
 *   
 * \endcode
 */
southprojects.Window = function (config) {
	//the reference to the root HTML element of the window
	this.container = null;
	//reference to the element which holds the title bar
	this.titleArea = null;
	//reference to the element which holds the title text
	this.titleText = null;
	//reference to the southprojects.Button object representing minimize button
	this.minButton = null;
	//reference to the southprojects.Button object representing maximize button
	this.maxButton = null;
	//reference to the southprojects.Button object representing close button
	this.closeButton = null;
	//reference to the southprojects.Pane object representing content of the window
	this.content = null;	
	//reference to the element holding status area element
	this.statusText = null;
	//reference to a Draggable object for this window
	this.draggable = null;
	//reference to the Modal object of this window
	this.modal = null;
	//reference to the cover element used for covering all the screen
	//when working with mouse events
	this.cover = null;
	//the number of the window
	this.winNumber = 0;
	//flag which determines if the window is resizing
	this.resizing = false;
	//type of the widget - window in our case :)
	this.widgetType = "window";
	//widget privillage modes
	this.widgetModes = {};
	//high priority events
	this.highPriorityEvents = [];
	//delayed events
	this.delayedEvents = [];
	//this variable points the state of the widget in general.
	//The widget has a set of states 4 of them should go one after another ('created' -> 'inited' -> 'loaded' -> 'ready')
	//and point to the stage of creation of widget. Last one should be 'ready', 
	//which means a fully ready for work widget. Each of the methods can require
	//the state to be not lower than it needs. So we will also define a method
	//to work with this variable - stateReached(state) - to get true if state reached or passed.
	this.widgetState = "created";
	//array of priorities for states, in other words its the number which points the order
	// of states to be passed.
	this.priorities = {
		//the number of states supported
		count : 7,
		//states priorities
		destroyed : 0,
		created : 1,
		inited : 2,
		loaded : 3,
		ready : 4,
		hidden : 5,
		shown : 6
	};
	this.setDefaultState();
	//calling super constructor
	southprojects.Window.SUPERconstructor.call(this, config);
	//creating SRProp object for manipulating with our object
	this.restorer = new southprojects.Utils.SRProp(this);
};

southprojects.Window.id = "southprojects.Window";

//Inheriting southprojects.Widget class
southprojects.inherit(southprojects.Window, southprojects.Widget);

/**
 * This function inits the config object and loads HTML structure
 * of the window, not to waste time :)
 * @param config [object] - object which holds the configuration, same as for constructor
 */
southprojects.Window.prototype.init = function(config) {
	//creating config object and defining default values for it
	//to use zpwidget class possibilities.
	//wether title is visible
	this.config.valor=-1;
	this.config.showTitle = true;
	//wethter min button is visible
	this.config.showMinButton = true;
	//wethter max button is visible
	this.config.showMaxButton = true;
	//wethter close button is visible
	this.config.showCloseButton = true;
	//wethter status bar is visible
	this.config.showStatus = true;
	//wethter window is resizable
	this.config.canResize = true;
	//wether to raise only on clicking the title
	this.config.raiseOnlyOnTitle = false;
	//wether window is draggable
	this.config.canDrag = true;
	//wether window is modal
	this.config.modal = false;
	//custom handler called on close action
	this.config.onClose = null;
	//custom handler called on restore action
	this.config.onRestore = null;
	//custom handler called on maximize action
	this.config.onMaximize = null;
	//custom handler called on minimize action
	this.config.onMinimize = null;
	//custom handler called on show action
	this.config.onShow = null;
	//custom handler called on hide action
	this.config.onHide = null;
	//custom handler called on resize action
	this.config.onResize = null;
	//custom handler called on raise action
	this.config.onRaise = null;
	//minimal width of the window
	this.config.minWidth = 120;
	//minimal height of the window
	this.config.minHeight = 80;
	//should we show content in IFRAME Pane or just simple div Pane
	this.config.iframeContent = false;
	//custom handler called after the content is loaded
	this.config.onContentLoad = null;
	//do we hide on close or destroy
	this.config.hideOnClose = false;
	//is minimized window draggable
	this.config.dragMin = false;
	//do we minimize to the bottom
	this.config.bottomMinimize = true;
	//default theme winxp
	this.config.theme = "winxp";
	//we need the HTML part of our window to be loaded, so defining the source and sourceType
	config.sourceType = "html/url";
    //Get path to module.
	config.source = southprojects.Window.path + "struc.html";
	// processing Widget functionality
	southprojects.Window.SUPERclass.init.call(this, config);
	
	this.addEventListener("onClose", this.config.onClose);
	this.addEventListener("onRestore", this.config.onRestore);
	this.addEventListener("onMaximize", this.config.onMaximize);
	this.addEventListener("onMinimize", this.config.onMinimize);
	this.addEventListener("onShow", this.config.onShow);
	this.addEventListener("onHide", this.config.onHide);
	this.addEventListener("onResize", this.config.onResize);
	this.addEventListener("onRaise", this.config.onRaise);
	this.addEventListener("onContentLoad", this.config.onContentLoad);
	this.addEventListener("privileged_execution_on", function(self) {
		self.highPriorityEvents = [];
	});
	this.addEventListener("privileged_execution_off", function(self) {
		for (var ii = self.highPriorityEvents.length - 1; ii >= 0; --ii) {
			if (self.highPriorityEvents[ii] && !self.highPriorityEvents[ii].executed) {
				self.addEventListener(self.highPriorityEvents[ii].state, self.highPriorityEvents[ii].listener, true);
			}
		}
		self.highPriorityEvents = [];
	});
	this.addEventListener("delayed_execution_on", function(self) {
		self.delayedEvents = [];
	});
	this.addEventListener("delayed_execution_off", function(self) {
		for (var ii = self.delayedEvents.length - 1; ii >= 0; --ii) {
			if (!self.fireOnState(self.delayedEvents[ii].state, self.delayedEvents[ii].listener)) {
				continue;
			}
			self.delayedEvents[ii].listener();
		}
	});
	
	this.changeState("inited");
	this.loadData();
};

/**
 * We overwrite the zpwidgets loadDataHtml method to parse 
 * needed values from given HTML source.
 * @param el [HTML element] - DOM representation of or HTML part.
 */
southprojects.Window.prototype.loadDataHtml = function(el) {
	//el is an DOM element created from the struct.html file, which contains HTML part of this widget.
	if (this.parseDom(el)) {
		this.changeState("loaded");
	}
};

/**
 * This function appends the loaded structure to the documents BODY,
 * makes Window draggable, sets all the parameters of the visual elements.
 * All its actions are closely connected with config options.
 * @param x [integer] x coordinate.
 * @param y [integer] y coordinate.
 * @param width [integer] width of the window.
 * @param height [integer] height of the window.
 *
 * @return [object] { x, y } containing the position.
 */
southprojects.Window.prototype.create = function (x, y, width, height)  {
	if (x != "center") {
		x = parseInt(x, 10);
	}
	if (y != "center") {
		y = parseInt(y, 10); 
	}
	if (width != "auto") {
		width = parseInt(width, 10); 
	}
	if (height != "auto") {
		height = parseInt(height, 10);
	}
	if ((typeof x != "number" && x != "center") || 
		(typeof y != "number" && y != "center") || 
		(typeof width != "number" && width != "auto") || 
		(typeof height != "number" && height != "auto")) {
			return false;
	}
	//If not everything is ready for creating the widget we should wait a little and try again.
	//some kind of imitation of "threaded widget", if you know what I mean :)
	var self = this;
	if (!this.fireOnState("body_loaded", function() {self.create(x, y, width, height);}) || !this.fireOnState("loaded", function() {self.create(x, y, width, height);})) {
		return;
	}
	//appending the loaded element
	document.body.appendChild(this.container);
	this.state.width = this.container.offsetWidth;
	//adding a button type for container to react on resizing
	this.container.buttonType = "resize";
	//adding a class name for using specified theme
	southprojects.Utils.addClass(this.container, this.getClassName({prefix : "spWin", suffix : "Container"}));
	//adding a button type for titleArea to react on dbl click
	this.titleArea.buttonType = "title";
	//adding buttons
	function replaceButton(but, idPrefix, func) {
		var button = new southprojects.Button({
			className : but.className,
			style : but.style.cssText,
			theme : null,
			idPrefix : idPrefix,
			clickAction : func
		});
		var nxtSbl = but.nextSibling;
		var par = but.parentNode;
		if (but.outerHTML) {
			but.outerHTML = "";
		} else {
			par.removeChild(but);
		}
		par.insertBefore(button.getContainer(), nxtSbl);
		return button;
	}
	//min button
	this.minButton = replaceButton(this.minButton, "spWin" + self.id + "MinButton", function() {self.minimize();});
	//max button
	this.maxButton = replaceButton(this.maxButton, "spWin" + self.id + "MaxButton", function() {self.maximize();});
	//close button
	this.closeButton = replaceButton(this.closeButton, "spWin" + self.id + "CloseButton", function() {self.close();});
	//restore button
	this.restoreButton = replaceButton(this.restoreButton, "spWin" + self.id + "RestoreButton", function() {self.restore();});
	//customizing the structure to the options of config
	this.setModeOn("immediate_execution");
	this.reconfig();
	this.setModeOff("immediate_execution");
	//using this method we calculate the width of titleArea, content and statusText
	//and save them to use in setWidth method.
	//This is needed for making elements with overflow (auto or hidden) work correct when size changes.
	this.calculateSizes();
	//Creating a Pane object
	var pane = new southprojects.Pane({
		containerType : (this.config.iframeContent ? "iframe" : "div"),
		autoContentWidth : width == "auto" ? true : false,
		autoContentHeight : height == "auto" ? true : false
	});
	if (width == "auto") width = 0;
	if (height == "auto") height = 0;
	this.content.parentNode.insertBefore(pane.getContainer(), this.content.nextSibling);
	if (!southprojects.is_opera) {
		pane.getContainer().style.cssText = this.content.style.cssText;
	} else {
		for(var i in this.content.style) {
			try {
				pane.getContainer().style[i] = this.content.style[i];
			} catch (e) {}
		}
	}
	pane.removeBorder();
	pane.getContainer().className = this.content.className;
	pane.fireWhenReady(function(p) {
		if (p.getContentElement()) {
			if (p.config.containerType.toLowerCase() == "iframe") {
				p.getContentElement().style.padding = "0px";
			}
			p.getContentElement().style.margin = "0px";
		}
	});
	this.content.parentNode.removeChild(this.content);
	this.content = pane;
	//Creating WCH
	southprojects.Utils.createProperty(this, "WCH", southprojects.Utils.createWCH());
	if (this.WCH) this.WCH.style.zIndex = southprojects.Window.maxNumber++;
	//manipulating with container
	this.container.style.zIndex = southprojects.Window.maxNumber++;
	southprojects.Utils.prepareToMove(this.container, null, document.body);
	southprojects.Utils.moveElementTo(this.container, (this.state.left = x), (this.state.top = y));
	//adding events
	this.addEvents();
	//FIXME: hack for IE5.5 - a problem appears when you set the display of 
	//container to "none" and than back to "block" the size of the table breaks
	//if titleText cell has width 100%
	this.titleText.parentNode.style.width = "";
	this.setModeOn("immediate_execution");
	//trying to set sizes and pos by our methods
	this.setPosAndSize(x, y, width, height);
	//hiding new window
	this.hide();
	this.setModeOff("immediate_execution");
	//setting the state to ready
	this.changeState("ready");
};

