////////////////////////////////////////////////////////////////////////////////
//   Vertical Menu Library
//   Notes: The menu items must be included in a span called 'spnVertMenu'
////////////////////////////////////////////////////////////////////////////////

// <script language="javascript">
// Copyright (c) Home Automation, Inc. All rights reserved.          
// Copyright (c) HomeRun Software Systems LLC. All rights reserved.

////////////////////////////////////////////////////////////////////////////////
// Globals
////////////////////////////////////////////////////////////////////////////////
var g_VM_VerticalMenu;			// Reference to control

////////////////////////////////////////////////////////////////////////////////
// Constants
////////////////////////////////////////////////////////////////////////////////
var VM_DIRECTION_UP    = 1;		// Scroll Upward
var VM_DIRECTION_DOWN  = 2;		// Scroll Downward

////////////////////////////////////////////////////////////////////////////////
// VerticalList: Create a new VerticalList Object
// Params: MarginTop = integer specifying margin between list and top of page
//         MarginRight = integer specifying margin between list and page right border
//         ListItemSpacing = integer specifying spacing between list items
//		   ResizeHorizontal = boolean specifying whether to resize list horizontally
// Notes: Set a paramater to null to use its default value
////////////////////////////////////////////////////////////////////////////////
function VerticalList
(
	MarginTop,
	MarginRight,
	ListItemSpacing,
	ResizeHorizontal
)
{
	// Functions
	this.Initialize				= VM_Init;
	this.Scroll					= VM_Scroll;
	this.ScrollPage				= VM_ScrollPage;
	this.SelectRow				= VM_SelectRow;
	this.SelectRowRemote		= VM_SelectRowRemote;
	this.DeselectRow			= VM_DeselectRow;
	this.ChooseRow				= VM_ChooseRow;
	this.SetStatusText			= VM_SetStatusText;
	this.ShowHideScrollButtons	= VM_ShowHideScrollButtons;
	
	// Position of first menu item vertically
	if (null == MarginTop)
		this.MarginTop		= 150;		
	else
		this.MarginTop		= MarginTop
		
	// Spacing between menu items
	if (null == ListItemSpacing)
		this.ListItemSpacing	= 5;		
	else
		this.ListItemSpacing	= ListItemSpacing;
	
	// Right margin of vertical menu
	if (null == MarginRight)
		this.MarginRight	= 75;		
	else
		this.MarginRight	= MarginRight;
		
	// Specifies whether list is resized horizontally
	if (null == ResizeHorizontal)
		this.ResizeHorizontal	= false;	
	else
		this.ResizeHorizontal	= ResizeHorizontal;

	this.HeightRatio		= .86;		// Default vertical menu size multiplier (676 @ 768 screen size)
	this.DisplayIndexFirst	= 0;		// Index of first item displayed
	this.DisplayIndexLast	= 0;		// Index of last item displayed
	this.SelectedItemIndex	= 0;		// Currently selected row
	this.MaxHeight			= 768;		// Max Height
	
	g_CurrentFocus = 0;

	// Initialize list
	this.Initialize();
}

////////////////////////////////////////////////////////////////////////////////
// VM_Init: Initialize Vertical Menu
////////////////////////////////////////////////////////////////////////////////
function VM_Init()
{
	var iPageWidth     = document.body.clientWidth;
	var iPageHeight    = document.body.clientHeight;
	var iMenuWidth;
	try
	{
		iMenuWidth     = tblVMItem[0].width;	// Default width for 1024x768 and lower resolution
	}
	catch(oError)
	{
		iMenuWidth     = tblVMItem.width;	// Default width for 1024x768 and lower resolution
	}
		
	var iMenuHeight    = 0;
	var iMenuTopCur    = 0;

	// Reset currently selected row
	this.SelectedItemIndex = 0;
	
	// Override page height/width when scaled
	if (g_bPageScaledDown)
	{
		iPageWidth  = 1024;
		iPageHeight = 768;
	}

	// Determine vertical display size
	this.MaxHeight = Math.round((iPageHeight * this.HeightRatio) - this.MarginTop);

	// Resize menu items horizontally
	var iListMarginLeft = 400;			// Default list margin to 400
	if (spnVertMenu.style.left != "")
		iListMarginLeft = spnVertMenu.style.left.substr(0,spnVertMenu.style.left.indexOf("px"));

	// Set horizontal width to avoid only partial display of transition
	spnVertMenu.style.width = iPageWidth - iListMarginLeft;
	
	if (this.ResizeHorizontal)
	{
		for (var x=0; x<tblVMItem.length; x++)
		{
			tblVMItem[x].width = iPageWidth - iListMarginLeft - this.MarginRight;
		}
	}

	spnVertMenu.filters[0].Apply();		// Set state for beginning of transition                 

	// Reset display count
	this.DisplayIndexFirst  = 0;
	this.DisplayIndexLast	= 0;
		
	// Align/Show list items
	if ( document.all.spnVMItem[0] )
	{
		// Align the page menu items
		for (var x = 0; x < spnVMItem.length; x++)
		{
			// Set the menu position
			spnVMItem[x].style.top = iMenuTopCur;
			
			// Display menu item if there is room
			spnVMItem[x].style.display = "inline";	// Need to set it to displayable to calculate height
			if ( (iMenuTopCur + spnVMItem[x].clientHeight) < this.MaxHeight)
			{
				// Show the item
				spnVMItem[x].style.display = "inline";
				
				// Increment last displayed
				this.DisplayIndexLast = x;
			}
			else
			{
				spnVMItem[x].style.display = "none";
			}
			
			// Calculate the next menu position
			iMenuTopCur = iMenuTopCur + spnVMItem[x].clientHeight + this.ListItemSpacing;
			
		}
		
	}
	else	// Only one menu item exists
	{
		// Set the menu position
		spnVMItem.style.top = iMenuTopCur;
		
		// Display menu item
		spnVMItem.style.display = "inline";
	}
	
	// Position and Show/Hide scroll buttons
	spnVMScrollButtons.style.left = iPageWidth - 204 - this.MarginRight;
	spnVMScrollButtons.style.top  = iPageHeight - 84;
	this.ShowHideScrollButtons(VM_DIRECTION_DOWN);
	
	spnVertMenu.filters[0].Play();
}

////////////////////////////////////////////////////////////////////////////////
// VM_Scroll: Scroll Vertical Menu up or down
// Params: Integer specifying VM_DIRECTION
////////////////////////////////////////////////////////////////////////////////
function VM_Scroll
(
	iDirection
)
{
	// If button was disabled then return without processing
	if ( (spnScrollUp.filters(0).src == AIButtonItem["VMScrollUp"].Disable.src) && 
	     (iDirection == VM_DIRECTION_UP) )
	     return;

	if ( (spnScrollUp.filters(0).src == AIButtonItem["VMScrollUp"].DisableSelect.src) && 
	     (iDirection == VM_DIRECTION_UP) )
	{
		PlaySound(SOUND_BONK);
		return;
	}
	     
	if ( (spnScrollDown.filters(0).src == AIButtonItem["VMScrollDown"].Disable.src) && 
	     (iDirection == VM_DIRECTION_DOWN) )
	     return;

	if ( (spnScrollDown.filters(0).src == AIButtonItem["VMScrollDown"].DisableSelect.src) && 
	     (iDirection == VM_DIRECTION_DOWN) )
	{
		PlaySound(SOUND_BONK);
		return;
	}

	spnVertMenu.filters[0].Apply();		// Set state for beginning of transition                 

	var iMenuSize = this.MaxHeight;
	var bVisible  = true;

	// Perform direction-specific actions
	if (iDirection == VM_DIRECTION_DOWN)
	{
		this.DisplayIndexLast++;	// Increment last displayed

		// Loop through menu items and display/hide them
		for (var x = this.DisplayIndexLast; x >= 0; x--)
		{
			spnVMItem[x].style.display = "inline";	// Need to set it to displayable to calculate height
			if ( bVisible && ((spnVMItem[x].clientHeight) < iMenuSize) )
			{
				// Show the item
				spnVMItem[x].style.display = "inline";
				
				// Set the first item displayed
				this.DisplayIndexFirst = x;
			}
			else
			{
				// Hide the item
				spnVMItem[x].style.display = "none";
				bVisible = false;
			}
			
			// Calculate remaining menu size
			iMenuSize-= (spnVMItem[x].clientHeight + this.ListItemSpacing);
		}
		
		// Handle page-specific actions
		if (g_iCurrentPage == PAGE_EVENT || g_iCurrentPage == PAGE_SECURITY_ZONES || g_iCurrentPage == PAGE_HOME || g_iCurrentPage == PAGE_SRVRLOG)
		{
			this.SelectedItemIndex++;
		}
	}
	else		// DIRECTION = UP
	{
		this.DisplayIndexFirst--;	// Decrement first displayed
		
		// Loop through menu items and display/hide them
		for (var x = this.DisplayIndexFirst; x < spnVMItem.length; x++)
		{
			spnVMItem[x].style.display = "inline";	// Need to set it to displayable to calculate height
			if ( bVisible && ((spnVMItem[x].clientHeight) < iMenuSize) )
			{
				// Show the item
				spnVMItem[x].style.display = "inline";
				
				// Set the last item displayed
				this.DisplayIndexLast = x;
			}
			else
			{
				// Hide the item
				spnVMItem[x].style.display = "none";
				bVisible = false;
			}
			
			// Calculate remaining menu size
			iMenuSize-= (spnVMItem[x].clientHeight + this.ListItemSpacing);		
		}
		
		// Handle page-specific actions
		if (g_iCurrentPage == PAGE_EVENT || g_iCurrentPage == PAGE_SECURITY_ZONES || g_iCurrentPage == PAGE_HOME || g_iCurrentPage == PAGE_SRVRLOG)
		{
			this.SelectedItemIndex--;
		}
	}	
				
	// Align the page menu items vertically
	var iMenuTopCur = 0;
	for (var x = 0; x < spnVMItem.length; x++)
	{
		if (spnVMItem[x].style.display == "inline")
		{
			// Set the menu position
			spnVMItem[x].style.top = iMenuTopCur;
			
			// Calculate the next menu position
			iMenuTopCur = iMenuTopCur + spnVMItem[x].clientHeight + this.ListItemSpacing;
		}
	}

	// Show/Hide scroll buttons
	this.ShowHideScrollButtons(iDirection);
	
	spnVertMenu.filters[0].Play();
}

////////////////////////////////////////////////////////////////////////////////
// VM_ScrollPage: Page Vertical Menu up or down
// Params: Integer specifying VM_DIRECTION
////////////////////////////////////////////////////////////////////////////////
function VM_ScrollPage
(
	iDirection
)
{
	// If button was disabled then return without processing
	if ( (spnScrollUp.filters(0).src == AIButtonItem["VMScrollUp"].Disable.src) && 
	     (iDirection == VM_DIRECTION_UP) )
	     return;

	if ( (spnScrollUp.filters(0).src == AIButtonItem["VMScrollUp"].DisableSelect.src) && 
	     (iDirection == VM_DIRECTION_UP) )
	{
		PlaySound(SOUND_BONK);
		return;
	}
	     
	if ( (spnScrollDown.filters(0).src == AIButtonItem["VMScrollDown"].Disable.src) && 
	     (iDirection == VM_DIRECTION_DOWN) )
	     return;

	if ( (spnScrollDown.filters(0).src == AIButtonItem["VMScrollDown"].DisableSelect.src) && 
	     (iDirection == VM_DIRECTION_DOWN) )
	{
		PlaySound(SOUND_BONK);
		return;
	}

	spnVertMenu.filters[0].Apply();		// Set state for beginning of transition                 

	// Deselect current row
	if (g_iCurrentPage != PAGE_EVENT && g_iCurrentPage != PAGE_SECURITY_ZONES && g_iCurrentPage != PAGE_HOME && g_iCurrentPage != PAGE_SRVRLOG)
		this.DeselectRow();
	
	var iMenuSize = this.MaxHeight;
	var bVisible  = true;
	var bOverridePageUp = false;
	
	// Hide current displayed items
	for (var x = this.DisplayIndexFirst; x <= this.DisplayIndexLast; x++)
		spnVMItem[x].style.display = "none";

	// Perform direction-specific actions for Page Up
	if (iDirection == VM_DIRECTION_UP)
	{
		this.DisplayIndexLast = this.DisplayIndexFirst - 1;

		// Loop through menu items and display/hide them
		for (var x = this.DisplayIndexLast; x >= 0; x--)
		{
			spnVMItem[x].style.display = "inline";	// Need to set it to displayable to calculate height
			if ( bVisible && ((spnVMItem[x].clientHeight) < iMenuSize) )
			{
				// Show the item
				spnVMItem[x].style.display = "inline";
				
				// Set the last item displayed
				this.DisplayIndexFirst = x;
			}
			else
			{
				// Hide the item
				spnVMItem[x].style.display = "none";
				bVisible = false;
			}
			
			// Calculate remaining menu size
			iMenuSize-= (spnVMItem[x].clientHeight + this.ListItemSpacing);		
		}	
		
		// Check the amount of real-estate used by the menu. If the amount is less than 75% of the 
		// available space then we have likely scrolled to the top of the list...so we should try
		// displaying more list items
		if ( iMenuSize > (this.MaxHeight	 *.25) )
		{
			iDirection = VM_DIRECTION_DOWN;
			bOverridePageUp = true;
			bVisible = true;
			iMenuSize = this.MaxHeight;
		}
	}

	// Perform direction-specific actions for Page Down
	if (iDirection == VM_DIRECTION_DOWN)
	{
		if (!bOverridePageUp)
			this.DisplayIndexFirst = this.DisplayIndexLast + 1;
		
		// Loop through menu items and display/hide them
		for (var x = this.DisplayIndexFirst; x < spnVMItem.length; x++)
		{
			spnVMItem[x].style.display = "inline";	// Need to set it to displayable to calculate height
			if ( bVisible && ((spnVMItem[x].clientHeight) < iMenuSize) )
			{
				// Show the item
				spnVMItem[x].style.display = "inline";
				
				// Set the last item displayed
				this.DisplayIndexLast = x;
			}
			else
			{
				// Hide the item
				spnVMItem[x].style.display = "none";
				bVisible = false;
			}
			
			// Calculate remaining menu size
			iMenuSize-= (spnVMItem[x].clientHeight + this.ListItemSpacing);		
		}	
	}

	// Set the new row
	this.SelectedItemIndex = this.DisplayIndexFirst;

	// Select the new row
	switch(g_iCurrentPage)
	{
		case PAGE_EVENT:
		case PAGE_SRVRLOG:
		case PAGE_SECURITY_ZONES:
			break;
		case PAGE_HOME:
			//this.SelectRow(spnVertMenu.childNodes[this.SelectedItemIndex].childNodes[0].childNodes[0].childNodes[0].childNodes[1].childNodes[0].childNodes[0].childNodes[0])
			break;
		default:
			this.SelectRow(spnVertMenu.childNodes[this.SelectedItemIndex].childNodes[0].childNodes[0].childNodes[0]);
	}
	
	// Align the page menu items vertically
	var iMenuTopCur = 0;
	for (var x = 0; x < spnVMItem.length; x++)
	{
		if (spnVMItem[x].style.display == "inline")
		{
			// Set the menu position
			spnVMItem[x].style.top = iMenuTopCur;
			
			// Calculate the next menu position
			iMenuTopCur = iMenuTopCur + spnVMItem[x].clientHeight + this.ListItemSpacing;
		}
	}

	// Show/Hide scroll buttons
	this.ShowHideScrollButtons(iDirection);
	
	spnVertMenu.filters[0].Play();
}

////////////////////////////////////////////////////////////////////////////////
// VM_SelectRow: Selects the specified row
// Params: oRow = a reference to a TR element
//         bUsedMouse = boolean specifying whether mouse was used to choose row
////////////////////////////////////////////////////////////////////////////////
function VM_SelectRow
(
	oRow,
	bUsedMouse
)
{
	// Loop through each <TD> element and set selection
	for (var x=0; x<oRow.childNodes.length; x++)
	{
		oRow.childNodes[x].className = "VMItemSelect";
	}

	// Set the currently selected row if navigated to via the mouse
	if (bUsedMouse)
	{
		var iNewRow = oRow.parentElement.parentElement.parentElement.ItemID;
		
		// Deselect the currently selected row
		if (this.SelectedItemIndex != iNewRow)
			this.DeselectRow();

		// Set newly selected row
		this.SelectedItemIndex = iNewRow;

		// If this is the first time the list is accessed then need to set focus to list
		for (var x=0; x<g_aryFocusTable.length; x++)
		{
			if (g_aryFocusTable[x][7] == spnVertMenu)
			{
				g_CurrentFocus = x;
			}
		}

		// Set scroll status text
		this.SetStatusText();
	}
	PlaySound(SOUND_SELECT);
}

////////////////////////////////////////////////////////////////////////////////
// VM_SelectRowRemote: Select Row specified by keyboard/remote control
// Params: iRow = integer specifying row to select
////////////////////////////////////////////////////////////////////////////////
function VM_SelectRowRemote
(
	iRow
)
{
	var iNewRow = iRow;

	switch (g_LastKeyChar)
	{
        case 0x26:				// Up button selected
        case 0x38:
			iNewRow = (this.SelectedItemIndex-0) - 1;
			break;
        case 0x28:				// Down button selected
        case 0x40:
			iNewRow = (this.SelectedItemIndex-0) + 1;
		default:
			if (null == iNewRow)
				iNewRow = this.SelectedItemIndex;
	}

	try
	{
		// If the new row is valid then select/deselect rows
		if ( (iNewRow >= 0) && (iNewRow < spnVertMenu.childNodes.length) )
		{
			this.DeselectRow();
			
			// Set the new row
			this.SelectedItemIndex = iNewRow;
			
			// Scroll up as necessary
			if ( this.SelectedItemIndex < this.DisplayIndexFirst )
				this.Scroll(VM_DIRECTION_UP);

			// Scroll down as necessary
			if ( this.SelectedItemIndex > this.DisplayIndexLast )
				this.Scroll(VM_DIRECTION_DOWN);
			
			// Select the new row
			if (g_iCurrentPage == PAGE_HOME)
				this.SelectRow(spnVertMenu.childNodes[this.SelectedItemIndex].childNodes[0].childNodes[0].childNodes[0].childNodes[1].childNodes[0].childNodes[0].childNodes[0])
			else
				this.SelectRow(spnVertMenu.childNodes[this.SelectedItemIndex].childNodes[0].childNodes[0].childNodes[0]);
			
			// Set scroll status text
			this.SetStatusText();
		}
	}
	catch (oError)
	{
	}
}

////////////////////////////////////////////////////////////////////////////////
// VM_DeselectRow: Deselect the currently selected row
////////////////////////////////////////////////////////////////////////////////
function VM_DeselectRow()
{
	try
	{
		if ( (this.SelectedItemIndex >= 0) && (this.SelectedItemIndex < spnVertMenu.childNodes.length) )
		{
			var oRow;
			if (g_iCurrentPage == PAGE_HOME)
				oRow = spnVertMenu.childNodes[this.SelectedItemIndex].childNodes[0].childNodes[0].childNodes[0].childNodes[1].childNodes[0].childNodes[0].childNodes[0];
			else
			{		
				oRow = spnVertMenu.childNodes[this.SelectedItemIndex].childNodes[0].childNodes[0].childNodes[0];
			}
			// Loop through each <TD> element and set selection
			for (var x=0; x<oRow.childNodes.length; x++)
			{
				if (g_iCurrentPage == PAGE_HOME)
					oRow.childNodes[x].className = "SectionHeader";
				else
					oRow.childNodes[x].className = "VMItem";
			}
		}
	}
	catch (oError)
	{
	}	
}

////////////////////////////////////////////////////////////////////////////////
// VM_ChooseRow: MouseClick & Enter event for menu item
// Params: iPage = integer identifying page to load
////////////////////////////////////////////////////////////////////////////////
function VM_ChooseRow
(
	iPage
)
{
	var iDataID = spnVertMenu.childNodes[this.SelectedItemIndex].DataID;

	switch (g_iCurrentPage)
	{
		case PAGE_BUTTON:
			CMD_Button(iDataID);
			RefreshCurrentPage();
			break;
		case PAGE_TEMPERATURE:
			iPage = parseInt(spnVertMenu.childNodes[this.SelectedItemIndex].GotoPage);
			ShowPage(iPage, iDataID);
			break;
		default:
			ShowPage(iPage,iDataID);
	}
}

////////////////////////////////////////////////////////////////////////////////
// VM_SetStatusText: Set the scroll status text
////////////////////////////////////////////////////////////////////////////////
function VM_SetStatusText()
{
	var iCurrentItem = (this.SelectedItemIndex-0) + 1;

	if (iCurrentItem > 0)
		spnVMScrollStatus.innerText = (iCurrentItem) + " of " + spnVMItem.length;
}

////////////////////////////////////////////////////////////////////////////////
// VM_ShowHideScrollButtons: Show or hide the scroll buttons
////////////////////////////////////////////////////////////////////////////////
function VM_ShowHideScrollButtons
(
	iDirection
)
{
	var bShowScroll = false;
	
	// Reset button source to deselected state
	spnScrollUp.filters(0).src = AIButtonItem["VMScrollUp"].Deselect.src
	spnScrollDown.filters(0).src = AIButtonItem["VMScrollDown"].Deselect.src

	// Determine display for scroll down
	if ( this.DisplayIndexLast < (spnVMItem.length-1) )
	{
		if (iDirection == VM_DIRECTION_DOWN)
		{
			if (g_iCurrentPage == PAGE_EVENT || g_iCurrentPage == PAGE_SECURITY_ZONES || g_iCurrentPage == PAGE_HOME || g_iCurrentPage == PAGE_SRVRLOG)
				AIButtonSelect(spnScrollDown, 'VMScrollDown');
		}
		bShowScroll = true;

	}
	else
	{
		AIButtonDisable(spnScrollDown, 'VMScrollDown');
		if (g_iCurrentPage == PAGE_EVENT || g_iCurrentPage == PAGE_SECURITY_ZONES || g_iCurrentPage == PAGE_HOME || g_iCurrentPage == PAGE_SRVRLOG)
			AIButtonSelect(spnScrollUp, 'VMScrollUp');
	}

	// Determine display for scroll up
	if ( this.DisplayIndexFirst > 0 )
	{
		if (iDirection == VM_DIRECTION_UP)
		{
			if (g_iCurrentPage == PAGE_EVENT || g_iCurrentPage == PAGE_SECURITY_ZONES || g_iCurrentPage == PAGE_HOME || g_iCurrentPage == PAGE_SRVRLOG)
				AIButtonSelect(spnScrollUp, 'VMScrollUp');
		}
		bShowScroll = true;
	}
	else
	{
		AIButtonDisable(spnScrollUp, 'VMScrollUp');
		if (g_iCurrentPage == PAGE_EVENT || g_iCurrentPage == PAGE_SECURITY_ZONES || g_iCurrentPage == PAGE_HOME || g_iCurrentPage == PAGE_SRVRLOG)
			AIButtonSelect(spnScrollDown, 'VMScrollDown');
	}


	if (bShowScroll)
	{
		// Set scroll status text
		this.SetStatusText();
		
		// Show the scroll buttons
		spnVMScrollButtons.style.display = "inline";	
	}
	else
	{
		// Hide the scroll buttons
		spnVMScrollButtons.style.display = "none";	
	}
}

