var goExpanderManager = new cExpanderManager();

/*
 * class to manage top level expander state between page
 * loads
 */
function cExpanderManager()
{
    this.expanders = new Array();
    this.formElement = null;
    
    this.add = cExpanderManager_Add;
    this.initialize = cExpanderManager_Initialize;
    this.registerOpen = cExpanderManager_RegisterOpen;
    this.registerClose = cExpanderManager_RegisterClose;
    this.isVisible = function() { return true; }
    this.isElementVisible = cExpanderManager_IsElementVisible;
}

function cExpanderManager_Add( oExpander )
{
    this.expanders[this.expanders.length] = oExpander;
    oExpander.manager = this;
}

function cExpanderManager_Initialize()
{
    if (this.formElement == null)
        return;
        
    for(var i=0; i < this.expanders.length; i++)
    {
        this.expanders[i].initialize( this.isElementVisible( this.expanders[i].element.id ) );
    }
}

function cExpanderManager_RegisterOpen( oExpander )
{
    if (this.formElement == null)
        return;

    if (this.formElement.value.indexOf( oExpander.element.id ) < 0 )
    {
        if (this.formElement.value != '')
            this.formElement.value += ",";
        this.formElement.value += oExpander.element.id;
    }  
}

function cExpanderManager_RegisterClose( oExpander )
{
    if (this.formElement == null)
        return;

    var rx = new RegExp( oExpander.element.id, '' );
    var text = this.formElement.value;
    text = text.replace( rx, '' );
    text = text.replace( /,,/g, ',' );
    if (text.substr(0, 1) == ',')
        text = text.slice( 1 );
    if (text.substr(-1) == ',')
        text = text.slice( 0, -1);
    this.formElement.value = text;
}

function cExpanderManager_IsElementVisible( id )
{
    rx = new RegExp( id, '' );
    return rx.test( this.formElement.value );
}

/*
 * basic expander class to handle an expandable element
 * that expands or contracts child elements.
 */
function cExpander( elm )
{
    this.element = elm;
    this.element.expander = this;
    this.children = new Array();
    this.bIsOpen = false;
    this.manager = null; 
    
    this.addElement = cExpander_AddElement;
    this.open = cExpander_Open;
    this.close = cExpander_Close;
    this.expand = cExpander_Expand;
    this.contract = cExpander_Contract;
    this.toggle = cExpander_Toggle;
    this.initialize = cExpander_Initialize;
    this.registerOpen = cExpander_RegisterOpen;
    this.registerClose = cExpander_RegisterClose;
    this.isVisible = cExpander_IsVisible;
}

function cExpander_AddElement( elm )
{
    this.children[this.children.length] = elm;
    elm.manager = this;
}

function cExpander_Open()
{
    for( var i=0; i<this.children.length; i++)
    {
        this.children[i].element.style.display = 'block';
        if (this.children[i].bIsOpen)
        {
            this.children[i].open();
        }
    }
}

function cExpander_Close()
{
    for( var i=0; i<this.children.length; i++)
    {
        this.children[i].element.style.display = 'none';
        this.children[i].close();
    }
}

function cExpander_Expand()
{
    this.bIsOpen = true;
    this.registerOpen( this );
}

function cExpander_Contract()
{
    this.bIsOpen = false;
    this.registerClose( this );
}

function cExpander_Toggle()
{
    if (this.bIsOpen)
        this.contract();
    else
        this.expand();
}

/* intialize this and all children recursively */
function cExpander_Initialize( bState )
{
    this.bIsOpen = bState;
    for( var i=0; i<this.children.length; i++)
    {
        var child = this.children[i];
        if (this.isVisible())
            child.element.style.display = 'block';
        this.children[i].initialize( goExpanderManager.isElementVisible( child.element.id ));
    }
}

/* cascade registration to top level manager */
function cExpander_RegisterOpen(elm)
{
    if (this.manager != null)
        this.manager.registerOpen( elm );
    this.open();
}

function cExpander_RegisterClose(elm)
{
    if (this.manager != null)
        this.manager.registerClose( elm );
    this.close();
}

/* determine if all elements in heirarchy are also open */
function cExpander_IsVisible()
{
    var bVisible = this.bIsOpen;
    if (this.manager != null)
        bVisible = bVisible && this.manager.isVisible();
    return bVisible;
}