/****
 * SMenu - (c) 2006 H.J.Faber
 *
 * Classes:
 * - SMenuContainer	Holds all menu's..
 * - SMenu		Manages a (1) menu.
 * - SMenuItem		Keeps items that can be used inside menu's.
 * - SMenuSubItem	Holds sub items for 'main' items if applicable.
 * - SVisualiserContainer	Holds all visualisers.
 * - SVisualiser	Controls visibility of menu-items.
 */

var SMenuDefaultClass = "Nav";

function SMenuContainer() {

	this.SClass = "SMenuContainer";

	// Array of menu objects..
	this.items = null;

	// Functions..
	this.SMenuContainer = SMenuContainer;
	this.add = add;
	this.get = get;
	this.length = 0;

	// Constructor..
	function SMenuContainer() {
		this.items = new Array();
	}

	// Add..
	function add(item) {
		if(null == this.items) this.SMenuContainer();

		var name = item.name;
		if(null != name) {
			this.items[name] = item;
		}

		this.length = this.items.length;

		return this.items.length;
	}

	// Get..
	function get(item) {
		if(null == this.items) return null;

		return this.items[item];
	}

	this.SMenuContainer();
}
var SMenus = new SMenuContainer();

function SMenu(name, style) {

	this.SClass = "SMenu";
	// Fields..
	this.name = name;
	this.items = null;
	this.hook = null;	// div waaraan menu attached gaat worden
	this.style = style;	// basis style voor menu (class).. default "Nav"

	// Functions..
	this.SMenu = SMenu;		// constructor
	this.add = add;			// add menu item
	this.get = get;			// returns specified menu item..
	this.attach = attach;		// attaches menu to hook
	this.setStyle = setStyle;	// sets base for CSS..
	this.render = render;		// renders to hook
	this.renderTo = renderTo;	// short-cut for attach + render
	this.renderHTML = renderHTML;	// renders actual HTML that generates menu..
	this.collapse = collapse;	// klapt alle menu elementen in (eventueel op 1tje na)..
	this.autoCollapse = true;

	this.IEfix = false;		// fixes IE bug as described in ticket 22.
					// this value is only used in SMenuItem, but default value can be set here..

	function SMenu(name, style) {
		if(null == name) name = this.name;
		if(null == name) {
			name = "menu" + SMenus.length;
		}
		if(null == style) style = this.style;

		this.name = name;
		this.setStyle(style);
		this.items = new Array();

		SMenus.add(this);
	}

	function add(item) {
		if(null == item) return null;
		if(null == item.SClass) return null;
		if("SMenuItem" != item.SClass) return null;

		if(null == this.items) this.SMenu();

		item.setStyle(this.style);
		item.parent = this;
		item.id = this.items.length;
		item.IEfix = this.IEfix;
		this.items.push(item);
	}

	function get(item) {
		if(null == this.items) return null;

		for(var i=0; i<this.items.length; i++) {
			if(item == this.items[i].getName()) {
				return this.items[i];
			}
		}

		return null;
	}

	function attach(id) {
		if(null != id)
		if(null != document.getElementById(id))
		this.hook = document.getElementById(id);
	}

	function setStyle(className) {
		if(null == className) className = SMenuDefaultClass;

		this.style = className;
	}

	function render() {
		if(null == this.hook) return null;

		var html = this.renderHTML();

		if(null != html) this.hook.innerHTML = html;
	}

	function renderTo(id) {
		this.attach(id);
		this.render();
	}

	function renderHTML() {
		var html = "";

		var containerClass = this.style + "Container";
		var containerId = "SMenu" + this.name;

		html += "<div id='" + containerId + "' class='" + containerClass + "'>";
		if(null != this.items) {
			for(var i=0; i<this.items.length; i++) {
				html += this.items[i].renderHTML();
			}
		}
		html += "</div>";

		return html;
	}

	function collapse(exception) {
		if(null == this.items) return;
		if(null == exception) exception = -1;

		for(var i=0; i<this.items.length; i++) {
			var item = this.items[i];

			if(item.id != exception) {
// item kan al collapsed zijn terwijl de hide nog in timer event zit, daarom *altijd* hiden.
// Whoohoo!, dit uitcommentarieren leverde tevens een fix voor de IE-bug!!!
//				if(false == item.collapsed) {
					item.hide(null, null, /* force! */ true, /* kill! */ true);
//				}
			}
		}
	}

	this.SMenu(name);
}

function SMenuItem(tag, sub, style, name) {

	this.SClass = "SMenuItem";

	// Fields..
	this.tag = tag;		// (div id) id of item 'tag', i.e. the text field of the item.
	this.tagContent = null;
	this.subContent = null;
	this.subContentId = null;	// id of div that will hold sub-content (and that can be collapsed / expanded)..
	this.style = null;	// class base name of styles that will be used.
	this.parent = null;	// SMenu that this item belongs to (Set by parent).
	this.id = null;		// ID (volgnummer binnen menu) of item (Set by parent).
	this.name = null;	// naam, optioneel (default ID).

	this.items = null;	// User-defined items instead of integral content from external (div) source..

	this.sticky = false;	// Disables show/hide events..
	this.clickBehaviour = false;	// true: een click kan nooit zichzelf dichtklikken, helpt sticky-gedrag
					// (bijv. verticale menu's waarvan altijd 1 element geopend moet blijven).

	this.method = "move";	// Default method. "move", "click", "click,sticky".
	this.behaviour = null;	// Determines event behaviour, default "move". Opions "move" & "click".
	this.showTrigger = null;// "mouseover" (default), "onclick"
	this.hideTrigger = null;// "mouseout" (default), "onclick"
	this.collapsed = true;	// by default, collapsed..

	this.IEfix = false;	// fixes IE bug as described in ticket 22.

	// styles for Tag
	this.currentStyle = null;	// current CSS style class name.. (used to track mouseover/out styles while active!)
	this.mouseoverStyle = null;
	this.mouseoutStyle = null;
	this.activeStyle = null;	// when item is selected..

	// Functions..
	this.SMenuItem = SMenuItem;
	this.setStyle = setStyle;
	this.renderHTML = renderHTML;
	this.renderEventsHTML = renderEventsHTML;	// Returns code snippet for mouse events..
	this.setBehaviour = setBehaviour;
	this.show = show;	// Handles mouse events..
	this.hide = hide;	// Handles mouse events..
	this.toggle = toggle;	// Handles mouse events..
	this.showAction = null;	// External handler..
	this.hideAction = null;	// External handler..
	this.killAction = null;	// External handler..
	this.mouseover = mouseover;
	this.mouseout = mouseout;

	this.subItem = subItem;	// generates & adds menu sub item..
	this.add = add;		// adds sub item to list..

	this.getName = getName;	// zodat sub-items naam van dit item kunnen opvragen..

	this.get = get;		// returns requested sub-item..

	function SMenuItem(tag, sub, style, name) {
		if(null == tag) return null;
		if(null == sub) sub = "";

		var tagDiv = document.getElementById(tag);
		var subDiv = document.getElementById(sub);

		if(null == tagDiv) {
			// No reference to div? use string literal as tag..
			this.tagContent = tag;
		} else {
			this.tagContent = tagDiv.innerHTML;
		}

		if(null == subDiv) {
			this.subContent = sub;
		} else {
			this.subContent = subDiv.innerHTML;
		}

		this.showAction = new SVisualiser("show");
		this.hideAction = new SVisualiser("hide");
		this.killAction = new SVisualiser("kill");

		this.setStyle(style);
		this.setBehaviour();
	}

	function setStyle(className) {
		if(null == className) className = SMenuDefaultClass;

		this.style = className;
	}

	function renderHTML() {
		var html = "";

		var containerClass = this.style + "ItemContainer";
		var itemClass = this.style + "Item";
		var subContainerClass = "Sub" + this.style + "Container";

		// create default names for style class names..
		if(null == this.currentStyle) this.currentStyle = itemClass;
		if(null == this.mouseoverStyle) this.mouseoverStyle = itemClass + "MOver";
		if(null == this.mouseoutStyle) this.mouseoutStyle = itemClass;
		if(null == this.activeStyle) this.activeStyle = itemClass + "Active";

		// default style handles initial collapsed state..
		var subContainerStyle = (true == this.collapsed) ? " style='display: none;'" : "";
		if(false == this.collapsed) itemClass = this.activeStyle;

		var baseId = "SMenu" + this.parent.name + "Item" + this.getName();
		var containerId = baseId;
		var itemId = baseId + "Tag";
		var subContainerId = baseId + "Subcontainer";

		// remember Id of tag..
		this.tag = itemId;

		// id of sub content will be needed elsewhere..
		this.subContentId = subContainerId;

		var itemEvents = this.renderEventsHTML("item");
		var subEvents = this.renderEventsHTML("sub");

		html += "<div id='" + containerId + "' class='" + containerClass + "'>";
		html += "<div id='" + itemId + "' class='" + itemClass + "'" + itemEvents + ">";
		html += this.tagContent;
		html += "</div>";
		html += "<div id='" + subContainerId + "' class='" + subContainerClass + "'" + subContainerStyle + subEvents + ">";
		if(null == this.items) {
			html += this.subContent;
		} else {
			for(var i=0; i<this.items.length; i++) {
				html += this.items[i].renderHTML();
			}
		}
		html += "</div>";
		html += "</div>";

		return html;
	}

	function renderEventsHTML(type) {
		var snippet = "";

		var menu = this.parent.name;
		var item = this.id;

		if("onmouseover" == this.showTrigger) {
			snippet += ' onmouseover="SMenuItem0.show(\'' + menu + '\',\'' + item + '\', true); SMenuItem0.mouseover(\'' + menu + '\',\'' + item + '\');"';
		}

		if("onmouseout" == this.hideTrigger) {
			snippet += ' onmouseout="SMenuItem0.hide(\'' + menu + '\',\'' + item + '\'); SMenuItem0.mouseout(\'' + menu + '\',\'' + item + '\');"';
		}

		if( ("onclick" == this.showTrigger) && ("onclick" == this.hideTrigger) ) {
			switch(type) {
				case "item":
					var clickBehaviour = ("sticky" == this.clickBehaviour) ? 'true' : 'false';
					snippet += ' onclick="SMenuItem0.toggle(\'' + menu + '\',\'' + item + '\', true, ' + clickBehaviour + ');"';
					snippet += ' onmouseover="this.style.cursor=\'pointer\'; SMenuItem0.mouseover(\'' + menu + '\',\'' + item + '\');"';
					snippet += ' onmouseout="this.style.cursor=\'default\'; SMenuItem0.mouseout(\'' + menu + '\',\'' + item + '\');"';
					break;
				case "sub":
				default:
					break;
			}
		}

		return snippet;
	}

	function setBehaviour(method) {
		if(null == method) method = this.method;

		this.method = method;
		switch(method) {
			case "click,sticky":
				this.clickBehaviour = "sticky";
			case "click":
				this.behaviour = "click";
				this.showTrigger = "onclick";
				this.hideTrigger = "onclick";
				break;
			case "move":
			default:
				this.behaviour = "move";
				this.showTrigger = "onmouseover";
				this.hideTrigger = "onmouseout";
				break;
		}
	}

	function show(menu, item, force) {
		if(null == force) force = false;
		if( (null == menu) || (null == item) ) {
			if( (false == this.sticky) || (true == force) ) {
				this.collapsed = false;

				this.hideAction.abort(); // kill hide action, voor het geval die al aangeroepen is..
				this.hideAction.blockHiding(); // sets threshold, minimum time item will be visible..

				if(null != this.showAction) this.showAction.execute(this.subContentId);
				if(true == this.parent.autoCollapse) this.parent.collapse(this.id);
				var item = document.getElementById(this.tag);
				if(null != item) item.className = this.activeStyle;
					// BUG FIX voor menu's die open blijven staan!
				if(true == this.IEfix) { /*alert('IE Fix');*/ this.parent.render(); }
			}
		} else {
			var menuObject = SMenus.get(menu);
			if(null != menuObject) {
				var itemObject = menuObject.get(item);
				if(null != itemObject) {
					itemObject.show(null, null, force);
				}
			}
		}
	}

	function hide(menu, item, force, kill) {
		if(null == force) force = false;
		if(null == kill) kill = false;
		if( (null == menu) || (null == item) ) {
			if( (false == this.sticky) || (true == force) ) {
				this.collapsed = true;
				if( (true == kill) && (null != this.killAction) ) {
					this.killAction.execute(this.subContentId);
				} else {
					if(null != this.hideAction) this.hideAction.execute(this.subContentId);
				}
				var item = document.getElementById(this.tag);
				if(null != item) item.className = this.currentStyle;
			}
			// Avoid IE's sticky bug..
			if( (true == this.sticky) && ("click" == this.method /* niet bij 'click,sticky' */) ) {
				this.parent.render();
			}
		} else {
			var menu = SMenus.get(menu);
			if(null != menu) {
				var item = menu.get(item);
				if(null != item) {
					item.hide(null, null, force);
				}
			}
		}
	}

	function toggle(menu, item, force, clickBehaviour) {
		if(null == clickBehaviour) clickBehaviour = false;
			// clickBehaviour: indien menu-item van het type 'click,sticky' is, wordt er standaard
			// clickBehaviour=true meegegeven. Dit houdt in dat de *hide* wordt geblokkeerd,
			// zodat een item niet zichzelf kan dichtklikken (dicht kan alleen door een ander te openen).
		if( (null == menu) || (null == item) ) {
			switch(this.collapsed) {
				case true:
					this.show(null, null, force);
					break;
				case false:
					if(!clickBehaviour) this.hide(null, null, force);
					break;
			}
		} else {
			var menu = SMenus.get(menu);
			if(null != menu) {
				var item = menu.get(item);
				if(null != item) {
					item.toggle(null, null, force, clickBehaviour);
				}
			}
		}
	}

	function mouseover(menu, item) {
		if( (null == menu) || (null == item) ) {
			if(null != this.mouseoverStyle) {
				if(true == this.collapsed) {
					var item = document.getElementById(this.tag);
					if(null != item) item.className = this.mouseoverStyle;
				}
				this.currentStyle = this.mouseoverStyle;
			}
		} else {
			var menu = SMenus.get(menu);
			if(null != menu) {
				var item = menu.get(item);
				if(null != item) {
					item.mouseover(null, null);
				}
			}
		}
	}

	function mouseout(menu, item) {
		if( (null == menu) || (null == item) ) {
			if(null != this.mouseoutStyle) {
				if(true == this.collapsed) {
					var item = document.getElementById(this.tag);
					if(null != item) item.className = this.mouseoutStyle;
				}
				this.currentStyle = this.mouseoutStyle;
			}
		} else {
			var menu = SMenus.get(menu);
			if(null != menu) {
				var item = menu.get(item);
				if(null != item) {
					item.mouseout(null, null);
				}
			}
		}
	}

	function subItem(url, tag, style, name) {
		if(null == style) style = this.style;
		if(null == tag) tag = url;
		if(null == url) return null;

		var item = new SMenuSubItem(url, tag, style, name);
		this.add(item);
	}

	function add(item) {
		if(null == item) return;
		if(null == item.SClass) return;
		if("SMenuSubItem" != item.SClass) return;

		if(null == this.items) {
			this.items = new Array();
		}

		item.parent = this;
		item.id = this.items.length;
		this.items.push(item);
	}

	function getName() {
		if(null == this.name) this.name = this.id;
		return this.name;
	}

	function get(subitem) {
		if(null == this.items) return null;

		for(var i=0; i<this.items.length; i++) {
			if(subitem == this.items[i].getName()) {
				return this.items[i];
			}
		}

		return null;
	}

	this.SMenuItem(tag, sub, style, name);
}
var SMenuItem0 = new SMenuItem();

function SMenuSubItem(url, tag, style, name) {

	this.SClass = "SMenuSubItem";

	this.url = url;
	this.tag = tag;
	this.style = style;

	this.parent = null;
	this.id = 0;
	this.name = null;

	this.SMenuSubItem = SMenuSubItem;
	this.setStyle = setStyle;
	this.renderHTML = renderHTML;
	this.getName = getName;

	function SMenuSubItem(url, tag, style, name) {
		this.url = url;
		this.tag = tag;
		this.setStyle(style);
		this.name = name;
	}

	function setStyle(className) {
		if(null == className) className = SMenuDefaultClass;

		this.style = className;
	}

	function renderHTML() {
		var html = "";

		var itemClass = "Sub" + this.style + "Item";
		var itemId = "SMenu" + this.parent.parent.name + "Item" + this.parent.getName() + "Sub"+ this.getName();

		// default style classes for mouse events..
		if(null == this.mouseoverStyle) this.mouseoverStyle = itemClass + "MOver";
		if(null == this.mouseoutStyle) this.mouseoutStyle = itemClass;

		// extra events when mouseover/out styles are set..
		var extra1 = "";
		var extra2 = "";
		if(null != this.mouseoverStyle) extra1 = "this.className = '" + this.mouseoverStyle + "';";
		if(null != this.mouseoutStyle) extra2 = "this.className = '" + this.mouseoutStyle + "';";

		var events = ' onclick="SURLForward(\'' + this.url + '\');"';
		events += ' onmouseover="this.style.cursor=\'pointer\';' + extra1 + '"';
		events += ' onmouseout="this.style.cursor=\'default\';' + extra2 + '"';

		html += "<div id='" + itemId + "' class='" + itemClass + "'" + events + ">";
		html += "<a href='" + this.url + "'>" + this.tag + "</a>";
		html += "</div>";

		return html;
	}

	function getName() {
		if(null == this.name) this.name = this.id;
		return this.name;
	}

	this.SMenuSubItem(url, tag, style, name);
}

function SVisualiserContainer() {

	this.SClass = "SVisualiserContainer";

	this.items = null;

	// Functions..
	this.SVisualiserContainer = SVisualiserContainer;
	this.add = add;
	this.get = get;

	this.length = 0;

	function SVisualiserContainer() {
		this.items = new Array();
		this.length = 0;
	}

	function add(item) {
		if(null == this.items) this.SVisualiserContainer();

		var id = item.id;
		if(null != id) {
			this.items[id] = item;
		}

		this.length = this.items.length;

		return this.length;
	}

	function get(item) {
		if(null == this.items) return null;

		return this.items[item];
	}

	this.SVisualiserContainer();
}
var SVisualisers = new SVisualiserContainer();

function SVisualiser(method) {

	this.SClass = "SVisualiser";

	this.id = null;

	this.method = method;

	this.timer = null;

	this.showTimeout = 0;
	this.hideTimeout = 300;
	this.doBlockHiding = false;	// used to block hiding to create minimum amount of time item is visible..
	this.blockHidingThreshold = 1000;	// default value for delay, minumum time item is visible..

	// Functions..
	this.SVisualiser = SVisualiser;
	this.execute = execute;
	this.abort = abort;
	this.show = show;
	this.hide = hide;
	this.blockHiding = blockHiding;

	function SVisualiser(method) {
		if(null == method) this.method = "show";

		this.method = method;

		this.id = SVisualisers.length;
		SVisualisers.add(this);
	}

	function execute(id) {
		this.abort();
		switch(this.method) {
			case "show": this.show(id, this.showTimeout); break;
			case "hide": this.hide(id, this.hideTimeout); break;
			case "kill": this.hide(id, 0); break;
			default: break;
		}
	}

	function abort() {
		if(null != this.timer) {
			clearTimeout(this.timer);
		}
	}

	function show(id, delay) {
		if(null == id) return;
		var div = document.getElementById(id);
		if(null == div) return;

		if(null == delay) delay = 0;

		div.style.display = "block";
	}

	function hide(id, delay) {
		if(null == id) return;
		var div = document.getElementById(id);
		if(null == div) return;

		if(null == delay) delay = 0;

		if(0 == delay) {
			if(this.doBlockHiding) {
				var timerCall = "SVisualisers.get('"+this.id+"').hide('"+id+"', 0);";
				clearTimeout(this.timer);
				this.timer = setTimeout(timerCall, 30);
			} else {
				div.style.display = "none";
			}
		} else {
			var timerCall = "SVisualisers.get('"+this.id+"').hide('"+id+"', 0);";
			this.timer = setTimeout(timerCall, delay);
		}
	}

	function blockHiding(delay) {
		if(null == delay) delay = this.blockHidingThreshold;

		this.doBlockHiding = true;

		timerCall = "SVisualisers.get('"+this.id+"').doBlockHiding = false;";
		setTimeout(timerCall, delay);
	}

	this.SVisualiser(method);
}

var SDataImportAutoRemove = true;
function SDataImport(id, removeSource) {
	if(null == removeSource) removeSource = SDataImportAutoRemove;

	var div = document.getElementById(id);
	if(null == div) return "";

	var html = div.innerHTML;
	if(true == removeSource) div.innerHTML = "";

	return html;
}

function SURLForward(url) {
	document.location = url;
}


