/**
 * This function is called from the main page to trigger loading of the menu.
 */
Page.loadXML = function(url) {
	jQuery.getJSON(url, Page.onLoadJsonCreateMenu);
}

/**
 * Event handler called when menu JSON AJAX request completes.
 */
Page.onLoadJsonCreateMenu = function(data, status) {

	if (Page.pageLoadComplete) {
		Page.buildMenuLevel0(data);
	} else {
		Page.menuJson = data;
	}
}

/**
 * Event handler called when the page has loaded.
 */
Page.onPageLoadCreateMenu = function() {
	if (Page.menuJson) {
		Page.buildMenuLevel0(Page.menuJson);
	}
	Page.pageLoadComplete = true;

	// Bind the event which collapses the menu when user clicks outside.
	jQuery(document.body).bind("click", Page.onClickOutsideMenu);
}

jQuery(document).ready(Page.onPageLoadCreateMenu);

/**
 * Builds the top level of the menu.
 * 
 * @param menuJson
 *            The JSON structure holding the menu.
 */
Page.buildMenuLevel0 = function(menuJson) {

	Page.cleanupMenus(jQuery(this));

	// Build the menu.
	var parentMenuDiv = jQuery("#menu");
	var originalMenuHeight = parentMenuDiv.height();
	var menuDiv = Page.populateMenu(menuJson.menu, Page.buildMenuLevel1);
	parentMenuDiv.append(menuDiv.attr("id", "menulevel0").css("width", "100%"));
	var spans = menuDiv.find("span");
	spans.each(function(index) {
		if (index > 0 && index < spans.size() - 1) {
			jQuery(this).addClass("adjustment");
		}
	});

	Page.itemDivsWidth = 0;

	menuDiv.children("div").each(function() {
		Page.itemDivsWidth += jQuery(this).width() + 4;
	});
	var remainWidth = menuDiv.width() - Page.itemDivsWidth - 1;

	if (remainWidth < 200) {

		var dec = (remainWidth / (spans.size() - 2)) * 0.5;
		var sum = 0;

		// Adjust the width of the horizontal menu to fill visible space.
		for (i = 2; i < (spans.size() - 1) * 2; i++) {

			sum += dec;

			var usablePixels = Math.round(sum);
			if (Math.abs(usablePixels) >= 1) {
				sum -= usablePixels;

				do {

					var thisMenuItem = jQuery(spans.get(parseInt(i / 2)));
					var currentPadding;
					if (i % 2 == 0) {

						// Left
						currentPadding = parseInt(thisMenuItem.css("paddingLeft").replace(/[^0-9]/g, ""));
						thisMenuItem.css("paddingLeft", (currentPadding + usablePixels) + "px");
					} else {

						// Right
						currentPadding = parseInt(thisMenuItem.css("paddingRight").replace(/[^0-9]/g, ""));
						thisMenuItem.css("paddingRight", (currentPadding + usablePixels) + "px");
					}

					// Weird fix to get around IE8 redraw problem - new paddings
					// dont take effect otherwise.
					spans.get(parseInt(i / 2)).style.margin = "0";
					usablePixels = -1;
				} while (parentMenuDiv.height() != originalMenuHeight && currentPadding > 0);
			}
		}
	}

	// If something was pre-selected at this level, go ahead and build the next
	// level now!
	var selectedItem = menuDiv.find(".selected");
	if (selectedItem.size() > 0) {
		Page.buildMenuLevel1(selectedItem);
	}
}

/**
 * Builds level 1 of the menu.
 * 
 * @param parentElement
 *            The parent menu item.
 */
Page.buildMenuLevel1 = function(parentElement) {

	// Cleanup and create the level 1 menu.
	Page.cleanupMenus(jQuery(parentElement));
	jQuery("#menuWrap").attr("class", "expanded");
	var menuDiv = Page.populateMenu(parentElement.data("childrenJson"), Page.buildMenuLevel2);
	if (menuDiv != null) {
		menuDiv.attr("id", "menulevel1").appendTo("#menu");
	}

	// If we've expanded a landingpage for the 1st time, immediately expand
	// children.
	var selectedItem = menuDiv.find(".selected");
	if (selectedItem.size() > 0 && location.search != null && new String(location.search).indexOf("mexpand=true") != -1) {
		Page.buildMenuLevel2(selectedItem);
	}
}

/**
 * Builds level 2 of the menu.
 * 
 * @param parentElement
 *            The parent menu item.
 */
Page.buildMenuLevel2 = function(parentElement) {

	// Cleanup and create the this menu level.
	Page.cleanupMenus(parentElement);
	var menuDiv = Page.populateMenu(parentElement.data("childrenJson"), Page.buildMenuLevel2);
	if (menuDiv != null) {

		menuDiv.attr("class", "menusublevel").appendTo("#menu");

		// position this menu.
		var menuOffset = jQuery("#menu").offset();
		var parentOffset = parentElement.offset();
		if (parentElement.parent().attr("id") == "menulevel1") {

			// Initial submenu, position in relation to the horizontal menu.
			menuDiv.css("top", (parentOffset.top - menuOffset.top + parentElement.height()) + "px");
			menuDiv.css("left", (parentOffset.left - menuOffset.left) + "px");

		} else {

			// Another nested submenu, position in relation to the other
			// submenu.
			menuDiv.css("top", (parentOffset.top - menuOffset.top + 4) + "px");
			menuDiv.css("left", (parentOffset.left - menuOffset.left + parentElement.width() - 4) + "px");
		}
	}
}

/**
 * Builds a menu level, by appending all the menu items found in the menuJson
 * array the returned div.
 * 
 * @param menuJson
 *            The immediate array holding the menu items.
 * @param nextLevelBuilderFunction
 *            The function to call when each item is clicked in the menu.
 * @return The created (parent) div holding all the menu items.
 */
Page.populateMenu = function(menuJson, nextLevelBuilderFunction) {

	if (menuJson == null) {
		return null;
	}

	var menuDiv = jQuery("<div>");

	for ( var i = 0; i < menuJson.length; i++) {
		var thisMenuItem = menuJson[i];

		var itemDiv = jQuery("<div>");
		itemDiv.bind("click", Page.onSelectMenu);
		itemDiv.data("nextLevelBuilderFunction", nextLevelBuilderFunction);
		itemDiv.bind("mouseover", Page.onMenuMouseOver);
		if (Page.isMenuItemSelected(thisMenuItem)) {
			itemDiv.addClass("selected");
			itemDiv.addClass("preselected");
		}
		if (thisMenuItem.url) {
			itemDiv.data("url", thisMenuItem.url);
		}
		if (thisMenuItem.children && thisMenuItem.children.length > 0) {
			itemDiv.addClass("submenu");
			itemDiv.data("childrenJson", thisMenuItem.children);
		}

		var span = jQuery("<span>" + thisMenuItem.title + "</span>").appendTo(itemDiv);
		itemDiv.appendTo(menuDiv);
	}

	return menuDiv;
}

/**
 * This examines the given menu item, and figures out if this should be
 * selected. It does so by examining the item itself and all its children, and
 * if its one of the children which is the selected one, this becomes selected
 * as well.
 * 
 * @param menuItemJson
 *            The item to examine.
 */
Page.isMenuItemSelected = function(menuItemJson) {

	var path = menuItemJson.path ? menuItemJson.path : menuItemJson.url;
	if (path != null) {

		// This item has an url, is it the selected one?
		var currentLocation = location.toString().replace(/\/?\?.*$/, "");
		if (currentLocation.length >= path.length && currentLocation.substring(0, path.length) == path) {
			return true;
		}
	}

	return false;
}

/**
 * Event handler when an item at level 1 in the menu is selected...
 */
Page.onSelectMenu = function() {

	var thisElement = jQuery(this);
	if (!thisElement.hasClass("selected").valueOf() || thisElement.hasClass("preselected").valueOf()) {

		// Select this item.
		thisElement.parent().children("div").removeClass("selected");
		thisElement.removeClass("preselected");
		thisElement.addClass("selected");

		if (thisElement.data("url")) {

			// This element has a URL, go there now!
			var url = new String(thisElement.data("url"));
			if (thisElement.data("childrenJson")) {
				url += url.indexOf('?') != -1 ? "&mexpand=true" : "?mexpand=true";
			}
			document.location = url;

		} else if (thisElement.data("childrenJson")) {

			// This element has children, call the builder for next menu level.
			thisElement.data("nextLevelBuilderFunction")(thisElement);
		}
	}
}

/**
 * This callback is invoked when an item in the menu has been clicked and the
 * target page has been loaded through AJAX.
 */
Page.onInjectionPageLoaded = function(data) {
	var page = jQuery(data);
	jQuery("#contentWrap").replaceWith(page.find("#contentWrap"));
	jQuery("#trailWrap").replaceWith(page.find("#trailWrap"));
}

/**
 * Cleans out the menu, removing unwanted submenus that are no longer valid.
 * 
 * @param parentElement
 *            The parent element of the menu about to be build.
 */
Page.cleanupMenus = function(parentElement) {

	if (parentElement.parent().attr("id") == "menulevel0") {
		jQuery("#menulevel1").remove();
	}

	// Clean up previous submenus and create a fresh one.
	if (parentElement.hasClass("submenu").valueOf()) {

		// Remove any open submenus opened after this one.
		parentElement.parent().nextAll(".menusublevel").remove();

	} else {

		// Parent wasnt a submenu itself, wipe all open submenus!
		jQuery("#menu > .menusublevel").remove();
	}
}

/**
 * This handler is called when the mouse hovers over a menu item.
 */
Page.onMenuMouseOver = function() {

	var thisElement = jQuery(this);

	if (!thisElement.data("initiated")) {
		thisElement.bind("mouseout", function() {
			jQuery(this).removeClass("over");
		});
		thisElement.data("initiated", "true");
	}
	thisElement.addClass("over");
}

/**
 * This handles takes care of collapsing the submenus when the user clicks
 * somewhere outside the menu area.
 */
Page.onClickOutsideMenu = function(event) {
	if (jQuery(event.target).parents("#menu").size() == 0) {

		var menuDiv = jQuery("#menu");
		Page.cleanupMenus(menuDiv);
		menuDiv.find(".selected").addClass("preselected");
	}
}

