/** Terminologie:
  * - Activator: HTML-element dat bij aanwijzen met de muis een menuutje laat zien
  * - Engine of Menu-engine: een object dat de menu's beheert
  * - Menu: een menublok, dat getoond wordt als een activator wordt aangewezen
  * - Menu-item: een item in het menublok
 **/

/** Waarden voor de 'clip'-parameters om te bepalen waar het menu tov de activator moet komen **/
var CLIP_TOP_LEFT = 0;
var CLIP_TOP_RIGHT = 1;
var CLIP_BOTTOM_LEFT = 2;
var CLIP_BOTTOM_RIGHT = 3;

/** seedID wordt gebruikt om verschillende objecten te nummeren, zoals menu's, menu-items ed **/
var seedID = new Object();

/** aengine: de animatie engine, geeft een leuk effect **/
var aengine = new AnimationEngine();

/** icht.nl-specifiek: voor het verbergen van de flash-banner als de menu's opengaan **/
var oAd = null; // Object waar de flashbanner inzit
var bHideAd = (location.href.indexOf('forum') != -1) ? true : false; // Alleen op het forum moeten de ads weg, niet op de startpagina

/** SnowGenerateID maakt een unieke ID aan voor een object van de klasse 'cls' (geen js-objecten/klassen) **/
function SnowGenerateID(cls) {
	if (!seedID[cls]) seedID[cls] = 0;
	return cls + (seedID[cls]++);
}

/** SnowGetPos berekent de positie van een HTML-element op de pagina
  * oElm: het HTML-element waarvan de positie berekend moet worden
 **/
function SnowGetPos(oElm) {
	var pos = new Object();
	pos.x = 0;
	pos.y = 0;
	
	if (oElm.offsetParent) {
		pos.x = oElm.offsetLeft;
		pos.y = oElm.offsetTop;

		while (oElm = oElm.offsetParent) {
			pos.x += oElm.offsetLeft;
			pos.y += oElm.offsetTop;
		}
	}

	return pos;
}

/** SnowGetDim berekent de dimensies van een object
  * oElm: het HTML-element waarvan de dimensies berekend moeten worden
 **/
function SnowGetDim(oElm) {
	var pos = new Object();
	pos.x = oElm.offsetWidth;
	pos.y = oElm.offsetHeight;
	return pos;
}

/** MenuItem is een klasse voor menu items
  * text: De tekst van het item
  * link: De URL die geopend wordt bij het aanklikken
  * target: Het frame waar de URL geopend wordt
 **/
function MenuItem (text, link, target) {
	var txt = text;
	var href = link;
	var targ = target;
	var itemID = SnowGenerateID('menu_item');

	/** toString geeft de HTML-code voor het menu item **/
	this.toString = function() {
		var s = '<div class="SnowMenuItem" id="' + itemID + '" onmouseover="itemover(this)" onmouseout="itemout(this)">';
		s += '<a href="' + href + '" target="' + targ + '">' + txt + '</a></div>\n';

		return s;
	}
}

/** Menu is een klasse voor menu's
  * oAct: de activator voor het menu (het ID van een HTML-element, want het kan zijn dat de activator nog gemaakt moet worden)
  * link: de URL die geopend wordt bij het aanklikken van de activator
  * target: het frame waarin de URL geopend moet worden
  * clipPoint: geeft aan waar het menu moet komen tov de activator, gebruik hiervoor de CLIP_* waarden
  * align: geeft aan hoe het menu uitgelijnd wordt tov de x- en y-coordinaten. kan zijn: leeg, 'right', 'bottom' of 'right bottom'
  * oEngine: de menu-engine waar het menu deel van uitmaakt
 **/
function Menu (oAct, link, target, clipPoint, align, oEngine) {
	var act = oAct;
	var clip = clipPoint;
	var hAlign = (align.indexOf('right') != -1) ? -1 : 0;  // right-aligned wil zeggen dat het menu links van de x-coordinaat komt ipv rechts
	var vAlign = (align.indexOf('bottom') != -1) ? -1 : 0; // bottom-aligned wil zeggen dat het menu boven de y-coordinaat komt ipv eronder

	var href = link;
	var targ = target;

	var items = [];
	var menuID = SnowGenerateID('menu');

	var menuElm = null;
	var menuCont = null;
	var menuDim = null;
	var parent = oEngine;

	/** init maakt het menu, of eigenlijk de activator, klaar voor gebruik **/
	this.init = function() {
		act = document.getElementById(act); // de activator converteren van een ID naar een HTML-object, waar makkelijker mee te werken is.
		act.onmouseover = open;
		act.onmouseout = close;
		act.onclick = function() { window.open(href, targ, ''); }
	}

	var _this = this; // om vanuit functies te refereren naar het Menu-object

	/** open opent het menu **/
	function open() {
		act.className = "SnowMenuHover"; // de activator higlighten
		if (parent.activeMenu != _this) { // openen heeft geen zin als het menu al geopend is
			parent.stopDelay(); // niet meer wachten om het nu geopende menu te sluiten, maar...
			if (parent.activeMenu != null) parent.activeMenu.doClose();  // het geopende menu meteen sluiten, als er tenminste een menu geopend is

			if (items.length > 0) { // openen heeft ook geen zin als er geen menu-items zijn
				/** icht.nl-specifiek: ads verbergen als er een menu open gaat **/
				if (bHideAd) {
					if (!oAd) oAd = document.getElementById("adsection");
					if (oAd) oAd.style.visibility = "hidden";
				}

				/** als we het HTML-object nog niet hebben, ophalen dat ding en als het er niet is, kunnen we niet verder, dus 'return' **/
				if (menuElm == null) {
					menuElm = document.getElementById(menuID);
					if (menuElm == null) return;
					menuCont = document.getElementById("cont_" + menuID);
					menuElm.onmouseover = stopDelay;
					menuElm.onmouseout = close;
				}

				/** positie van het menu bepalen. moet elke keer weer, omdat er bij het resizen van het venster van alles met de positie
				    van de activator kan gebeuren **/
				var actPos = SnowGetPos(act);
				var actDim = SnowGetDim(act);
				menuDim = SnowGetDim(menuElm);

				if (clip >= 2) actPos.y += actDim.y; /* CLIP_BOTTOM_* */
				if (clip & 1) actPos.x += actDim.x; /* CLIP_*_RIGHT */

				actPos.x += hAlign * menuDim.x;
				actPos.y += vAlign * menuDim.y;

				/** menu op z'n plaats zetten... **/
				menuCont.style.left = actPos.x + "px";
				menuCont.style.top = actPos.y + "px";
				menuCont.style.zIndex = "100";

				/** ... en laten zien **/
				menuElm.style.top = "-" + menuDim.y + "px";
				menuElm.style.visibility = "visible";

				/** Animatie starten **/
				var a = new Animation(menuElm, 0);
				a.addProperty("top", 0, "", "px", 0.5);
				aengine.addAnimation(a);
			}

			/** de engine laten weten dat dit menu geopend is, ook als het menu niet geopend is, want de activator is nog wel gehighlight **/
			parent.activeMenu = _this;
		}
	}

	/** close stelt een timer in om het menu over enkele ms te sluiten, als er daarvoor niks gebeurt **/
	function close() {
		parent.delayClose(); // uitbesteden aan de engine
	}

	this.close = close; // voor outsiders

	/** doClose sluit het menu daadwerkelijk **/
	this.doClose = function() {
		act.className = "SnowMenu"; // activator niet meer highlighten

		if (menuElm) {
			/** Animatie starten **/
			var a = new Animation(menuElm, 0);
			a.addProperty("top", -(menuDim.y), "", "px", 0);
			a.addPostFunction(function() { menuCont.style.zIndex  = "-1" });
			aengine.addAnimation(a);
			// menuElm.style.visibility = "hidden"; // menu verbergen
			// menuCont.style.zIndex = "-1";
		}
		if (oAd) oAd.style.visibility = "visible"; // ads weer tevoorschijn toveren
		parent.activeMenu = null; // de engine vertellen dat er geen menu meer open is
	}

	/** addItem voegt een menu-item toe aan het menu
	  * text: De tekst van het item
	  * link: De URL die geopend wordt bij het aanklikken
	  * target: Het frame waar de URL geopend wordt
	 **/
	this.addItem = function(text, link, target) {
		var idx = items.length;
		items[idx] = new MenuItem(text, link, target);
	}

	/** toString geeft de HTML-code voor het menu **/
	this.toString = function() {
		var s = '<div class="SnowMenuPaneContainer" id="cont_' + menuID + '">\n';
		s += '<div class="SnowMenuPane" id="' + menuID + '">\n';
		for (var i=0; i<items.length; i++) s += items[i].toString();
		s += '</div>\n</div>\n';

		return s;
	}

	/** stopDelay stopt de timer om het menu te sluiten **/
	function stopDelay() {
		parent.stopDelay(); // weer uitbesteden aan de engine
	}
}

/** MenuEngine is een klasse voor een menu engine **/
function MenuEngine() {
	var menus = [];
	var activators = [];

	this.activeMenu = null; // bijhouden welk menu geopend is
	var _this = this;

	var tim = null; // de timer om menu's te sluiten

	/** delayClose stelt een timer in om het menu over enkele ms te sluiten, als er daarvoor niks gebeurt **/
	this.delayClose = function() {
		tim = setTimeout(closeMenu, 500);
	}

	/** stopDelay stopt de timer om het menu te sluiten **/
	this.stopDelay = function() {
		if (tim) {
			clearTimeout(tim);
			tim = null;
		}
	}

	/** closeMenu sluit het geopende menu **/
	function closeMenu() {
		if (_this.activeMenu) _this.activeMenu.doClose();
	}

	/** addMenu voegt een menu toe
	  * ar: een array met gegevens: [activator_id, link, target]
	  * clipPoint: geeft aan waar het menu moet komen tov de activator, gebruik hiervoor de CLIP_* waarden
	  * align: geeft aan hoe het menu uitgelijnd wordt tov de x- en y-coordinaten. kan zijn: leeg, 'right', 'bottom' of 'right bottom'
	 **/
	this.addMenu = function(ar, clipPoint, align) {
		var idx = menus.length;
		activators[idx] = [SnowGenerateID('SnowAct'), ar[0], ar[1], ar[2]];
		menus[idx] = new Menu(activators[idx][0], ar[1], ar[2], clipPoint, align, this);
		return menus[idx];
	}

	/** render schrijft het hele menu naar het HTML-document **/
	this.render = function() {
		var s_act = ""; // voor de menubalk
		var s_menu = ""; // voor de menublokken
		s_act = '<table class="SnowMenuBar" cellspacing="0">\n<tr>\n';
		for (var i=0; i<activators.length; i++) {
			s_act += '<td class="SnowMenu" id="' + activators[i][0] + '"><A href="' + activators[i][2] + '" target="' + activators[i][3] + '">' +
			activators[i][1] + '</A></td>\n';
		}
		s_act += '</tr>\n</table>\n';
		document.write(s_act);

		for (var i=0; i<menus.length; i++) {
			if (menus[i]) {
				menus[i].init();
				s_menu += menus[i].toString();
			}
		}

		document.write(s_menu);
	}

	/** loadMenu maakt een compleet menu aan de hand van een array **/
	this.loadMenu = function(ar, clip, align) {
		for (var i=0; i<ar.length; i++) {
			var m = this.addMenu(ar[i], clip, align, this);
			for (var j=3; j<ar[i].length; j++) {
				m.addItem(ar[i][j][0], ar[i][j][1], ar[i][j][2]);
			}
		}
	}
}

/** itemover wordt aangeroepen als de muis over een menu-item beweegt en highlight het item **/
function itemover(elm) { elm.className = "SnowMenuItemHover"; }

/** itemover wordt aangeroepen als de muis een menu-item verlaat en haalt de highlight van het item **/
function itemout(elm) { elm.className = "SnowMenuItem"; }
