// (C) 2002 SRC, LLC  -   All rights reserved
//  Module: SRCTREE.JS
//  Author: Rob Bryan


/*

var SampleTree =
{
    name: "ReportTree",
    height: 400,
    width: 500,
    getDataUrl: "AllocateOnline.srct?ShowPage=pages/VarTreeGetInfo.htm",
    multipleSelect : true,
    imgRoot : "images/treecontrol/"

    initialSelection : 'a','b','c'
    selectionDelimiter : "," // default is a comma

    aNodesByKey : null,
    aRootNodeKeys : null,
    showStatusBar : true,
    statusHeight : 20,
    statusBarSelectionDescription : "Report",
    statusBarSelectionDescriptionPlural : "Reports",
    statusBarMaxSelection : nMaxReportCount

    ///////////////////
    sSelectedKey
};

var SampleNode =
{
    namePrefix: null,
    name: "foo",
    nameSuffix: "bar",
    value: "baz",
    key: "0154",
    selectable : true,
    selected: false,
    expandable: true,
    expanded: false,
    parentKey : "01"
    containedLeafCount: 3

//
  tree
  partSelected
  aChildKeys
  initialSelection
  bChildrenFromServer

};
*/
//Public: /////////////////////
var SrcTree_Image_Width = "17";
var SrcTree_Image_Height = "20";


var SrcTree_Image_BlankSpacer = "blankspacer.gif";
var SrcTree_Image_FullSpacer = "spacer.gif";

var SrcTree_Image_NoExpand = "noexpand.gif";
var SrcTree_Image_Expand = "plus.gif";
var SrcTree_Image_Unexpand = "minus.gif";
var SrcTree_Image_NoExpand_Bottom = "bottom_noexpand.gif";
var SrcTree_Image_Expand_Bottom = "bottom_plus.gif";
var SrcTree_Image_Unexpand_Bottom = "bottom_minus.gif";

var SrcTree_Image_Multiple_Selected = "checked.gif";
var SrcTree_Image_Multiple_Unselected = "unchecked.gif";
var SrcTree_Image_Multiple_PartSelected = "greychecked.gif";
var SrcTree_Image_Single_Selected = "radiochecked.gif";
var SrcTree_Image_Single_Unselected = "radiounchecked.gif";

var SrcTree_RunCallback =true;


function SrcTree_Create(oConfig,oSpan)
{
    /*
        We have problems putting the tree code into Firefox, which requires
        different code from IE.
    */
    if(oConfig.selectionDelimiter == null)
        oConfig.selectionDelimiter = ","; // Default selection delimiter is a comma
    if(oConfig.initialSelectionKey != null && oConfig.initialSelectionKey == "")
        oConfig.initialSelectionKey = null;

    gaTreesByName[oConfig.name] = oConfig;

    var sTreeFrameName ="SrcTree_" + oConfig.name;
    var sTreeFrameHtml = '<iframe name="' + sTreeFrameName +'" id="' +sTreeFrameName +'" src=""'+
        ' height="' + oConfig.height + '" width="' + oConfig.width +'"' +
        ' MARGINWIDTH="0" MARGINHEIGHT="0" BORDER="1" SPACING="0" FRAMEBORDER="1" FRAMESPACING="0" noscroll></iframe>';
    var bHasFrames      =(document.frames!=null);

    if (bHasFrames)
    {
        sTreeFrameHtml =sTreeFrameHtml.replace(/src=""/, 'src="javascript: parent.SrcTree_CreateInternal(\''+oConfig.name+'\');"');
    }

    if (arguments.length < 2)
    {
        document.write(sTreeFrameHtml);
    }
    else
    {
        oSpan.innerHTML = sTreeFrameHtml;
    }

    if (!bHasFrames)
    {
        var sText =SrcTree_CreateInternal (oConfig.name); //alert (sText);
        var oDoc =document.getElementById (sTreeFrameName).contentWindow.document;

        oDoc.open();
        oDoc.write(sText);
        oDoc.close();
    }


    if (oConfig.showStatusBar)
    {
        var sStatusFrameName ="SrcTree_" +oConfig.name +"_Status";
        var sStatusFrameHtml = '<br><iframe name="' +sStatusFrameName +'" id="' +sStatusFrameName +'" src=""'+
        ' height="' + oConfig.statusHeight + '" width="' + oConfig.width +'"' +
        ' MARGINWIDTH="0" MARGINHEIGHT="0" BORDER="1" SPACING="0" FRAMEBORDER="1" FRAMESPACING="0" noscroll></iframe>';

        if (bHasFrames)
        {
            sStatusFrameHtml =sStatusFrameHtml.replace(/src=""/, 'src="javascript: parent.SrcTree_CreateStatusInternal(\''+oConfig.name+'\');"');
        }

        if (arguments.length < 2)
            document.write(sStatusFrameHtml);
        else
            oSpan.innerHTML += sStatusFrameHtml;

        if (!bHasFrames)
        {
            var sText =SrcTree_CreateStatusInternal (oConfig.name); //alert (sText);
            var oDoc =document.getElementById (sStatusFrameName).contentWindow.document;

            oDoc.open();
            oDoc.write(sText);
            oDoc.close();
        }
    }
}

function SrcTree_AddNodes(sTreeName,aNodes)
{
    var oTree = gaTreesByName[sTreeName];
    for (var x = 0 ; x<aNodes.length; x++)
    {
        if (aNodes[x] == null)
            continue;

        // Make a copy of the current node to avoid strange awful bugs!
        var oNode = new Object();
        oNode.namePrefix = aNodes[x].namePrefix;
        oNode.name = aNodes[x].name;
        oNode.nameSuffix = aNodes[x].nameSuffix;
        oNode.value = aNodes[x].value;
        oNode.key = aNodes[x].key;
        oNode.selectable = aNodes[x].selectable;
        oNode.expandable = aNodes[x].expandable;
        oNode.selected = aNodes[x].selected;
        oNode.expanded = aNodes[x].expanded;
        oNode.parentKey = aNodes[x].parentKey;
        oNode.containedLeafCount = aNodes[x].containedLeafCount;
        oNode.initialSelection = aNodes[x].initialSelection;
        oNode.bChildrenFromServer = aNodes[x].bChildrenFromServer;


        // If single selection tree, don't allow non-leaf nodes to be selected.
        if (!oTree.multipleSelect && oNode.expandable)
        {
            oNode.selectable = false;
            oNode.selected = false;
        }


        oNode.tree = oTree;
        oNode.aChildKeys = null;

        if (oNode.initialSelection == "")
            oNode.initialSelection = null;
        if (oNode.initialSelection)
        {
            if (oNode.initialSelection.split(oTree.selectionDelimiter).length == oNode.containedLeafCount)
            {
                oNode.partSelected = false;
                oNode.selected = true;
            }
            else
            {
                oNode.partSelected = true;
                oNode.selected= false;

            }
        }
        else
        {
            oNode.partSelected = false;
        }

        oTree.aNodesByKey[aNodes[x].key] = oNode;

        if (oNode.parentKey == null || oNode.parentKey == "")
        {
            oTree.aRootNodeKeys[oTree.aRootNodeKeys.length] = oNode.key;
        }
        else
        {
            oParentNode = oTree.aNodesByKey[oNode.parentKey];
            if (oParentNode.aChildKeys == null)
            {
                oParentNode.aChildKeys = new Array();
            }
            oParentNode.aChildKeys[oParentNode.aChildKeys.length] = oNode.key;
            oParentNode.expandable = true;
            oNode.selected = oParentNode.selected || oNode.selected;

            // Update parent's leaf count.
            if (oParentNode.bChildrenFromServer==null)
            {
                if(oNode.expandable)
                    oParentNode.containedLeafCount += oNode.containedLeafCount;
                else
                    oParentNode.containedLeafCount += 1;
            }
            else
            {
                oParentNode.containedLeafCount = SrcTree_CountChildLeaves(oParentNode);
            }
        }
    }
    SrcTree_Render(oTree);
}



function SrcTree_GetSelectionArrayBranch(oNode, sFieldType, aRet)
{

    if (oNode.selected)
    {
        if (sFieldType == 'key')
            aRet[aRet.length] = oNode.key;
        else if (sFieldType == 'value')
            aRet[aRet.length] = oNode.value;
        else
            alert('Illegal sFieldType passed to SrcTree::SrcTree_GetSelectionArrayBranch(): ' + sFieldType);
    }
    else if (oNode.partSelected || !oNode.selectable)
    {
        if (oNode.aChildKeys == null)
        {
            if(oNode.initialSelection != null)
            {
                var aSel =  oNode.initialSelection.split(',');
                for (var i = 0; i < aSel.length; aSel++)
                    aRet[aRet.length] =aSel[i];
            }
        }
        else
        {
            var numChildren =  oNode.aChildKeys.length;

            for (var y = 0; y < numChildren; y++)
            {
                SrcTree_GetSelectionArrayBranch(oNode.tree.aNodesByKey[oNode.aChildKeys[y]], sFieldType, aRet);
            }
        }

    }
}

// ******************************
// Parameters (2):
//   oTree - The Tree control object
//   sFieldType - (optional) 'key' to return the key field, 'value' to return the value field.
//
function SrcTree_GetSelectionArray(oTree)
{

    var aRet = new Array();
    var sFieldType = "key"; // Default to 'key'
    var sDelimiter = ',';   // Default delimiter is a comma

    // Optional second parameter is the node field type to return.  Either 'key' or 'value'
    if (arguments.length >= 2 )
    {
        sFieldType = arguments[1];
    }



    if (oTree.multipleSelect)
    {
        for (var x = 0; x < oTree.aRootNodeKeys.length  ; x++)
        {
            SrcTree_GetSelectionBranch(oTree.aNodesByKey[oTree.aRootNodeKeys[x]], sFieldType, aRet);

        }
    }
    else if (oTree.sSelectedKey!=null) // Single select tree
    {
        var oNode = oTree.aNodesByKey[oTree.sSelectedKey];
        if (sFieldType=='key')
            aRet[0] = oNode.key;
        else
            aRet[0] = oNode.value;
    }
    return aRet;
}




function SrcTree_GetSelectionBranch(oNode, sFieldType, sDelimiter)
{
    var sRet = "";
    if (oNode.selected)
    {
        if (sFieldType == 'key')
            sRet = oNode.key;
        else if (sFieldType == 'value')
            sRet = oNode.value;
        else if (sFieldType == 'name')
            sRet = oNode.name;
        else
            alert('Illegal sFieldType passed to SrcTree::SrcTree_GetSelectionBranch(): ' + sFieldType);
    }
    else if (oNode.partSelected || !oNode.selectable)
    {
        if (oNode.aChildKeys == null)
        {
            if(oNode.initialSelection != null)
            {
                sRet += oNode.initialSelection;
            }
        }
        else
        {
            var numChildren =  oNode.aChildKeys.length;

            for (var y = 0; y < numChildren; y++)
            {
                var sNodeRet = SrcTree_GetSelectionBranch(oNode.tree.aNodesByKey[oNode.aChildKeys[y]], sFieldType, sDelimiter);
                if (sNodeRet.length > 0)
                {
                    if (sRet.length >0)
                        sRet += sDelimiter;
                    sRet += sNodeRet;
                }
            }
        }

    }
    return sRet;
}

// ******************************
// Parameters (3):
//   oTree - The Tree control object
//   sFieldType - (optional) 'key' to return the key field, 'value' to return the value field, 'name' to return the name field, "namepath" to return the full tree name.
//   sDelimiter - (optional) delimiter to separate the selections.  Default is a comma ','.
//
function SrcTree_GetSelection(oTree)
{

    var sRet = "";
    var sFieldType = "key"; // Default to 'key'
    var sDelimiter = ',';   // Default delimiter is a comma

    // Optional second parameter is the node field type to return.  Either 'key' or 'value'
    if (arguments.length >= 2 )
    {
        sFieldType = arguments[1];
    }

    // Optional third parameter is the delimiter to separate values with.
    if (arguments.length >= 3 )
    {
        sDelimiter = arguments[2];
    }

    if (oTree.multipleSelect)
    {
        for (var x = 0; x < oTree.aRootNodeKeys.length  ; x++)
        {
            var sNodeRet = SrcTree_GetSelectionBranch(oTree.aNodesByKey[oTree.aRootNodeKeys[x]], sFieldType, sDelimiter);
            if (sNodeRet.length > 0)
            {
                if (sRet.length >0)
                    sRet += sDelimiter;
                sRet += sNodeRet;
            }
        }
    }
    else if (oTree.sSelectedKey!=null) // Single select tree
    {
        var oNode = oTree.aNodesByKey[oTree.sSelectedKey];
        if (sFieldType=='key')
            sRet += oNode.key;
        else if (sFieldType=='name')
            sRet += oNode.name;
        else if (sFieldType=='namepath')
        {
            sRet =oNode.name;
            var parent =oTree.aNodesByKey [oNode.parentKey];
            while (parent !=null)
            {
                sRet =parent.name +" " +sRet;
                parent =oTree.aNodesByKey [parent.parentKey];
            }
        }
        else
            sRet += oNode.value;
    }
    return sRet;
}

function SrcTree_SelectAll(sTreeName, toggle)
{
    var oTree = gaTreesByName[sTreeName];
    var numRoots = oTree.aRootNodeKeys.length;
    for (var x = 0; x < numRoots; x++)
    {
        var oRootNode = oTree.aNodesByKey[oTree.aRootNodeKeys[x]]

        if(toggle == 'selectall') {
            if (oRootNode.partSelected)
                SrcTree_ToggleSelection(sTreeName,oTree.aRootNodeKeys[x]);
            if (!oRootNode.selected)
                SrcTree_ToggleSelection(sTreeName,oTree.aRootNodeKeys[x]);
        }
        else if(toggle == 'unselectall') {
            if (oRootNode.selected || oRootNode.partSelected) {
                SrcTree_ToggleSelection(sTreeName,oTree.aRootNodeKeys[x]);
            }
        }
    }
}

//TODO: handle adding newly created node?!?!
function SrcTree_ChangeNode()
{
}

function SrcTree_RemoveNode(sTreeName,sNodeKey)
{
    var oTree = gaTreesByName[sTreeName];
    if (oTree == undefined)
    {
        alert('Error: SrcTree::SrcTree_RemoveNode passed invalid Tree Name: ' + sTreeName);
        return;
    }

    var oNode = oTree.aNodesByKey[sNodeKey];
    if (oNode == undefined)
    {
        alert('Error: SrcTree::SrcTree_RemoveNode passed invalid Node Key: ' + sNodeKey);
        return;
    }

    // If this node has children that is an error.
    if (oNode.aChildKeys != null)
    {
        alert('Error: SrcTree::SrcTree_RemoveNode was passed a Node with children: ' + sNodeKey);
        return;
    }

    if (oNode.selected || oNode.partSelected)
    {
        oNode.selected = false;
        oNode.partSelected = false;
        SrcTree_PropagateSelectionChangeUp(oNode);
    }

    oTree.aNodesByKey[sNodeKey] = null; // Tantamount to removing the node from the array.

    SrcTree_RemoveItemFromArray(oTree.aRootNodeKeys, sNodeKey);

    if ((oNode.parentKey != null) && (oNode.parentKey != ''))
    {
        // Remove the node's key from its parent's aChildKeys list
        var oParentNode = oTree.aNodesByKey[oNode.parentKey];
        SrcTree_RemoveItemFromArray(oParentNode.aChildKeys, sNodeKey);

        if (oParentNode.aChildKeys.length == 0)
        {
            oParentNode.selected = false;
            oParentNode.partSelected = false;
            SrcTree_PropagateSelectionChangeUp(oParentNode);
        }

        if (oNode.expandable)
            oParentNode.containedLeafCount -= oNode.containedLeafCount;
        else
            oParentNode.containedLeafCount -= 1;
    }


    SrcTree_Render(oTree);
}

//Private: /////////////////////

var gaTreesByName = new Array();

function SrcTree_CountChildLeaves(oNode)
{
    if(oNode.aChildKeys == null)
        return 0;

    var leafCount = 0;
    var oTree = oNode.tree;
    for (var i=0; i<oNode.aChildKeys.length; i++)
    {
        var oCurrentNode = oTree.aNodesByKey[oNode.aChildKeys[i]];
        if (oCurrentNode.expandable == true)
            leafCount += oCurrentNode.containedLeafCount;
        else
            leafCount += 1;
    }

    return leafCount;
}

function SrcTree_RemoveItemFromArray(aTheArray, oTheItem)
{
    var bFoundIt = false;
    for (var i=0; i<aTheArray.length; i++)
    {
        if (aTheArray[i] == oTheItem)
            bFoundIt = true;

        if (bFoundIt && (i<aTheArray.length-1))
            aTheArray[i] = aTheArray[i+1];
    }
    if (bFoundIt)
        aTheArray.length = aTheArray.length-1;
}


function SrcTree_CreateInternal(sName)
{
    var oConfig = gaTreesByName[sName];
    var ret = '<html>';
    ret += '<body onLoad="parent.SrcTree_InitialSetup(\''+ sName +'\')" leftmargin="0" topmargin="0"><link REL="stylesheet" HREF="styles/style.css" TYPE="text/css">';
    ret += '<script><!-- \n function AddNodes(aNodes) \n { \n parent.SrcTree_AddNodes("' + sName + '",aNodes); \n } \n //--> \n </script>'
    ret += '<span ID="RenderSpan"></span>';
    ret += '<span style="position:absolute; visibility:hidden; display:none" height="1" width="1"><iframe name="DataLink" id="DataLink" height="1" width="1" src=""></iframe></span>';
//  ret += '<span style="position:absolute; visibility:visible; display:block" height="100" width="500"><iframe name="DataLink" height="500" width="500" src=""></iframe></span>';
    ret += '</body></html>';
    return ret;
}

function SrcTree_CreateStatusInternal(sName)
{
    var oConfig = gaTreesByName[sName];
    var ret = '<html>';
    ret += '<body onLoad="parent.SrcTree_StatusInitialSetup(\''+ sName +'\')" leftmargin="0" topmargin="0" bgcolor="#C0C0C0"><link REL="stylesheet" HREF="styles/style.css" TYPE="text/css">';
    ret += '<span ID="StatusSpan"></span>';
    ret += '</body></html>';
    return ret;
}

function SrcTree_StatusInitialSetup(sName)
{
    var oTree = gaTreesByName[sName];
    oTree.statusSpan = frames["SrcTree_"+sName+"_Status" ].document.getElementById("StatusSpan");
    var nInitialSelCount = 0;
    if (oTree.initialSelection == "")
        oTree.initialSelection = null;
    if (oTree.initialSelection != null)
    {
        if (oTree.initialSelection.charAt(oTree.initialSelection.length-1) == oTree.selectionDelimiter)
        {
            oTree.initialSelection = oTree.initialSelection.substr(0,oTree.initialSelection.length-1);
        }
        nInitialSelCount = oTree.initialSelection.split(oTree.selectionDelimiter).length;
    }
    SrcTree_ShowStatus(oTree, nInitialSelCount);

}

function SrcTree_ShowStatus(oTree, nCount)
{
    var sStatus = "";
    if (oTree.multipleSelect)
    {
        sStatus = nCount;
        sStatus += " ";
        sStatus += nCount == 1 ? oTree.statusBarSelectionDescription : oTree.statusBarSelectionDescriptionPlural;
        sStatus += " selected";
        if (oTree.statusBarMaxSelection > 0)
        {
            var sMaxMsg = " (Max ";
            sMaxMsg += oTree.statusBarMaxSelection;
            sMaxMsg += ")";
            if (nCount > oTree.statusBarMaxSelection)
            {
                sMaxMsg = '<b>' + sMaxMsg + '</b>';
                sStatus = '<font color="red">' + sStatus + sMaxMsg + '</font>';
            }
            else
            {
                sStatus += sMaxMsg;
            }
        }
    }
    else // Single Select Tree
    {
        if (oTree.sSelectedKey!=null)
        {
            var oNode = oTree.aNodesByKey[oTree.sSelectedKey];
            sStatus = "Selection: " + SrcTree_GetSelectionString(oNode);
        }
        else
        {
            sStatus = "Selection: None";
        }
    }
    if (oTree.statusSpan)
        oTree.statusSpan.innerHTML = sStatus;
}

function SrcTree_GetSelectionString(oNode)
{
    var oTree = oNode.tree;
    var sSelection = oNode.name; //oNode.name;
    while (oNode.parentKey != "")
    {
        oNode=oTree.aNodesByKey[oNode.parentKey];
        sSelection = oNode.name + ": " + sSelection;
    }
    return sSelection;
}

function SrcTree_InitialSetup(sName)
{
    var oTree = gaTreesByName[sName];
    oTree.winRef = frames["SrcTree_"+sName ];
    oTree.renderSpan = oTree.winRef.document.getElementById("RenderSpan");

    //  Is this IE, or Firefox?
    if (oTree.winRef.document.frames)
        oTree.dataFrame =oTree.winRef.document.frames["DataLink"];
    else
        oTree.dataFrame =oTree.winRef.document.getElementById ("DataLink").contentWindow;

    if (oTree.aRootNodeKeys == null)
    {
        oTree.aRootNodeKeys = new Array();
        oTree.aNodesByKey = new Array();
        if (oTree.getDataUrl !=null)
        {
            var sTarget = oTree.getDataUrl;
            sTarget += "&TreeName=";
            sTarget += sName;
            sTarget += "&ParentKey=";

            if (oTree.initialSelectionKey != null)
            {
                sTarget += "&InitialSelectionKey=";
                sTarget += oTree.initialSelectionKey;
            }
            else if (oTree.initialSelection != null)
            {
                sTarget += "&InitialSelection=";
                sTarget += oTree.initialSelection;
            }
            oTree.initialSelection = null;

            oTree.dataFrame.document.location.replace(sTarget);
        }
    }
    else
    {
        SrcTree_Render(oTree);
    }
}

function SrcTree_Render(oTree)
{

    var nScrollPosition = getPageScrollY(oTree.winRef);

    var sRenderHtml = "";

    for (var x = 0; x < oTree.aRootNodeKeys.length  ; x++)
    {
        sRenderHtml += SrcTree_RenderBranch(oTree.aNodesByKey[oTree.aRootNodeKeys[x]], "",x ==oTree.aRootNodeKeys.length-1);
    }

    oTree.renderSpan.innerHTML = sRenderHtml;

    if(oTree.initialized)
        setTimeout('ScrollTreeToInitialSelection("' +oTree.name +'")', 1);
    else
        setTimeout('UpdateScroll(gaTreesByName["'+ oTree.name + '"].winRef,' + nScrollPosition +')',1);
}


function SrcTree_RenderBranch(oNode,sSpacerPattern,bLastSibling)
{
    var ret = "";
    var eKey =oNode.key.replace("'", "\\'");    //  Handle apostrophes in user names.

    ret += '<NOBR>';
    for (var x = 0; x < sSpacerPattern.length; x++)
    {
        ret += '<img src="';
        ret += oNode.tree.imgRoot;
        if (sSpacerPattern.charAt(x) == "1")
        {
            ret += SrcTree_Image_FullSpacer;
        }
        else
        {
            ret += SrcTree_Image_BlankSpacer;
        }
        ret += '" border="0"  width="'+ SrcTree_Image_Width +'" height="'+ SrcTree_Image_Height +'" class="TreeImage">';

    }
    if (oNode.expandable)
    {
        ret += '<a href="javascript: parent.SrcTree_ToggleExpansion(\''
        ret += oNode.tree.name
        ret += '\',\'' + eKey + '\');">';
    }

    ret += '<img src="';
    ret += oNode.tree.imgRoot;

    if (oNode.expandable)
    {
        if (oNode.expanded)
        {
            ret += bLastSibling ? SrcTree_Image_Unexpand_Bottom : SrcTree_Image_Unexpand;
        }
        else
        {
            ret += bLastSibling ? SrcTree_Image_Expand_Bottom : SrcTree_Image_Expand;
        }

    }
    else
    {
        ret += bLastSibling ? SrcTree_Image_NoExpand_Bottom : SrcTree_Image_NoExpand;
    }

    ret += '" border="0"  width="'+ SrcTree_Image_Width +'" height="'+ SrcTree_Image_Height +'" class="TreeImage">';

    if (oNode.expandable)
        ret += '</a>'

    if (oNode.selectable)
    {
        ret += '<a href="javascript: parent.SrcTree_ToggleSelection(\''
        ret += oNode.tree.name
        ret += '\',\'' + eKey + '\');"><img id="check_' + eKey + '" src="';
        ret += oNode.tree.imgRoot;
        if (oNode.tree.multipleSelect)
        {
            if (oNode.selected)
                ret += SrcTree_Image_Multiple_Selected;
            else
                ret += oNode.partSelected ? SrcTree_Image_Multiple_PartSelected : SrcTree_Image_Multiple_Unselected;
        }
        else
        {
            if (oNode.selected)
                ret += SrcTree_Image_Single_Selected;
            else
                ret += SrcTree_Image_Single_Unselected;
        }
        ret += '" border="0"  width="'+ SrcTree_Image_Width +'" height="'+ SrcTree_Image_Height +'" class="TreeImage"></a>';

    }
    if (oNode.namePrefix)
        ret += oNode.namePrefix;

    if (oNode.expandable)
    {
        ret += '<a href="javascript: parent.SrcTree_ToggleExpansion(\''+ oNode.tree.name +'\',\'' + eKey + '\');">';
    }
    else if (oNode.selectable)
    {
        ret += '<a href="javascript: parent.SrcTree_ToggleSelection(\''+ oNode.tree.name +'\',\'' + eKey + '\');">';

    }
    ret += '<font class="TreeFont">' + oNode.name + '</font>';

    if (oNode.expandable || oNode.selectable)
        ret +='</a>';

    if (oNode.nameSuffix)
        ret += oNode.nameSuffix;

    ret += '</NOBR><br>';


    if (oNode.expanded)
    {
        var numChildren =oNode.aChildKeys ==null ? 0 :  oNode.aChildKeys.length;

        for (var y = 0; y < numChildren; y++)
        {
            ret += SrcTree_RenderBranch(oNode.tree.aNodesByKey[oNode.aChildKeys[y]],sSpacerPattern + (bLastSibling ? "0" : "1"),y==numChildren-1);
        }
    }
    return ret;
}

function SrcTree_CountBranchSelection(oNode)
{
    var ret;
    if (oNode.selected)
    {
        ret = oNode.containedLeafCount;

    }
    else if (oNode.partSelected || !oNode.selectable)
    {
        if (oNode.initialSelection != null)
        {
            ret = oNode.initialSelection.split(oNode.tree.selectionDelimiter).length;
        }
        else
        {
            ret = 0;
            if (oNode.aChildKeys != null)
            {
                var numChildren =  oNode.aChildKeys.length;
                for (var y = 0; y < numChildren; y++)
                {
                    ret += SrcTree_CountBranchSelection(oNode.tree.aNodesByKey[oNode.aChildKeys[y]]);
                }
            }
        }
    }
    else
    {
        ret = 0;
    }
    return ret;

}

function SrcTree_CountSelection(oTree)
{
    var nSelectionCount = 0;
    for (var x = 0; x < oTree.aRootNodeKeys.length  ; x++)
    {
        nSelectionCount += SrcTree_CountBranchSelection(oTree.aNodesByKey[oTree.aRootNodeKeys[x]]);
    }
    return nSelectionCount;
}

function SrcTree_UpdateStatus(oTree)
{
    var nCount =  SrcTree_CountSelection(oTree);
    SrcTree_ShowStatus(oTree,nCount)
    onTreeSelectionChanged(oTree);
}



function SrcTree_ToggleExpansion(sTreeName,sNodeKey)
{
    var oTree = gaTreesByName[sTreeName];
    var oNode = oTree.aNodesByKey[sNodeKey];

    if (oNode.expanded)
    {
        oNode.expanded = false;
        SrcTree_Render(oTree);
    }
    else
    {
        oNode.expanded = true;

        if (oNode.bChildrenFromServer == null)
        {
            oNode.bChildrenFromServer=true;

            // remove existing children to avoid duplicates
            if (oNode.aChildKeys != null)
            {
                var saveSelected = oNode.selected;
                while (oNode.aChildKeys.length > 0)
                    SrcTree_RemoveNode(sTreeName,oNode.aChildKeys[oNode.aChildKeys.length-1])
                oNode.selected = saveSelected;
            }

            var sTarget = oTree.getDataUrl;
            sTarget += "&TreeName=";
            sTarget += sTreeName;
            sTarget += "&ParentKey=";
            sTarget += sNodeKey;
            if (oNode.initialSelection != null)
            {
                if (oTree.initialSelectionKey != null)
                {
                    sTarget += "&InitialSelectionKey=";
                    sTarget += oTree.initialSelectionKey;
                }
                else
                {
                    sTarget += "&InitialSelection=";
                    sTarget += oNode.initialSelection;
                }
                oNode.initialSelection = null;
            }

            oTree.dataFrame.document.location.replace(sTarget);

        }
        else
        {
            SrcTree_Render(oTree);
        }

    }

}


function SrcTree_PropagateSelectionChangeDown(oNode,bChildrenVisible)
{
    if (oNode.aChildKeys != null)
    {
        for (var x=0; x<  oNode.aChildKeys.length; x++)
        {
            oChildNode = oNode.tree.aNodesByKey[oNode.aChildKeys[x]];
            oChildNode.selected = oNode.selected;
            oChildNode.partSelected = false;
            if (bChildrenVisible)
                SrcTree_SetSelectionImage(oChildNode);
            SrcTree_PropagateSelectionChangeDown(oChildNode, bChildrenVisible && oNode.expanded);
        }

    }
}

function SrcTree_PropagateSelectionChangeUp(oNode)
{
    if (oNode.parentKey != null && oNode.parentKey != "")
    {
        oParentNode = oNode.tree.aNodesByKey[oNode.parentKey];
        if (oParentNode.selectable)
        {
            var bChanged = false;
            if (oNode.partSelected)
            {
                if (!oParentNode.partSelected)
                {
                    oParentNode.partSelected = true;
                    oParentNode.selected = false;
                    SrcTree_SetSelectionImage(oParentNode);
                    SrcTree_PropagateSelectionChangeUp(oParentNode);
                }
            }
            else
            {
                var bFoundSelected = oNode.selected;
                var bFoundUnselected = !oNode.selected;
                for (var x=0 ; x< oParentNode.aChildKeys.length; x++)
                {
                    var oChildNode = oNode.tree.aNodesByKey[oParentNode.aChildKeys[x]];
                    if (oChildNode.partSelected)
                    {
                        bFoundSelected = true;
                        bFoundUnselected = true;
                    }
                    else if (oChildNode.selected)
                        bFoundSelected = true;
                    else
                        bFoundUnselected = true;

                    if (bFoundSelected && bFoundUnselected)
                        break;

                }
                //becoming part selected
                if ((!oParentNode.partSelected)&& bFoundSelected && bFoundUnselected)
                {
                    oParentNode.partSelected = true;
                    oParentNode.selected = false;
                    SrcTree_SetSelectionImage(oParentNode);
                    SrcTree_PropagateSelectionChangeUp(oParentNode);
                }
                //becoming unselected
                else if ((oParentNode.selected ||oParentNode.partSelected) && !bFoundSelected)
                {
                    oParentNode.partSelected = false;
                    oParentNode.selected = false;
                    SrcTree_SetSelectionImage(oParentNode);
                    SrcTree_PropagateSelectionChangeUp(oParentNode);
                }
                //becoming selected
                else if (!oParentNode.selected && !bFoundUnselected)
                {
                    oParentNode.partSelected = false;
                    oParentNode.selected = true;
                    SrcTree_SetSelectionImage(oParentNode);
                    SrcTree_PropagateSelectionChangeUp(oParentNode);
                }

            }
        }
    }
}

function SrcTree_SetSelectionImage(oNode)
{
    var eKey    =oNode.key.replace("'", "\\'"); //  Handle apostrophes in user names.
    var imgTag  =oNode.tree.winRef.document.getElementById("check_" + eKey);

    if (imgTag == null)
    {
        // This node is not currently displayed.  It is in a collapsed branch
        // so there is nothing for us to do here.
        return;
    }

    if (oNode.tree.multipleSelect)
    {
        if (oNode.selected)
            imgTag.src = oNode.tree.imgRoot + SrcTree_Image_Multiple_Selected;
        else if (oNode.partSelected)
            imgTag.src = oNode.tree.imgRoot + SrcTree_Image_Multiple_PartSelected;
        else
            imgTag.src = oNode.tree.imgRoot + SrcTree_Image_Multiple_Unselected;

    }
    else
    {
        if (oNode.selected)
        {
            imgTag.src = oNode.tree.imgRoot + SrcTree_Image_Single_Selected;
        }
        else
        {
            imgTag.src = oNode.tree.imgRoot + SrcTree_Image_Single_Unselected;
        }
    }
}

function SrcTree_ToggleSelection(sTreeName,sNodeKey)
{
    var oTree = gaTreesByName[sTreeName];
    var oNode = oTree.aNodesByKey[sNodeKey];

    if (!oTree.multipleSelect) // Single Selection Tree
    {
        if (oTree.sSelectedKey!=null)
        {
            var oPreviousNode = oTree.aNodesByKey[oTree.sSelectedKey];
            oPreviousNode.selected = false;
            SrcTree_SetSelectionImage(oPreviousNode);
        }
        oTree.sSelectedKey = sNodeKey;
        oNode.selected = true;
    }
    else // Multi Selection Tree
    {
        oNode.selected = !(oNode.selected || oNode.partSelected);
        oNode.partSelected = false;
    }
    oNode.initialSelection = null;

    SrcTree_SetSelectionImage(oNode);

    if (oTree.multipleSelect)
    {
        SrcTree_PropagateSelectionChangeDown(oNode,oNode.expanded);
        SrcTree_PropagateSelectionChangeUp(oNode);
    }
    SrcTree_UpdateStatus(oNode.tree);
}


function getPageScrollY(windowRef)
{

  if (!windowRef)
  {
    windowRef = window;
  }

  if (typeof(windowRef.pageYOffset) == 'number')
  {
    return windowRef.pageYOffset;
  }

  if (typeof(windowRef.document.body && windowRef.document.body.scrollTop) == 'number')
  {
    return windowRef.document.body.scrollTop;
  }

  return 0;
}

function UpdateScroll(windowRef,nScrollPosition)
{
    windowRef.scroll(0,nScrollPosition);
}

var aSelectionChangeCallBacks = new Array();

function RegisterTreeSelectionChangeCallBack(sFunc)
{
    aSelectionChangeCallBacks[aSelectionChangeCallBacks.length] = sFunc;
}

function onTreeSelectionChanged(oTree)
{
    if (SrcTree_RunCallback) {
        for (var x = 0 ; x < aSelectionChangeCallBacks.length; x++)
        {
            eval(aSelectionChangeCallBacks[x] +"(oTree)" );
        }
    }
}

function SrcTree_SetCurrentSelection(sTreeName,oNode,bCurrentTab,bExpand)
{
    var oTree   =gaTreesByName[sTreeName];

    if (arguments.length <3)
        bExpand =false;

    if (bExpand)
        SrcTree_ToggleExpansion (sTreeName, oNode.parentKey);

    SrcTree_ToggleSelection (sTreeName, oNode.key);
}


function ScrollTreeToInitialSelection(sTree,bIsActiveTab)
{
    var oTree   =gaTreesByName [sTree];
    var aSel    =SrcTree_GetSelectionArray (oTree, "key");
    var nOffset =-1;

    if (aSel && (aSel.length >0))
    {
        var sKey    =aSel[0];
        var eKey    =sKey.replace("'", "\\'"); //  Handle apostrophes in user names.
        var imgTag  =oTree.winRef.document.getElementById("check_" + eKey);

        if (imgTag) // Will not be found if tree is collapsed.
            nOffset =imgTag.offsetTop -imgTag.offsetHeight
    }

    if (nOffset <0)
    {
        nOffset =getPageScrollY(oTree.winRef);
    }

    oTree.initialized =true;
    UpdateScroll(oTree.winRef, (nOffset >0 ? nOffset : 0));
}

function SrcTree_SelectInitialNode(aNodeList,sInitialSelection,sGroupList)
{
    var oInitialNode    =null;
    var bSelected       =false;

    //StackTrace ("SrcTree_SelectInitialNode [" +sInitialSelection +"]");
    //Debug ("[" +aNodeList[0].key +"]   [" +aNodeList[0].value+"]");

    if(sInitialSelection && (sInitialSelection !=""))
    {
        for (var i =0; i < aNodeList.length ; ++i)
        {
            if (aNodeList[i] && (aNodeList [i].key ==sInitialSelection))
            {
                oInitialNode =aNodeList [i];
                bSelected    =true;
                //sTrace +=" at " +i;
                break;
            }
        }
    }

    if (!bSelected)
    {
        //  Select the first report that is in the user's group list.
        var aGroupList  =sGroupList.replace(/"/g,"").split(",");
        var oGroupList  =new Object();

        for (var i =0; i <aGroupList.length; ++i)
        {
            oGroupList [aGroupList [i]] =true;
        }


        for (var i =0; i <aNodeList.length ; ++i)
        {
            if (aNodeList [i] && aNodeList[i].selectable)
            {
                var aKey    =aNodeList[i].key.split(",");

                if (aKey.length ==3)
                {
                    var aOwner  =aKey [0].split(":");
                    var sKey    =aKey [2];

                    if ((aOwner[0] =="Static")   &&
                         oGroupList [aOwner [1]])
                    {
                        oInitialNode =aNodeList [i];
                        bSelected =true;
                        //sTrace +=" First in group at " +i;
                        break;
                    }
                }
            }
        }
    }

    if (!bSelected && (aNodeList.length >0))
    {
        //  Couldn't find something to select the previous two ways,
        //  so seleect the first selectable node.
        for (var i =0; i <aNodeList.length ; ++i)
        {
            if (aNodeList [i] && aNodeList[i].selectable)
            {
                oInitialNode =aNodeList [i];
                bSelected =true;
                //sTrace +=" First selectable at " +i;
                break;
            }
        }
    }

    //if (!bSelected) sTrace +="No selection"; Debug (sTrace);

    return oInitialNode;
}


