/*
$HeadURL: svn+secure://svn.comminternet.com/main/websites/provincetownrealestate.com/trunk/web/common/framework/javascript/cxMenu.js $
$LastChangedRevision: 7026 $
$LastChangedDate: 2010-03-22 14:15:22 -0400 (Mon, 22 Mar 2010) $
*/

cxMenu_menuIDPrefix = "cxMenu";

// Create a separate settings function with a numerical index corresponding to each menu
// you define on the page.
function cxMenu_menuSettings0()
{
    this.hideDelay = 250;
    this.isHorizontal = true;
    this.isPopUp = true;
    this.showFunction = "onmouseover";
    this.hideFunction = "onmouseout";
    this.childMenuDisplayStyle = "block";
}

// -----

if (cxDOM_canGetElementByID())
    cxMenu_initialize();

function cxMenu_initialize()
{
    var matches;
    var menuID;
    var menuSettings;

    // Get all unordered lists on the page.
    var lists = cxDOM_getElementsByTagName("ul");
    for (var i = 0; i < lists.length; ++i)
    {
	// Only handle initialization for top-level menus.
	if (lists[i].id.match(/^cxMenu(\d+)$/))
	{
	    menuID = lists[i].id.substring(lists[i].id.indexOf(cxMenu_menuIDPrefix) + cxMenu_menuIDPrefix.length)

	    menuSettings = new window["cxMenu_menuSettings" + menuID];
	    menuSettings.timeouts = new Array();
	    menuSettings.currentlyDisplayedItem = new Array();

	    cxMenu_initializeList(lists[i], menuSettings, lists[i].id, 1);
	}
    }
}

function cxMenu_initializeList(pList, pMenuSettings, pIDString, pDepth)
{
    var childIndex = 0;
    var childListIndex = 0;
    var children = pList.childNodes;
    var offsetLeft = 0;
    var offsetTop = 0;

    // If this list has already been initialized, don't do it again. Otherwise, indicate
    // that this list has been initialized.
    if (pList.cxMenu_isInitialized)
	return;
    else
	pList.cxMenu_isInitialized = true;

    // Position all sublists.
    if (pDepth > 1)
    {
	if (pMenuSettings.isPopUp)
	    pList.style.position = "absolute";

	// Indicate that this list is a submenu.
	pList.cxMenu_isSubmenu = true;
    }

    if (pMenuSettings.isPopUp)
    {
	if (pDepth >= 3 || (!pMenuSettings.isHorizontal && pDepth >= 2))
	{
	    pList.style.left = (pList.parentNode.offsetLeft + pList.parentNode.offsetWidth) + "px";
	    pList.style.top = (pList.parentNode.offsetTop - 1) + "px";
	} else if (pMenuSettings.isHorizontal && pDepth == 2) {
	    pList.style.left = pList.parentNode.offsetLeft + "px";
	    pList.style.top = (pList.parentNode.offsetTop + pList.parentNode.offsetHeight) + "px";
	}
    }

    // Loop through each child of this list.
    for (var i = 0; i < children.length; ++i)
    {
	// We're only interested in children that are list items.
	if (children[i].tagName != "LI")
	    continue;

	// Give this list item a unique ID if it doesn't already have one.
	if (!children[i].id)
	    children[i].id = pIDString + "_" + childIndex++;

	// Save this menu's settings with the item.
	children[i].cxMenu_menuSettings = pMenuSettings;
	// Indicate whether this list item is part of a submenu.
	children[i].cxMenu_isSubmenu = pList.cxMenu_isSubmenu;
	// Save the depth of this list item.
	children[i].cxMenu_depth = pDepth;

        // Initialize the list item with the not-hovering class.
        cxGeneral_addClassName(children[i], "notHover");

	// Loop through each child of this list item.
	var grandchildren = children[i].childNodes;
	for (var j = 0; j < grandchildren.length; ++j)
	{
	    // If this list item has a child list, we need to initialize it as well.
	    if (grandchildren[j].tagName == "UL")
	    {
		// Give this child list a unique ID if it doesn't already have one.
		if (!grandchildren[j].id)
		    grandchildren[j].id = pIDString + "_l" + childListIndex++;

		// Point the list item to its child list.
		children[i].cxMenu_childList = grandchildren[j];
		// Indicate that the parent list item is expandable.
		children[i].cxMenu_isExpandable = true;

		// Give the list item a class to indicate that it is expandable.
		cxGeneral_addClassName(children[i], "expandable");

		// Give the list item a class to indicate that it is a submenu.
		if (children[i].cxMenu_isSubmenu)
		    cxGeneral_addClassName(children[i], "submenu");

		// If there is more than one child list, the rest are ignored.
		break;
	    }
	}

	// Set timeouts to show and hide the child list for this list item.
	children[i][pMenuSettings.showFunction] = function(pEvent) {

	    // Don't fire this event on parent elements.
	    cxGeneral_cancelBubble(pEvent);

	    // Initialize the child list if it exists. It won't be reinitialized if it's already been initialized.
            if (this.cxMenu_childList)
	        cxMenu_initializeList(this.cxMenu_childList, pMenuSettings, this.id, pDepth + 1);

	    // Clear hide timeouts on the parent node.
	    clearTimeout(pMenuSettings.timeouts[this.parentNode.parentNode.id]);

	    // Hover the list item immediately.
	    cxMenu_setListItemHoverState(this, true);
	    clearTimeout(pMenuSettings.timeouts[this.id]);

	    // Display this item.
	    if (pMenuSettings.isPopUp)
	        cxMenu_setChildListState(this, true);
	    else
		cxMenu_setChildListState(this, !this.cxMenu_displayed);
	};

	if (pMenuSettings.hideFunction)
	{
	    children[i][pMenuSettings.hideFunction] = function(pEvent) {

		// Don't fire this event on parent elements.
		//cxGeneral_cancelBubble(pEvent);

		// Unhover the list item immediately.
		cxMenu_setListItemHoverState(this, false);

		clearTimeout(pMenuSettings.timeouts[this.id]);
		pMenuSettings.timeouts[this.id] = setTimeout("cxMenu_setChildListState(cxDOM_getElementByID('" + this.id + "'), false)", pMenuSettings.hideDelay);
	    };
	}
    }
}

function cxMenu_setListItemHoverState(pElement, pShow)
{
    if (pShow) {
        cxGeneral_removeClassName(pElement, "notHover");
        cxGeneral_addClassName(pElement, "hover");
    } else {
        cxGeneral_removeClassName(pElement, "hover");
        cxGeneral_addClassName(pElement, "notHover");
    }
}

function cxMenu_setChildListState(pElement, pShow)
{
    pElement.cxMenu_displayed = pShow;

    // If there is a child list...
    if (typeof(pElement.cxMenu_childList) != "undefined")
    {
	// Display the list item's child list.
	if (pShow)
	{
	    if (pElement.cxMenu_isExpandable)
	    {
		// Hide the item on this level that is currently displayed.
		if (pElement.cxMenu_menuSettings.currentlyDisplayedItem[pElement.cxMenu_depth] && pElement.cxMenu_menuSettings.currentlyDisplayedItem[pElement.cxMenu_depth].id != pElement.id)
		    cxMenu_setChildListState(pElement.cxMenu_menuSettings.currentlyDisplayedItem[pElement.cxMenu_depth], false);

		// Save this item as the currently displayed item on this level.
		pElement.cxMenu_menuSettings.currentlyDisplayedItem[pElement.cxMenu_depth] = pElement;
	    }

	    pElement.cxMenu_childList.style.display = pElement.cxMenu_menuSettings.childMenuDisplayStyle;

	// Hide the child list and its descendents.
	} else {

	    pElement.cxMenu_childList.style.display = "none";

	    // Because the absolutely positioned descendent lists aren't hidden when the parent
	    // list is, we have to hide them manually. We keep a queue of nodeLists of descendent
	    // list items which need to have their child lists hidden. As each child list is hidden,
	    // a nodeList with all of its child list items is added to the queue, so that each child list
	    // item's descendents are hidden as well.
	    var nodeLists = new Array();
	    var currentNodeList;

	    // Initialize the first element in the queue with the child list items of this list.
	    nodeLists[0] = pElement.cxMenu_childList.childNodes;
	    while (currentNodeList = nodeLists.shift())
	    {
		for (var i = 0; i < currentNodeList.length; ++i)
		{
		    // If this child isn't a list item or doesn't have a child list (i.e., is a terminal node), skip it.
		    if (currentNodeList[i].tagName != "LI" || !currentNodeList[i].cxMenu_childList)
			continue;

		    currentNodeList[i].cxMenu_childList.style.display = "none";

		    nodeLists.push(currentNodeList[i].cxMenu_childList.childNodes);
		}
	    }
	}
    }
}
