/*f
********************************************************************************************************************************************************************
* Name              :
*
* Description       :
*
* Author(S)         : JSHUMAKER
*
* Creation Date     : 1/11/2007
*
* Version           : 1.0
*
*
* Modifications:
*    MOD ID          Date              Developer Name                   Description
*    ------------    --------------    -----------------------------    ----------------------------------------------------
*
* VSS Info:
*      $Archive:
*      $Author:
*              $Date:
*              $Revision:
*
*  COPYRIGHT 2005 TDCI Inc.
********************************************************************************************************************************************************************
*/

/*
Class: GraphicButtonPanel
Public Functions:
    UpdateContent(Command)
        Command -   The ControlCommand object that should be passed during the update.
             This function will call a delegate function specified by the GraphicButtonPanel's
             OnUpdateContent function and provide the means for the panel's content to change.

    SetClientClick(ClientClick)
        ClientClick -     The javascript to execute when a Button inside the 
            GraphicButtonPanel is clicked. You may reference the CommandName and CommandArgument
            variables from within the javascript specified in this property.
    
    GetClientClick()
        Return -     The javascript that will be executed when a Button inside the 
            GraphicButtonPanel is clicked.
    
    SetEnabled(ControlEnabled)
        ControlEnabled -    A boolean value that specifies whether or not the GraphicButtonPanel
            should function.
    
    GetEnabled()
        Return -    A boolean value that represents whether or not the GraphicButtonPanel is 
            currently functioning.
    
    SetHoverEnabled(HoverEnabled)
        HoverEnabled -    A boolean value that specifies whether or not the GraphicButtonPanel
            should have hovering styles.
    
    GetHoverEnabled()
        Return -    A boolean value that represents whether or not the GraphicButtonPanel
            has hovering styles.
    
    SetPanelType(PanelType)
        PanelType -     This property specifies the type of panel that should be used.
            0 - The panel will not have any toggling capability.
            1 - Only one GraphicButton within the panel may be selected.
            2 - There will always be one and only one GraphicButton that
                is selected at any given time. This functionality is much like a group of
                radio buttons.
            3 - There may be any number of GraphicButtons within the panel that
                are selected.
            4 - There is at least one GraphicButton within the panel that
                is selected but there may also be more than one.
        
    GetPanelType()
        Return -     This property represents the type of panel that is used.
    
    SetSelected(Selected)
        Selected -  An array of ControlCommand objects that specify which GraphicButtons
            should be selected.
    
    GetSelected()
        Return -  An array of ControlCommand objects that represent which GraphicButtons
            are currently selected.
    
    SetCurrentGroup(CurrentGroup)
        CurrentGroup -  The zero based index of the group that should be shown within the 
            GraphicButtonPanel.
    
    GetCurrentGroup()
        Return -  The zero based index of the group that is shown within the 
            GraphicButtonPanel.

    GetScrollType()
        Return -    An integer that represents the type of scrolling that is used.
            0 - No scrolling
            1 - Smooth scrolling
            2 - Fixed scrolling
    
    GetScrollInterval()
        Return -    An integer that represnts the number of GraphicButtons that
            will be scrolled with fixed scrolling.
    
    GetRows()
        Return -    An integer that represents the number of rows in each group.
    
    GetCols()
        Return -    An integer that represents the number of cols in each group.

    NumViewableButtons()
        Return -    An integer that represents the number of GraphicButtons that are
            currently in the viewing area of the GraphicButtonPanel.
    
    NumButtons()
        Return -    An integer that represents the number of GraphicButtons within
            the GraphicButtonPanel.
    
    NumGroups()
        Return -    An integer that represents the number of groups within the 
            GraphicButtonPanel.    
*/

GraphicButtonPanel = Class.create();
GraphicButtonPanel.prototype = 
{
    initialize: function(OuterDivID)
    {
        var TempGroup = 0;

	    // state variables
        this.IsMouseOver = false;
        this.ClientID = OuterDivID;
        
        // object variables
        this.OuterDiv = null;
        this.DataField = null;
        this.Window = null;
        this.Buffer = null;
        this.Previous = null;
        this.Next = null;
        this.Transparent = null;
        
        //Assign references to the object variables
        this.OuterDiv = $(OuterDivID);

        //Change VB true/false values to javascript true/false values
        this.ParseInitialValues();

    
        this.ReferenceStructure();
        this.ToggleTransparency(true);


        //Initialize the GraphicButtons
        this.InitializeGraphicButtons();

        //Make sure the client on click is cleared
        //  This functionality will be executed during the mouse down event.
        //  This simplifies the event handling and toggling.
        this.OuterDiv.onclick = null;

        //Build up pointers to all event handlers so that they can be removed with
        //  stopObserving.
        this.EventHandlerWindowOver = this.WindowOver.bindAsEventListener(this);
        this.EventHandlerWindowOut = this.WindowOut.bindAsEventListener(this);
        this.EventHandlerMouseWheel = this.MouseWheel.bindAsEventListener(this);

        //Attach Events
        //    Prototype automatically does cleanup on these events so 
        //    a disposal method is not necessary
        
        //Use the SetEnabled & SetHoverEnabled methods to correctly hook the right event handlers.
        if (this.OuterDiv.ControlEnabled)
        {
            this.OuterDiv.ControlEnabled = false;
            this.SetEnabled(true);

            if (this.OuterDiv.HoverEnabled)
            {
                this.OuterDiv.HoverEnabled = false;
                this.SetHoverEnabled(true);
            }
        }

        
        //Setup the current group
        TempGroup = this.OuterDiv.CurrentGroup;
        this.OuterDiv.CurrentGroup = -1;
        this.SetCurrentGroup(TempGroup);


        this.PreviousMidPoint = 0;        

        //Compute the number of buttons in the first group so that this doesn't have to be computed later.
        this.EndingButtons();
        
        //COmpute the scrolling distance so we don't have to compute it later.
        this.OuterDiv.ScrollDist = this.GetDistToScroll();

        this.UpdateAttributes();
        this.UpdateScrolling();
        
        this.ToggleTransparency(false);

        return true;
    },
    
    InitializeGraphicButtons: function()
    {
        var Index = 0;
        var SelectedIndex = 0;
        var Found = false;
        var ClientID = "";
        
        for (Index = 0; Index < this.Buttons.length; Index++)
        {
            ClientID = this.Buttons[Index];
            this.Buttons[Index] = this.CreateGraphicButton(ClientID, 0, Index);
            
            Found = false;
            SelectedIndex = 0;
            while (!Found && SelectedIndex < this.OuterDiv.SelectedButtons.length)
            {
                if (this.OuterDiv.SelectedButtons[SelectedIndex] == ClientID)
                {
                    this.OuterDiv.SelectedButtons[SelectedIndex] = Index;
                    Found = true;
                }
                
                SelectedIndex++;
            }
        }
    },
    
    CreateGraphicButton: function(ButtonID, ButtonType, Index)
    {
        var Button = new GraphicButton(ButtonID);

        switch (ButtonType)
        {
            case 0: //Panel Button
                Button.SetClientChangeInContext(this, "this.ClientChange(" + Index + ");");
                Button.SetClientClickInContext(this, "this.ClientClick(this.Buttons[" + Index + "].GetCommand(), HandledEvent);");
                break;
            case 1: //Previous Button
                if (this.OuterDiv.ScrollType == 3)
                {
                    Button.SetClientClickInContext(this, "this.Fetch(" + Button.GetClientClick + ", false);");
                }
                else
                {
                    Button.SetClientContinuousClickAddonInContext(this, "this.ScrollPrevious();");
                }
                break;
            case 2: //Next Button
                if (this.OuterDiv.ScrollType == 3)
                {
                    Button.SetClientClickInContext(this, "this.Fetch(" + Button.GetClientClick + ", true);");
                }
                else
                {
                    Button.SetClientContinuousClickAddonInContext(this, "this.ScrollNext();");
                }
                break;
        }

        return Button;
    },
    
//Client-side Properties*****************************

    //Behavior Properties
    SetUpdateShowing: function(Showing)
    {
        this.OuterDiv.SetShowing = Showing;
    },
    
    UpdateShowing: function()
    {
        this.ComputeShowing();
    },
    
    SetSelectionFinished: function(FunctionPointer)
    {
        this.OuterDiv.SelectionFinished = FunctionPointer;
    },

    SetClientClickInContext: function(Object, Command)
    {
        this.OuterDiv.OnEnabledClick = Command;
        this.OuterDiv.OnEnabledClickInContext = Object;
        this.OuterDiv.OnEnabledClickInContextFunction = function(HandledEvent)
        {
            return eval(Command);
        };
        this.OuterDiv.OnEnabledClickInContextPointer = this.OuterDiv.OnEnabledClickInContextFunction.bind(Object);
        
//        this.SaveState();
    },

    SetClientClick: function(ClientClick)
    {
        if (ClientClick != this.OuterDiv.OnEnabledClick)
        {
            this.OuterDiv.OnEnabledClick = ClientClick;
            
//            this.SaveState();
            
            return true;
        }
        
        return false;
    },
    
    GetClientClick: function()
    {
        return this.OuterDiv.OnEnabledClick;
    },
    
    
    
    //Status Properties
    SetEnabled: function(ControlEnabled)
    {
        if (ControlEnabled != this.OuterDiv.ControlEnabled)
        {
            this.OuterDiv.ControlEnabled = ControlEnabled;
            
            this.UpdateButtonStatus();
            
            this.UpdateAttributes();
            
            if (ControlEnabled && this.OuterDiv.ScrollType != 0)
            {
                if (window.addEventListener)    //Fix for mozilla
                {
                    Event.observe(this.Window, 'DOMMouseScroll', this.EventHandlerMouseWheel);
                }
                else
                {
                    Event.observe(this.Window, 'mousewheel', this.EventHandlerMouseWheel);
                }
            }
            else if (this.OuterDiv.ScrollType != 0)
            {
                if (window.addEventListener)    //Fix for mozilla
                {
                    Event.stopObserving(this.Window, 'DOMMouseScroll', this.EventHandlerMouseWheel);
                }
                else
                {
                    Event.stopObserving(this.Window, 'mousewheel', this.EventHandlerMouseWheel);
                }
            }

//            this.SaveState();

            return true;
        }
        
        return false;
    },
    
    GetEnabled: function()
    {
        return this.OuterDiv.ControlEnabled;
    },
    
    SetHoverEnabled: function(HoverEnabled)
    {
        if (HoverEnabled != this.OuterDiv.HoverEnabled)
        {
            this.OuterDiv.HoverEnabled = HoverEnabled;
            
            if (this.OuterDiv.HoverEnabled)
            {
                Event.observe(this.Window, 'mouseover', this.EventHandlerWindowOver);
                Event.observe(this.Window, 'mouseout', this.EventHandlerWindowOut);
            }
            else
            {
                Event.stopObserving(this.Window, 'mouseover', this.EventHandlerWindowOver);
                Event.stopObserving(this.Window, 'mouseout', this.EventHandlerWindowOut);
            }
            
            this.UpdateButtonStatus();
            
            this.UpdateAttributes();
            
//            this.SaveState();
            
            return true;
        }
        
        return false;
    },
    
    GetHoverEnabled: function()
    {
        return this.OuterDiv.HoverEnabled;
    },
    
    SetPanelType: function(PanelType)
    {
        PanelType = parseInt(PanelType);
        if (PanelType >= 0 && PanelType <= 6 && PanelType != this.OuterDiv.PanelType)
        {
            this.OuterDiv.PanelType = PanelType;
            
            //Enforce PanelTypes.
            switch (PanelType)
            {
                case 0:     //NoToggle
                    this.UpdateSelected(0);
                    break;
                case 1:     //SingleToggle
                    if (this.OuterDiv.SelectedButtons.length > 1)
                    {
                        this.UpdateSelected(1);
                    }
                    break;
                case 5:     //SingleRequiredToggle
                case 2:     //SingleForcedToggle
                    if (this.OuterDiv.SelectedButtons.length < 1)
                    {
                        this.OuterDiv.SelectedButtons.push(0);
                    }
                    this.UpdateSelected(1);
                    break;
                case 6:     //MultiRequiredToggle
                case 4:     //MultiForcedToggle
                    if (this.OuterDiv.SelectedButtons.length < 1)
                    {
                        this.OuterDiv.SelectedButtons.push(0);
                        this.UpdateSelected(1);
                    }
                    break;
            }
            
//            this.SaveState();
            
            return true;
        }
        
        return false;
    },
    
    GetPanelType: function()
    {
        return this.OuterDiv.PanelType;
    },
    
    
    //State Properties
    SetSelected: function(Selected)
    {
        var Index = 0;
        var CheckIndex = 0;
        var Found = false;
        var Button;
        
        //Enforce the panel type, assume all commands passed in Selected are valid.
        if (Selected.length <= 0 && (this.OuterDiv.PanelType == 2 || this.OuterDiv.PanelType == 4 || this.OuterDiv.PanelType == 5 || this.OuterDiv.PanelType == 6))
        {
            return false;
        }
        else if (Selected.length > 1 && (this.OuterDiv.PanelType == 1 || this.OuterDiv.PanelType == 2 || this.OuterDiv.PanelType == 5))
        {
            return false;
        }
        else if (this.OuterDiv.PanelType == 0 && Selected.length > 0)
        {
            return false;
        }
        
        this.OuterDiv.SelectedButtons.length = 0;

        if (parseInt(Selected.length) == 0 || parseInt(Selected.length) == NaN)
        {
            return true;
        }
        
        //Find the selected buttons.
        for (Index = 0; Index < this.Buttons.length; Index++)
        {
            Found = false;
            Button = this.Buttons[Index];
            CheckIndex = 0;
            
            while (!Found && CheckIndex < Selected.length)
            {
                if (Button.GetCommand().Equals(Selected[CheckIndex]))
                {
                    this.OuterDiv.SelectedButtons.push(Index);
                    Found = true;
                }
                
                CheckIndex++;
            }
            
            //Enforce the selected status
            this.Buttons[Index].SetSelected(Found);
        }
        
        return true;
    },
    
    GetSelected: function()
    {
        var Commands = new Array();
        var Index = 0;
        
        for (Index = 0; Index < this.OuterDiv.SelectedButtons.length; Index++)
        {
            Commands.push(this.Buttons[this.OuterDiv.SelectedButtons[Index]].GetCommand());
        }
        
        return Commands;
    },
    
    SetCurrentGroup: function(CurrentGroup)
    {
        if (parseInt(CurrentGroup) != NaN && CurrentGroup != this.OuterDiv.CurrentGroup)
        {
            this.OuterDiv.CurrentGroup = CurrentGroup;
            
            this.ScrollToGroup(CurrentGroup);
            
//            this.SaveState();
            
            return true;
        }
        
        return false;
    },
    
    GetCurrentGroup: function()
    {
        return this.OuterDiv.CurrentGroup;
    },
    
    

    //Read only properties
    GetScrollType: function()
    {
        return this.OuterDiv.ScrollType;
    },
    
    GetScrollInterval: function()
    {
        return this.OuterDiv.ScrollInterval;
    },
    
    GetRows: function()
    {
        return this.OuterDiv.RowCount;
    },
    
    GetCols: function()
    {
        return this.OuterDiv.ColCount;
    },
    
    
    
    
//Public Methods
    NumButtons: function()
    {
        return this.Buttons.length;
    },
    
    UpdateButton: function(Index, Text, ImageURL, Command, Enabled, HoverEnabled)
    {
        if (Index >= this.Buttons.length || Index < 0)
        {
            return false;
        }
        
        this.Buttons[Index].SetText(Text);
        this.Buttons[Index].SetImage(ImageURL);
        this.Buttons[Index].SetCommand(Command);
        this.Buttons[Index].SetEnabled(Enabled);
        this.Buttons[Index].SetHoverEnabled(HoverEnabled);
        
        return true;
    },
    
    UpdateButtonText: function(Index, Text)
    {
        if (Index >= this.Buttons.length || Index < 0)
        {
            return false;
        }

        this.Buttons[Index].SetText(Text);
        
        return true;
    },
    
    UpdateButtonImage: function(Index, ImageURL)
    {
        if (Index >= this.Buttons.length || Index < 0)
        {
            return false;
        }

        this.Buttons[Index].SetImage(ImageURL);
        
        return true;
    },
    
    UpdateButtonCommand: function(Index, Command)
    {
        if (Index >= this.Buttons.length || Index < 0)
        {
            return false;
        }
        
        this.Buttons[Index].SetCommand(Command);

        return true;
    },
    
    UpdateButtonEnabled: function(Index, Enabled)
    {
        if (Index >= this.Buttons.length || Index < 0)
        {
            return false;
        }
        
        this.Buttons[Index].SetEnabled(Enabled);

        return true;
    },
    
    UpdateButtonHoverEnabled: function(Index, HoverEnabled)
    {
        if (Index >= this.Buttons.length || Index < 0)
        {
            return false;
        }
        
        this.Buttons[Index].SetHoverEnabled(HoverEnabled);
        
        return true;
    },
    
    NumGroups: function()
    {
        return this.NumChildNodes(this.Buffer);
    },
    
    Fetch: function(Command, Next)
    {
        var Index = 0;
        var ButtonSettings;
        var Button;

        this.ToggleTransparency(true);
        
        ButtonSettings = Command(Next);
        
        if (ButtonSettings == null || ButtonSettings.length == null || this.Buttons.length != ButtonSettings.length || this.Buttons.length == 0)
        {
            return false;
        }
        
        for (Index = 0; Index < ButtonSettings.length; Index++)
        {
            Button = this.Buttons[Index];
            
            Button.SetEnabled(ButtonSettings[Index].GetEnabled());
            Button.SetHoverEnabled(ButtonSettings[Index].GetHoverEnabled());
            Button.SetSelected(ButtonSettings[Index].GetSelected());
            Button.SetImage(ButtonSettings[Index].GetImage());
            Button.SetText(ButtonSettings[Index].GetText());
            Button.SetCommand(ButtonSettings[Index].GetCommand());
            Button.SetCollapse(ButtonSettings[Index].GetCollapse());
        }

        //Enable Control
        this.ToggleTransparency(false);

        return true;
    },
    

//Event Handlers *************************    
    ClientClick: function(Command, HandledEvent)
    {
        this.ToggleTransparency(true);
        
        var Value;
        
        if (this.OuterDiv.OnEnabledClickInContext != null)
        {
            Value = this.OuterDiv.OnEnabledClickInContextPointer(HandledEvent);
        }
        else
        {
            Value = eval(this.OuterDiv.OnEnabledClick);
        }

        if (this.OuterDiv.SelectionFinished != null)
        {
            if (this.OuterDiv.PanelType != 0)
            {
                this.OuterDiv.SelectionFinished(this.GetSelected());
            }
            else
            {
                var temp = new Array();
                temp[0] = Command;
                this.OuterDiv.SelectionFinished(temp[0]);
            }
        }

        this.ToggleTransparency(false);

        return Value;
    },
    
    ClientChange: function(ButtonIndex)
    {
        var Index = 0;
        var Found = false;
        //Ensure the index is valid.
        if (ButtonIndex < 0 || ButtonIndex >= this.Buttons.length)
        {
            return false;
        }
    
        //Check if the change will be valid.
        switch (this.OuterDiv.PanelType)
        {
            case 0:     //NoToggle
                return false;
                break;
            case 1:     //SingleToggle
                if (!this.Buttons[ButtonIndex].GetSelected() && this.OuterDiv.SelectedButtons.length > 0)
                {
                    this.Buttons[this.OuterDiv.SelectedButtons[0]].SetSelected(false);
                    this.OuterDiv.SelectedButtons.length = 0;
                }
                break;
            case 5:     //SingleRequiredToggle
            case 2:     //SingleForcedToggle
                if (this.Buttons[ButtonIndex].GetSelected())
                {
                    if (this.OuterDiv.SelectedButtons.length > 0 && this.OuterDiv.SelectedButtons[0] == ButtonIndex)
                    {
                        // this is the only currently selected button.
                        // fail the change
                        return false;
                    }
                    else
                    {
                        // this is simply a button that is being swapped
                        // via ClientChange, approve the change.
                        return true;
                    }
                }
                
                if (this.OuterDiv.SelectedButtons.length > 0)
                {
                    Index = this.OuterDiv.SelectedButtons[0];
                    this.OuterDiv.SelectedButtons.length = 0;
                    this.Buttons[Index].SetSelected(false);
                }
                break;
            case 6:     //MultiRequiredToggle
            case 4:     //MultiForcedToggle
                if (this.Buttons[ButtonIndex].GetSelected() && this.OuterDiv.SelectedButtons.length == 1)
                {
                    return false;
                }
                break;
        }
        
        //Affect the change
        if (this.Buttons[ButtonIndex].GetSelected())
        {
            Index = 0;
            while (!Found && Index < this.OuterDiv.SelectedButtons.length)
            {
                if (this.OuterDiv.SelectedButtons[Index] == ButtonIndex)
                {
                    this.OuterDiv.SelectedButtons.splice(Index, 1);
                    Index--;
                    Found = true;
                }
                
                Index++;
            }
        }
        else
        {
            this.OuterDiv.SelectedButtons.push(ButtonIndex);
        }
        
        return true;
    },
    
    WindowOver: function()
    {
        this.IsMouseOver = true;
        
        this.UpdateAttributes();
    },
    
    WindowOut: function()
    {
        this.IsMouseOver = false;
        
        this.UpdateAttributes();
    },

    ScrollPrevious: function()
    {
        if (this.NumGroups() > 0)
        {
            var Distance = this.OuterDiv.ScrollDist * -1;
            
            if (this.OuterDiv.DisplayOrientation == 0)
            {
                this.Window.scrollLeft += Distance;
            }
            else
            {
                this.Window.scrollTop += Distance;
            }
            
            this.UpdateScrolling();
            this.UpdateCurrentGroup();
        }
    },
    
    ScrollNext: function()
    {
        if (this.NumGroups() > 0)
        {
            var Distance = this.OuterDiv.ScrollDist;
            
            if (this.OuterDiv.DisplayOrientation == 0)
            {
                this.Window.scrollLeft += Distance;
            }
            else
            {
                this.Window.scrollTop += Distance;
            }
            
            this.UpdateScrolling();
            this.UpdateCurrentGroup();
        }
    },
    
    MouseWheel: function(e)
    {
        //This code was taken from http://adomas.org/javascript-mouse-wheel/
                
        var delta = 0;
        if (!e) /* For IE. */
                e = window.event;
        if (e.wheelDelta) { /* IE/Opera. */
                delta = e.wheelDelta/120;
                /** In Opera 9, delta differs in sign as compared to IE.
                 */
                if (window.opera)
                        delta = -delta;
        } else if (e.detail) { /** Mozilla case. */
                /** In Mozilla, sign of delta is different than in IE.
                 * Also, delta is multiple of 3.
                 */
                delta = -e.detail/3;
        }
        /** If delta is nonzero, handle it.
         * Basically, delta is now positive if wheel was scrolled up,
         * and negative, if wheel was scrolled down.
         */
        if (delta)
                this.HandleWheel(delta);
        /** Prevent default actions caused by mouse wheel.
         * That might be ugly, but we handle scrolls somehow
         * anyway, so don't bother here..
         */
        if (e.preventDefault)
                e.preventDefault();
	    e.returnValue = false;
    },
    
    HandleWheel: function(Delta)
    {
        var Direction;
        var Index = 0;
        
        //Move the sign of delta into Direction.
        if (Delta > 0)
        {
            Direction = 1;
        }
        else
        {
            Direction = -1;
        }
        
        //Double the delta to make the scrolling a suitable speed.
        Delta *= Direction * 2;
        
        //Scroll for as many deltas as there were.
        for (Index = 0; Index < Delta; Index++)
        {
            if (Direction > 0)
            {
                this.ScrollPrevious();
            }
            else
            {
                this.ScrollNext();
            }
        }
    },




//Helper Functions **********************
    EndingButtons: function()
    {
        var CellIndex = 0;
        var Group;
        var Buttons = 0;
        var GroupCount = 0;
        var Index = 0;
        
        var Groups = new Array();
        
        GroupCount = this.NumGroups();
        
        if (GroupCount > 1)
        {
            Groups[0] = 0;
            Groups[1] = GroupCount - 1;
        }
        else if (GroupCount > 0)
        {
            Groups[0] = 0;
        }
        
        for (Index = 0; Index < Groups.length; Index++)
        {
            Buttons = 0;
            Group = this.ChildNodes(this.Buffer, Groups[Index]);
            
            for (CellIndex = 0; CellIndex < this.NumChildNodes(Group); CellIndex++)
            {
                if (this.ChildNodes(Group, CellIndex).getAttribute("className") != "EmptyCell")
                {
                    Buttons++;
                }
            }
            
            Groups[Index] = Buttons;
        }
        
        this.OuterDiv.EndingButtons = Groups;
    },

    ComputeShowing: function()
    {
        if (this.OuterDiv.SetShowing == null)
        {
            return false;
        }
        
        if (this.NumChildNodes(this.Buffer) <= 0 || this.NumButtons() <= 0)
        {
            this.OuterDiv.SetShowing(0, 0, 0)
            /*
            First(Default);
            this.OuterDiv.SetLast(Default);
            this.OuterDiv.SetTotal(Default);
            */
            
            return true;
        }
    
        //Declare Variables
        var OrientationIndex = 0;
        var Dimension = "";
    
        var BasePoint = 0;
        var PreviousPoint = 0;
        var NextPoint = 0;
        var CellPoint = 0;
        
        var GroupDimension = 0;
        var CellDimension = 0;
        
        var FirstGroupIndex = -1;
        var FirstCellIndex = -1;
        var Index = 0;
        var Row = 0;
        var Col = 0;
        var Group;
        var Cell;
        
        var Buttons = 0;
        var FirstViewable = 0;
        
        //Determine Orientation Information
        if (this.OuterDiv.DisplayOrientation == 0)
        {
            Dimension = "width";
            OrientationIndex = 0;
        }
        else
        {
            Dimension = "height";
            OrientationIndex = 1;
        }
        

        BasePoint = Position.cumulativeOffset(this.ChildNodes(this.ChildNodes(this.Buffer, 0), 0))[OrientationIndex];
        PreviousPoint = Position.realOffset(this.Window)[OrientationIndex];
        NextPoint = Position.realOffset(this.Window)[OrientationIndex] + eval("Element.getDimensions(this.Window)." + Dimension);
        GroupDimension = eval("Element.getDimensions(this.ChildNodes(this.Buffer, 0))." + Dimension);
        CellDimension = Math.round(eval("Element.getDimensions(this.ChildNodes(this.ChildNodes(this.Buffer, 0), 0))." + Dimension) / 2.0);
        
        if (GroupDimension == 0)
        {
            return false;
        }

        //Compute the likely groups.
        PreviousIndex = Math.floor(PreviousPoint / GroupDimension);
        if (PreviousIndex >= this.NumGroups())
        {
            PreviousIndex = this.NumGroups()-1;
        }
        else if (PreviousIndex < 0)
        {
            PreviousIndex = 0;
        }

        NextIndex = Math.floor(NextPoint / GroupDimension);
        if (NextIndex >= this.NumGroups())
        {
            NextIndex = this.NumGroups()-1;
        }
        else if (NextIndex < 0)
        {
            NextIndex = 0;
        }        

        
        //Now that we have the groups, we can loop through them and determine how many buttons are in each
        for (Index = PreviousIndex; Index <= NextIndex; Index++)
        {
            Group = this.ChildNodes(this.Buffer, Index);
            
            for (Row = 0; Row < this.GetRows(); Row++)
            {            
                Cell = this.ChildNodes(Group, this.GetCols() * Row);
                CellPoint = Position.cumulativeOffset(Cell)[OrientationIndex] - BasePoint + CellDimension;

                if (PreviousPoint <= CellPoint && CellPoint <= NextPoint)
                {
                    for (Col = 0; Col < this.GetCols(); Col++)
                    {
                        if (Col != 0)
                        {
                            Cell = this.ChildNodes(Group, Col + this.GetCols() * Row);
                        }
                        
                        if (Cell.getAttribute("className") != "EmptyCell")
                        {
                            if (FirstGroupIndex == -1)
                            {
                                FirstGroupIndex = Index;
                            }
                        
                            if (FirstCellIndex == -1)
                            {
                                FirstCellIndex = Col + this.GetCols() * Row;
                            }
                            
                            Buttons++;
                        }
                    }
                }
            }
        }
        
        
        //Determine the first viewable of the buttons.
        FirstViewable = FirstGroupIndex * this.GetCols() * this.GetRows() + FirstCellIndex;
        
        if (FirstGroupIndex != 0)
        {
            FirstViewable -= this.GetCols() * this.GetRows() - this.OuterDiv.EndingButtons[0];
        }
        
        this.OuterDiv.SetShowing(FirstViewable + 1, FirstViewable + Buttons, this.NumButtons());

        /*
        First(FirstViewable + 1);
        this.OuterDiv.SetLast(FirstViewable + Buttons);
        this.OuterDiv.SetTotal(this.NumButtons());
        */

        return true;
    },

    UpdateButtonStatus: function()
    {
        var Index = 0;
        
        //Update the status of the panel buttons.
        for (Index = 0; Index < this.Buttons.length; Index++)
        {
            this.Buttons[Index].SetToggleDisabled(!this.OuterDiv.ControlEnabled);
            this.Buttons[Index].SetToggleHoverDisabled(!this.OuterDiv.HoverEnabled);
        }
        
        if (this.OuterDiv.ScrollType != 0)
        {
            //Update the status of the previous/next buttons.
            this.Previous.SetEnabled(this.OuterDiv.ControlEnabled);
            this.Previous.SetHoverEnabled(this.OuterDiv.HoverEnabled);
            this.Next.SetEnabled(this.OuterDiv.ControlEnabled);
            this.Next.SetHoverEnabled(this.OuterDiv.HoverEnabled);
        }
    },
    
    UpdateSelected: function(Length)
    {
        var Index = 0;
        var CheckIndex = 0;
        var Found = false;
        var Button;
        
        //Update length
        this.OuterDiv.SelectedButtons.length = Length;
        
        //Update Buttons
        for (Index = 0; Index < this.Buttons.length; Index++)
        {
            Found = false;
            Button = this.Buttons[Index];
            CheckIndex = 0;
            
            while (!Found && CheckIndex < this.OuterDiv.SelectedButtons.length)
            {
                if (Index == this.OuterDiv.SelectedButtons[CheckIndex])
                {
                    Found = true;
                }
                
                CheckIndex++;
            }
            
            //Enforce the selected status
            //Enforce the panel type
            if (this.GetPanelType() == 0)
            {
                Button.SetButtonType(0);
            }
            else
            {
                Button.SetButtonType(1);
            }
            Button.SetSelected(Found);
        }
    },
    
    FindStartIndex: function()
    {
        var StartIndex = 0;
        if (this.NumGroups() > 0)
        {
            StartIndex = parseInt(this.ChildNodes(this.Buffer, 0).getAttribute("Index"));
        }
        
        return StartIndex;
    },
    
    GetDistToScroll: function()
    {
        if (this.Buttons == null || this.Buttons.length <= 0)
        {
            //There is no distance to scroll if there are no buttons.
            return 0;
        }
    
        var FixedPixelInterval = 30;
        var GroupDimension = 0;
        var IntervalDimension = 0;
        var Dimension = "";
        
        if (this.OuterDiv.ScrollType == 1)
        {
            return FixedPixelInterval;
        }

        if (this.OuterDiv.DisplayOrientation == 0)
        {
            Dimension = "width";
        }
        else
        {
            Dimension = "height";
        }        
        
        var GroupDimension = eval("Element.getDimensions(this.ChildNodes(this.Buffer, 0))." + Dimension);
        
        if (this.OuterDiv.DisplayOrientation == 0)
        {
            IntervalDimension = Math.round(GroupDimension * (this.OuterDiv.ScrollInterval / this.OuterDiv.ColCount));
        }
        else
        {
            IntervalDimension = Math.round(GroupDimension * (this.OuterDiv.ScrollInterval / this.OuterDiv.RowCount));
        }
        
        return IntervalDimension;
    },
    
    UpdateCurrentGroup: function()
    {
        var MidPoint = 0;
        var GroupDimension = 0;
        var OrientationIndex = 0;
        var Orientation = "";
        var Dimension = "";
        
        var GroupIndex = 0;
        var CurrentGroup = 0;
        
        //Figure out orientation & dimension of the current panel.
        if (this.OuterDiv.DisplayOrientation == 0)
        {
            OrientationIndex = 0;
            Orientation = "Left";
            Dimension = "width";
        }
        else
        {
            OrientationIndex = 1;
            Orientation = "Top";
            Dimension = "height";
        }
        
        //Find midpoint of the current window
        MidPoint = Position.realOffset(this.Window)[OrientationIndex] + Math.round(eval("Element.getDimensions(this.Window)." + Dimension) / 2);
        GroupDimension = eval("Element.getDimensions(this.ChildNodes(this.Buffer, 0))." + Dimension);
        
        //Compute the likely group.
        GroupIndex = Math.floor(MidPoint / GroupDimension);
        if (GroupIndex >= this.NumGroups())
        {
            GroupIndex = this.NumGroups-1;
        }
        else if (GroupIndex < 0)
        {
            GroupIndex = 0;
        }
        CurrentGroup = this.ChildNodes(this.Buffer, GroupIndex).getAttribute("Index");
        CurrentGroup = parseInt(CurrentGroup);
        
        this.ComputeShowing();
        
        this.OuterDiv.CurrentGroup = CurrentGroup;
        
//        this.SaveState();
    },
    
    ScrollToGroup: function(Group)
    {
        if (this.Buttons == null || this.Buttons.length <= 0)
        {
            return false;
        }
    
        var Index = Group - this.FindStartIndex();
        var GroupOffset = 0;
        

        if (this.OuterDiv.DisplayOrientation == 0)
        {
            OrientationIndex = 0;
        }
        else
        {
            OrientationIndex = 1;
        }

        GroupOffset = Position.cumulativeOffset(this.ChildNodes(this.Buffer, Index))[OrientationIndex];
        GroupOffset -= Position.cumulativeOffset(this.ChildNodes(this.Buffer, 0))[OrientationIndex];

        if (this.OuterDiv.DisplayOrientation == 0)
        {
            this.Window.scrollLeft = GroupOffset;
        }
        else
        {
            this.Window.scrollTop = GroupOffset;
        }

        this.UpdateScrolling();
        
        return true;
    },
    
    UpdateScrolling: function()
    {
        if (this.OuterDiv.ScrollType != 0 && this.OuterDiv.ScrollType != 3 && this.OuterDiv.ControlEnabled)
        {
            if (this.NumGroups() <= 0)
            {
                //Disable Previous button
                this.Previous.SetEnabled(false);
                
                //Disable Next button
                this.Next.SetEnabled(false);
            }
            else if (this.OuterDiv.DisplayOrientation == 0)
            {
                //Specify the status of the previous button
                if (this.Window.scrollLeft == 0)
                {
                    this.Previous.SetEnabled(false);
                }
                else
                {
                    this.Previous.SetEnabled(true);
                }

                //Specify the status of the next button
                if (this.Window.scrollLeft == (this.Window.scrollWidth - this.Window.offsetWidth))
                {
                    this.Next.SetEnabled(false);
                }
                else
                {
                    this.Next.SetEnabled(true);
                }
            }
            else
            {
                //Specify the status of the previous button
                if (this.Window.scrollTop == 0)
                {
                    this.Previous.SetEnabled(false);
                }
                else
                {
                    this.Previous.SetEnabled(true);
                }

                //Specify the status of the next button
                if (this.Window.scrollTop == (this.Window.scrollHeight - this.Window.offsetHeight))
                {
                    this.Next.SetEnabled(false);
                }
                else
                {
                    this.Next.SetEnabled(true);
                }
            }
        }
    },
    
    ToggleTransparency: function(Disable)
    {
        var Pos;
        var Dimensions;
        
        if (Disable)
        {
            Position.prepare();
            Pos = Position.page(this.OuterDiv);
            Dimensions = Element.getDimensions(this.OuterDiv);
            this.OuterDiv.TransparentStyle = "position: absolute; top: " + Pos[1] + "px; left: " + Pos[0] + "px; width: " + Dimensions.width + "px; height: " + Dimensions.height + "px; z-index: 500;"

            this.Transparent.style.cssText = this.OuterDiv.TransparentStyle + "display: block; visibility: visible";
        }
        else
        {
            this.Transparent.style.cssText = this.OuterDiv.TransparentStyle + "display: none; visibility: hidden";
        }
    },
    
//Display Helper Functions**********************
    UpdateAttributes: function()
    {
        //Clear classes/styles
        this.OuterDiv.className = "";
        this.Window.className = "";

    
        if (this.OuterDiv.ControlEnabled)
        {
            this.OuterDiv.className = this.OuterDiv.CssClassDefault + " " + this.OuterDiv.CssClassDefault + "_Enabled";

            if (this.OuterDiv.HoverEnabled)
            {
                if (this.IsMouseOver)
                {
                    this.Window.className = "Window Window_HoverOver";
                }
                else
                {
                    this.Window.className = "Window Window_HoverOut";
                }
            }
            else
            {
                this.Window.className = "Window";
            }
        }
        else
        {
            this.OuterDiv.className = this.OuterDiv.CssClassDefault + " " + this.OuterDiv.CssClassDefault + "_Disabled";
            this.Window.className = "Window";
        }
    },



//Setup Helper Functions**************
    ParseInitialValues: function()
    {
        //Fix for FireFox
        //  Firefox does not permit custom attributes to be accessed as follows:
        //      element.CustomAttribute
        //  Instead you have to do element.getAttribute("CustomAttribute")
        //  Instead of performing this and changing all of the javascript code
        //  we will parse all custom attributes initially and reassign them to 
        //  there element.CustomAttribute counterparts.
        
        //Parse Properties
        this.OuterDiv.PanelType = this.OuterDiv.getAttribute("PanelType");
        this.OuterDiv.ControlEnabled = this.OuterDiv.getAttribute("ControlEnabled");
        this.OuterDiv.HoverEnabled = this.OuterDiv.getAttribute("HoverEnabled");
        this.OuterDiv.SelectedButtons = this.OuterDiv.getAttribute("SelectedButtons");
        this.Buttons = this.OuterDiv.getAttribute("Buttons");
        this.OuterDiv.CurrentGroup = this.OuterDiv.getAttribute("CurrentGroup");
        this.OuterDiv.OnEnabledClick = this.OuterDiv.getAttribute("OnEnabledClick");
        this.OuterDiv.DisplayOrientation = this.OuterDiv.getAttribute("DisplayOrientation");

        //Parse Read Only Properties
        this.OuterDiv.ScrollType = this.OuterDiv.getAttribute("ScrollType");
        this.OuterDiv.ScrollInterval = this.OuterDiv.getAttribute("ScrollInterval");
        this.OuterDiv.RowCount = this.OuterDiv.getAttribute("RowCount");
        this.OuterDiv.ColCount = this.OuterDiv.getAttribute("ColCount");
        
        //Parse CSS settings
        this.OuterDiv.CssClassDefault = this.OuterDiv.getAttribute("CssClassDefault");

        //Parse Structure Attributes
        this.OuterDiv.StructureIDs = this.OuterDiv.getAttribute("StructureIDs");
        
        //Convert VB Boolean Values
        this.OuterDiv.ControlEnabled = this.ConvertToBoolean(this.OuterDiv.ControlEnabled);
        this.OuterDiv.HoverEnabled = this.ConvertToBoolean(this.OuterDiv.HoverEnabled);
        this.OuterDiv.UseStartupScript = this.ConvertToBoolean(this.OuterDiv.getAttribute("UseStartupScript"));
        
        //Convert VB Integer Values
        this.OuterDiv.PanelType = parseInt(this.OuterDiv.PanelType);
        this.OuterDiv.CurrentGroup = parseInt(this.OuterDiv.CurrentGroup);
        this.OuterDiv.ScrollType = parseInt(this.OuterDiv.ScrollType);
        this.OuterDiv.ScrollInterval = parseInt(this.OuterDiv.ScrollInterval);
        this.OuterDiv.RowCount = parseInt(this.OuterDiv.RowCount);
        this.OuterDiv.ColCount = parseInt(this.OuterDiv.ColCount);
        this.OuterDiv.DisplayOrientation = parseInt(this.OuterDiv.DisplayOrientation);

        //Convert delimited strings to arrays.
        this.OuterDiv.SelectedButtons = this.ConvertToArray(this.OuterDiv.SelectedButtons, "|");
        this.Buttons = this.ConvertToArray(this.Buttons, "|");
        this.OuterDiv.StructureIDs = this.ConvertToArray(this.OuterDiv.StructureIDs, "|");

        return true;
    },
    
    ReferenceStructure: function()
    {
        var NextID = "";
        var PreviousID = "";
        
        this.Transparent = $(this.OuterDiv.StructureIDs[0]);
        this.DataField = $(this.OuterDiv.StructureIDs[1]);
        this.Window = $(this.OuterDiv.StructureIDs[2]);
        this.Buffer = this.ChildNodes(this.Window, 0);
        
        if (this.OuterDiv.StructureIDs[3].length > 0)
        {
            PreviousID = this.OuterDiv.StructureIDs[3];
            NextID = this.OuterDiv.StructureIDs[4];
            
            this.Previous = this.CreateGraphicButton(PreviousID, 1, 0);
            this.Next = this.CreateGraphicButton(NextID, 2, 0);
        }
    },
    
    ConvertToBoolean: function(Value)
    {
        if (Value == "True")
        {
            return true;
        }
        
        return false;
    },
    
    ConvertToArray: function(Value, Delimiter)
    {
        if (Value != null && Value.length > 0)
        {
            return Value.split(Delimiter);
        }
        else
        {
            return new Array();
        }
    },
    
    ChildNodes: function(Object, Index)
    {
        var Pos = 0;
        var RealPos = -1;
        
        for (Pos = 0; Pos < Object.childNodes.length; Pos++)
        {
            if (Object.childNodes.item(Pos).nodeType != 3)
            {
                RealPos++;
            }
            
            if (RealPos == Index)
            {
                return Object.childNodes.item(Pos);
            }
        }
        
        return null;
    },
    
    NumChildNodes: function(Object)
    {
        var Pos = 0;
        var RealPos = 0;
        
        for (Pos = 0; Pos < Object.childNodes.length; Pos++)
        {
            if (Object.childNodes.item(Pos).nodeType != 3)
            {
                RealPos++;
            }
        }
        
        return RealPos;
    }
};