﻿// IMPORTANT!
// TODO: Since the state of the menu is stored as a cookie, ASP.NET can read that 
// cookie and (optionally) set the state of the menu accordingly on the server-side
// which will avoid the menu flickering while state is updated when reloading the page.
// The constructor of the menu should take a parameter which specifies wheather or not
// the server-side should handle the initial state adjustment. If not, the client-side
// should update the menu state as usual.
// IMPORTANT!

// Define version.
var HIERARCHICALMENU_JS = 1.0;

// Common.js dependencies:
// * getElement
// * Events.attachEventListener
// * Cookie.deleteCookie
// * Cookie.getCookie
// * Cookie.setCookie
// * Cookie.setSessionCookie

if(typeof(COMMON_JS) == 'undefined') {
    alert('Common.js is not included.');
}

var HierarchicalMenu = new Object();

HierarchicalMenu.persistedElements = new Object();

HierarchicalMenu.OpenMenuItemClassName = 'OpenMenuItem';
HierarchicalMenu.ClosedMenuItemClassName = 'ClosedMenuItem';
HierarchicalMenu.LastMenuItemClassName = 'LastMenuItem';
HierarchicalMenu.OpenSubMenuClassName = 'OpenSubMenu';
HierarchicalMenu.ClosedSubMenuClassName = 'ClosedSubMenu';

HierarchicalMenu.createHierarchicalMenu = function(menuId, shouldPersistState, persistDays) {
	var ulElements = getElement(menuId).getElementsByTagName("ul");
	if(typeof(HierarchicalMenu.persistedElements[menuId]) == 'undefined') {
		if(shouldPersistState == true) {
			// Load menu state from persistent medium.
			HierarchicalMenu.persistedElements[menuId] = HierarchicalMenu.loadState(menuId);
		}
	}

	for(var i=0; i<ulElements.length; i++) {
		HierarchicalMenu.buildSubTree(menuId, ulElements[i], i);
	}
	
	if(shouldPersistState == true) {
	    // If not specified, default to session storage only (not persistent).
		var durationDays = (typeof(persistDays) == 'undefined') ? 0 : parseInt(persistDays);
		
		if(window.opera) {
			// Opera doesn't support the unload event so we need to store the state every time the menu state changes.
			for(var i=0; i<ulElements.length; i++) {
				Events.attachEventListener(ulElements[i].parentNode, 'click', function() {
					HierarchicalMenu.saveState(menuId, durationDays);
				});
			}
		} else {
			// Save opened element indexes on window.onunload.
			Events.attachEventListener(window, 'unload', function() {
				HierarchicalMenu.saveState(menuId, durationDays);
			});
		}
	}
};

HierarchicalMenu.buildSubTree = function(menuId, ulElement, index) {
           
/*	if(typeof(HierarchicalMenu.ClosedSubMenuClassName) != 'undefined') {
		ulElement.parentNode.className = HierarchicalMenu.ClosedSubMenuClassName;
		// HierarchicalMenu.log(ulElement.parentNode.innerHTML.substring(0, 50) + ' is submenu');
	}
	*/
	
    if(typeof(HierarchicalMenu.persistedElements[menuId]) == "object") {
		// If a cookie exists (HierarchicalMenu.persistedElements[menuId] is an array versus "" string).
		if(HierarchicalMenu.searchArray(HierarchicalMenu.persistedElements[menuId], index) == true) {
			HierarchicalMenu.setElementState(ulElement.parentNode, 'open');
			ulElement.setAttribute("rel", "open");
			ulElement.style.display = "block";
		} else {
			HierarchicalMenu.setElementState(ulElement.parentNode, 'closed');
			ulElement.setAttribute("rel", "closed");
			ulElement.style.display = "none";
		}
		// End cookie persist code.
	} else if(ulElement.getAttribute("rel") == null || ulElement.getAttribute("rel") == false) {
		// If no cookie and UL has NO rel attribute explicitly added by user.
		HierarchicalMenu.setElementState(ulElement.parentNode, 'closed');
		ulElement.setAttribute("rel", "closed");
		ulElement.style.display = "none";
	} else if(ulElement.getAttribute("rel") == "open") {
		// If no cookie and this UL has an explicit rel value of "open".
		// Expand this UL plus all parent ULs (so the most inner UL is revealed!).
		//HierarchicalMenu.setElementState(ulElement.parentNode, 'closed'); // ???? Is this correct?
		HierarchicalMenu.expandSubTree(menuId, ulElement);
	}

	// Determine wheather or not this item is the last element or not.
	if(typeof(HierarchicalMenu.LastMenuItemClassName) != 'undefined' && HierarchicalMenu.LastMenuItemClassName != '') {
		var liElements = ulElement.getElementsByTagName("li");
		if(liElements.length > 0) {
			liElements[liElements.length-1].className = HierarchicalMenu.LastMenuItemClassName;
		}
	}

	ulElement.parentNode.onclick = function(e) {
		var submenu = this.getElementsByTagName("ul")[0];
		
		if(submenu.getAttribute("rel") == "closed") {
			submenu.style.display = "block";
			submenu.setAttribute("rel", "open");
			HierarchicalMenu.setElementState(ulElement.parentNode, 'open');
		} else if(submenu.getAttribute("rel") == "open") {
			submenu.style.display = "none";
			submenu.setAttribute("rel", "closed");
			HierarchicalMenu.setElementState(ulElement.parentNode, 'closed');
		}
		
		HierarchicalMenu.preventPropagation(e);
	}

	ulElement.onclick = function(e) {
		HierarchicalMenu.preventPropagation(e);
	}
};

HierarchicalMenu.preventPropagation = function(e) {
    if(typeof e!= "undefined") {
        e.stopPropagation()
    } else {
        event.cancelBubble=true;
    }
};

HierarchicalMenu.setElementState = function(element, state) {
    //element = element.getElementsByTagName("a")[0];
	if(state == 'open') {
		element.className = HierarchicalMenu.OpenSubMenuClassName;
		element.firstChild.className = HierarchicalMenu.OpenMenuItemClassName;
	} else {
	    element.className = HierarchicalMenu.ClosedSubMenuClassName;
		element.firstChild.className = HierarchicalMenu.ClosedMenuItemClassName;
	}
};

HierarchicalMenu.expandSubTree = function(menuId, ulElement) { // Expand a UL element and any of its parent ULs.
	var rootnode = getElement(menuId);
	var currentnode = ulElement;
	currentnode.style.display = "block";
	HierarchicalMenu.setElementState(currentnode.parentNode, 'open');
	
	while(currentnode != rootnode) {
		if(currentnode.tagName == "UL") { // If parent node is a UL, expand it too.
			currentnode.style.display = "block";
			currentnode.setAttribute("rel", "open"); // Indicate it's open.
			HierarchicalMenu.setElementState(currentnode.parentNode, 'open');
		}
		currentnode = currentnode.parentNode;
	}
};

HierarchicalMenu.flatten = function(menuId, action) { // Expand or contract all UL elements.
	var ulElements = getElement(menuId).getElementsByTagName("ul");
	for(var i=0; i<ulElements.length; i++) {
		ulElements[i].style.display = (action == "expand") ? "block" : "none";
		var relValue = (action == "expand") ? "open" : "closed";
		ulElements[i].setAttribute("rel", relValue);
		if(action == 'expand') {
			HierarchicalMenu.setElementState(ulElements[i].parentNode, 'open');
		} else {
			HierarchicalMenu.setElementState(ulElements[i].parentNode, 'closed');
		}
	}
};

HierarchicalMenu.searchArray = function(a, value) { // Searches an array for the entered value. If found, delete value from array.
	for(var i=0; i<a.length; i++) {
		if(a[i] == value) {
			if(a.shift) a.shift(); // Delete this element from array for efficiency sake if supported.
			return true;
		}
	}
	
	return false;
};

HierarchicalMenu.clearState = function(menuId) {
    Cookie.deleteCookie(menuId);
};

HierarchicalMenu.loadState = function(menuId) {
	var cookieContent = Cookie.getCookie(menuId);
	if(cookieContent == '') return '';
	return cookieContent.split(',');
};

HierarchicalMenu.saveState = function(menuId, durationDays) { // Store index of opened ULs relative to other ULs in Tree into cookie.
	var ulElements = getElement(menuId).getElementsByTagName("ul");
	
	var openElementsList = '';
	for(var i=0; i<ulElements.length; i++) {
		if(ulElements[i].getAttribute("rel") == "open") {
			// Save the index of the opened UL.
			if(openElementsList != '') openElementsList += ',';
			openElementsList += i;
		}
	}

	// Are there any opened ULs to save/persist.
	// Set array value to string to simply indicate all ULs should persist with state being closed.
	if(openElementsList != '') {
		// Populate cookie with the name menuId with value 1,2,3 etc (where 1,2... are the indexes of the opened ULs).
		if(durationDays > 0) {
	        Cookie.setCookie(menuId, openElementsList, durationDays);
	    } else {
	        Cookie.setSessionCookie(menuId, openElementsList);
	    }
    } else {
        Cookie.deleteCookie(menuId);
	}
};

HierarchicalMenu.log = function(text) {
	var element = getElement('logtarget');
	if(!element) {
		element = document.createElement('DIV');
		element.id = 'logtarget';
		element.style.border = '1px solid black';
		document.body.insertBefore(element, document.body.firstChild)
	}
	
	var textNode = document.createTextNode(text + '\n\r');
	element.appendChild(textNode);
	element.appendChild(document.createElement('BR'));
};
