﻿// liconceptTreeControl JScript File

var globalConceptTreeTimer;
var conceptTreeControl_preTreeViewID;
var conceptTreeControl_preTreeNodeID;
var scrollingDivID;
var loadingDivOffset = 75;
var m_settingStatus = false;
var m_srmDelay = 800;
var dblClickSearchPhrase;
var ConceptTitleLabelID;

// Handle tree node expand or collapsed 
function ConceptTreeControl_SetTreeNodeStatus(_node, _hiddenFieldClientID, _sessionNameForExpandedNodes, _scrollFunctionName, _srmIndex) 
{
  if(_node != null)
  {
    var seperator = '@';
    var nodeID = _node.ID.split('_');
    var nodeType = nodeID[0];
    var nodeVal = '[' + nodeType + '_' + _node.Value + ']';
    var box = document.getElementById(_hiddenFieldClientID);
    if(box != null)
    {
      var nodesstatus = box.value;
      
      if (nodeType == "HSO") //an SO ConceptTree Root Node - record if contracted
      {
        if(_node.Expanded)
        {
          // then this node will be collapsed
          if(nodesstatus.indexOf(nodeVal) < 0)
          {
            // not recorded yet
            box.value = nodesstatus + nodeVal + seperator;
          } //end index if
          eval(_scrollFunctionName); //fire the onscroll event incase more nodes are required
          //Currently only SOTree has a valid _scrollFunctionName, but should only be fired if it's a SO node
        }
        else
        {
          // will be expanded
          box.value = nodesstatus.replace(nodeVal+seperator,'');
          
        } //end expanded if
      }
      else // Not an SO ConceptTree Root Node
      {
        if(_node.Expanded)
        {
          // then this node will be collapsed
          box.value = nodesstatus.replace(nodeVal+seperator,'');
          try
          {
            m_srmAction[_srmIndex] = m_srmAction[_srmIndex].replace('Expand','Collapse');
            m_srmAction[_srmIndex] = m_srmAction[_srmIndex].replace(',LOD','');
          }
          catch(e){}
          if (_scrollFunctionName.indexOf('SearchResult') > -1) 
            checkNodeCollapsed(_node, _scrollFunctionName); //fire the onscroll event incase more nodes are required; Make sure the collapse has finished first
            //setTimeout(_scrollFunctionName, 500); //fire the onscroll event incase more nodes are required; Timeout makes sure tree is redrawn first (to check it's new height)
        }
        else
        {
          // will be expanded
          if(nodesstatus.indexOf(nodeVal) < 0)
          {
            // not recorded yet
            box.value = nodesstatus + nodeVal + seperator;
          } //end index if
        } //end expanded if
      }
      setTimeout("SetSessionProperty('" + _sessionNameForExpandedNodes + "', '" + box.value + "')",1);
    }
    else
    {
        alert('Concept tree hidden field not found.');
    } //end box null if
  } 
  try 
  {
    if (m_srmGetTimes!= null && m_srmGetTimes == "True" && _srmIndex != null)
    {
      if (m_srmCallbacks[_srmIndex] == 2)
      {
        m_settingStatus = _srmIndex;
        setTimeout("ResetSettingStatus();",m_srmDelay);
      }
      else
        m_settingStatus = false;
      
      SrmControl_RecordTimes(_srmIndex);
    }
  }
  catch(e){}
  return true; //end node null if
}// end function

function checkNodeCollapsed(_node, _scrollFunctionName, _divId, _counter)
{ // make sure the node is actually collapsed before calling the scrolling function
  if (_node)
  {
    var index = _node.GetCurrentIndex();
    var treeViewId = _node.ParentTreeView.TreeViewID;
    _divId = treeViewId + '_item_' + index + '_div';
  }
  var div = document.getElementById(_divId);
  if (div != null) // div is null if you scroll at the same time
  {
    if (div.style.display != 'none')
    {
      if (_counter != null)
        _counter++;
      else
        _counter = 1;
      if (_counter <= 10) // make sure it doesn't loop forever
        window.setTimeout("checkNodeCollapsed(null, '" + _scrollFunctionName + "', '" + _divId + "', " + _counter + ")", 200);
    }
    else
      window.setTimeout(_scrollFunctionName, 20);
  }
}

function ResetSettingStatus()
{
  if (m_settingStatus)
  {
    try
    {
      m_srmAction[m_settingStatus] = m_srmAction[m_settingStatus].replace('LOD','NoLOD');
      SrmControl_CallbackTrigger_AfterDelay(m_settingStatus, m_srmDelay);
    }
    catch(e){}
    m_settingStatus = false;
  }
}

// Confirm remove concept notification
function ConceptTreeControl_RemoveConceptNotification(_param, _postBackReference)
{  
    var iConfirm= confirm('OK to remove notification?');
    if (iConfirm== true)
    {
      _param = 'RemoveAlertForConcept-' + _param;
    }
    else
    {
      _param = 'FavouriteConceptAlert-' + _param;
    }
    // trigger postback
    eval(_postBackReference);
}// end function

// Process callback error
function ConceptTreeControl_ProcessCallBackError(args, context)
{
  //debugger;

  // Here we are dealing with authentication timeout before callback, 
  // the message from the server is 'elogin' signify an error with 
  // authentication. The response will be trimmed to form the args 
  // 'login' here..... 
  if(args == 'login')
  {
    window.location='home.aspx';
  }
  else
  {
    m_scrolling = false;
    //_args =  _args.substring(_args.indexOf('[@|@]') + 5);
    var s = _args.split('='); 
    var holder = document.getElementById(s[0]);
    if(holder != null)
    {
      holder.innerHTML = 'An error has occurred. ' + s[1];
    }
    else
    {
      alert('Exception occurred. '+ s[1]);
    }
  }
}// end function

// Handle tree node checked/unchecked
function ConceptTreeControl_SetTreeNodeCheckedStatus(_node, _callBackReference, _clientSideOnSubscriptionChange, _srmIndex)
{
  try
  {
    if (m_srmGetTimes!= null && m_srmGetTimes == "True")
      m_srmAction[_srmIndex] += ',' + _node.Text + ',' + _node.ID + ',Checked=' + _node.Checked;
  }
  catch(e){}
  
  if(_node != null)
  {
    // SetSessionProperty('PageSession_KGCheckedConceptID', _node.Value);
    if(_clientSideOnSubscriptionChange != null && _clientSideOnSubscriptionChange.length > 0)
    {
      eval(_clientSideOnSubscriptionChange);
    }
    // trigger callback
    var args = 'Concept=' + _node.Value + '|Checked=' + _node.Checked + '|NodeID=' + _node.ID + '|TreeID=' + _node.ParentTreeView.TreeViewID  + '|SrmIndex=' + _srmIndex;
    
    eval(_callBackReference);
  }
  // alert(_node.Value); // for debug
  // alert(_node.get_Checked()); // for debug
  return true;
}// end function

//// Handle tree node checked/unchecked if subscribing concept from KGKnowlegeGeneListControl
//function ConceptTreeControl_SetTreeNodeCheckedStatusByKGList(_aCheckbox, _conceptId, _kgId, _callBackReference , _clientSideOnSubscriptionChange)
//{
//  if(_conceptId != null && _kgId != null && _aCheckbox != null)
//  {
//    if(_clientSideOnSubscriptionChange != null && _clientSideOnSubscriptionChange.length > 0)
//    {
//      eval(_clientSideOnSubscriptionChange);
//    }
//    
//    // trigger callback
//    var args = 'Concept=' + _conceptId + '|Checked=' + _aCheckbox.checked + '|NodeID='+ 'How_'+ _conceptId + '|TreeID=' + 'FT' + _conceptId +'|KGSubscrpition=1|KGID='+_kgId;
//    
//    eval(_callBackReference);
//    
//    _aCheckbox.checked = _aCheckbox.checked;
//  }
//  
//  return true;
//}

// Subscribe Knowlegenes  from KGKnowlegeGeneListControl
function ConceptTreeControl_SubscribeKGByKGListControl(_aCheckbox, _kgId, _callBackReference , _clientSideOnSubscriptionChange)
{
  if( _kgId != null && _aCheckbox != null)
  {
    if(_clientSideOnSubscriptionChange != null && _clientSideOnSubscriptionChange.length > 0)
    {
      eval(_clientSideOnSubscriptionChange);
    }
    
    // trigger callback;
    var args = 'Concept=-1|Checked=' + _aCheckbox.checked + '|KGSubscrpition=1|KGID='+_kgId;
    
    eval(_callBackReference);
    
    _aCheckbox.checked = _aCheckbox.checked;
  }
  
  return true;
}

// Repopulate concept tree control
function ConceptTreeControl_RepopulateCallbackDone(_args, _context)
{
  // Check for a session time out before completing the callback
  if (CheckSessionTimeout())
    return;
  
  var start = new Date();

  if(_args.indexOf('Status=Error') > -1)
  {
    var statusInfo = _args.split('[@|@]'); 
    var status = statusInfo[0].split('=');
    if(status[1]=='Error')
    {
      var holderID = statusInfo[1].split('=');
      var exception = statusInfo[2].split('=');
      var callbackerror = holderID[1] + '=' + exception[1];
      ConceptTreeControl_ProcessCallBackError(callbackerror, '');
    }
  }
  else
  {
    var repop = _args.split('[@|@]');
    var repopulateStatus = repop[2].split('=');
    if(repopulateStatus[1] == 'true')
    {
      //_args =  _args.substring(_args.indexOf('[@|@]') + 5);
      _args = repop[4];
      var s = _args.split('='); 
      //debugger;
      // get parent container (multipage in this case)
      var seperatorIndex = s[0].lastIndexOf('_');
      if(s[0].lastIndexOf('Page') > seperatorIndex)
      {
        Global_SemanticTreeHolderID = s[0].substring(0,seperatorIndex);
      }
      var holder = document.getElementById(s[0]);
      if(holder != null)
      {
        holder.innerHTML = _args.substring(_args.indexOf('=')+1);

        // need to redeclare the storage and the main function before calling it
        // therefore get the text of it
        // storage first
        var remainString = _args;
        var continueLoop = 0;

        do
        {
          continueLoop = 0;
          var pos1 = remainString.indexOf('![CDATA[');
          if ( pos1 > - 1)
          {
            var string2 = remainString.substring(pos1, _args.length);
            var pos2 = string2.indexOf('window.ComponentArt_Storage_');
            var pos3 = string2.indexOf('//]]>', pos2 + 1);
            
            if ( pos2 > -1 && pos3 > -1)
            {
              var evalStorageString = string2.substring(pos2, pos3);

              // eval the string
              eval(evalStorageString);

              // now the init string
              var pos4 = string2.indexOf('window.ComponentArt_Init_', pos3 + 5);
              var pos5 = string2.indexOf('//]]>', pos4 + 1);
              var funpos = string2.indexOf('=', pos4 + 1);
              if ( pos4 > -1 && pos5 > -1 && funpos > -1)
              {
                var string3 = string2.substring(0, pos5);
                var pos6 = string3.lastIndexOf('}');
                if ( pos6 > -1 )
                {
                  // init function name
                  var functionName = string2.substring(pos4, funpos-1);
                  functionName = functionName.replace(' ','');
                  functionName = functionName + '()';

                  var evalInitString = string3.substring(pos4, pos6 + 1);

                  // eval the string
                  eval(evalInitString);

                  // now execute it now that we've redefined it
                  eval(functionName);
                  
                  // set status
                  continueLoop = 1;
                } // end if pos6
              } // end if pos4 and pos5
            } // end if pos2 and pos3 and funpos

            // get remain string
            remainString = string2.substring(pos5 + 1);
          } // end if pos1
          else
          {
            remainString = '';
          }
        }while(remainString.length > 0 && continueLoop == 1) // end while length
      }
      else
      {
        ConceptTreeControl_ProcessCallBackError('ConceptTreeControl RepopulationCallBackDone: Holder div not found.', '');
      }
    } // end if need repopulation block
      
    try
    {
      SrmControl_RecordTimes(repop[3]);
    }
    catch(e) 
    {}
  } // end status error else block
  
  // mark the end of the Topic Control Callback
  //if (TopicControlBusyFlag)
    //TopicControlBusyFlag = null;
  
  try
  {
    if (m_srmGetTimes != null && m_srmGetTimes == "True")
    {
      var now = new Date();
      var time = Math.round(now.getTime() - start.getTime()) / 1000;
      var message = 'Time,ConceptTreeControl_RepopulateCallbackDone,' + s[0] +': ' + time;
      setTimeout("SrmControl_QuickCallback('" + message + "')",1);
    }
  }
  catch(e) 
  {}
  m_treeViewIsLoaded = true;
}// end function


// Handle alert toggle
function ConceptTreeControl_ChangeAlertSetting(_event, _status, _value, _callBackReference, _srmIndex)
{
  try
  {
    if (m_srmGetTimes!= null && m_srmGetTimes == "True")
      m_srmAction[_srmIndex] += ',Concept=' + _value + ',AlertSetting=' + _status;
  }
  catch(e){}

  //alert(value); 
  var args = 'Concept=' + _value + '|AlertSetting=' + _status + '|SrmIndex=' + _srmIndex;
  // trigger callback
  eval(_callBackReference);
  CancelBubble(_event);
}// end function

// Handle float over concept with mouse
function ConceptTreeControl_OnNodeMouseOver_Wrapped(_node, _displayMode, _eventArgs)
{
  if (_node != null)
  {
    var refocusImgId = _displayMode + '_' + _node.get_id() + '_refocusCell';
    var refocusImg = document.getElementById(refocusImgId);
    if (refocusImg != null)
      refocusImg.className = 'RefocusCellShown';
  }
}

// Handle move mouse off concept
function ConceptTreeControl_OnNodeMouseOut_Wrapped(_node, _displayMode, _eventArgs)
{
  if (_node != null)
  {
    var refocusImgId = _displayMode + '_' + _node.get_id() + '_refocusCell';
    var refocusImg = document.getElementById(refocusImgId);
    if (refocusImg != null)
      refocusImg.className = 'RefocusCellHidden';
  }
}

function GrabHighlightedMyKnowledgeContext(_treeID)
{
  dblClickSearchPhrase = "";
  var aTreeView = null;
  var aTreeNode = null;
  var nodeId = _treeID.SelectedNode.ID;
  var treeId = _treeID.TreeViewID;
  
  if(treeId != null && treeId !='' && treeId != '-1' && eval('window.'+ treeId+'!=null'))
    aTreeNode = eval(treeId + '.FindNodeById(\'' + nodeId + '\')');

  if(aTreeNode != null)
  { 
    aTreeView = aTreeNode.ParentTreeView;
    
    if(aTreeNode.ID != null && aTreeNode.ID != '')
      conceptTreeControl_preTreeNodeID = aTreeNode.ID;
    
    if(aTreeView != null && aTreeView.TreeViewID != '')
      conceptTreeControl_preTreeViewID = aTreeView.TreeViewID;
  }

  while(aTreeNode != null)
  {
    aTreeNode.SaveState();
    dblClickSearchPhrase = aTreeNode.Text + " " + dblClickSearchPhrase;
    aTreeNode = aTreeNode.ParentNode;
  }
    
} // end function

// Wrapper of ConceptTreeControl_OnNodeSelect - set timeout to separate double and single click
function ConceptTreeControl_OnNodeSelect_Wrapper(_treeView, _conceptID, _mapViewDisplayMode, _clientSideOnConceptSeleted, _srmIndex)
{
  var aTreeView = _treeView;
  var aTreeNode = null;
  var treeViewID = '-1';
  var treeNodeID = '-1';
  
  if(aTreeView != null)
  {
    aTreeNode = aTreeView.SelectedNode;
    treeViewID = aTreeView.TreeViewID;
    if(aTreeNode!= null && aTreeNode.ID != '')
      treeNodeID = aTreeNode.ID;
  }
  
  globalConceptTreeTimer = 1;
  ConceptTreeControl_SelectConcept(treeViewID, treeNodeID, _conceptID, _mapViewDisplayMode, _clientSideOnConceptSeleted, _srmIndex);
	//DoCollapseMapViewPane(); //Need to remove to stop bug 5397
}

// Concept selection
function ConceptTreeControl_SelectConcept(_treeViewID, _treeNodeID, _conceptID, _mapViewDisplayMode, _clientSideOnConceptSeleted, _srmIndex)
{
  if (window.CancelEdit)
    CancelEdit(true);
    
  // Lowlight Previous Tree Node
  ConceptTreeControl_LowlightTreeNode(conceptTreeControl_preTreeViewID, conceptTreeControl_preTreeNodeID);
  
  // Highlight Selected Tree Node
  ConceptTreeControl_HighlightTreeNode(_treeViewID, _treeNodeID);
  
  if (_treeViewID.indexOf('ResultTree') > -1)
    hideRootNode(_treeViewID)
    
  var nodeID = _conceptID.split('-');
  var nodeType = nodeID[0];
  var idvalue = _conceptID.substring(nodeID[0].length + 1);
  try 
  {
    if (m_srmGetTimes!= null && m_srmGetTimes == "True" && _srmIndex != null)
      m_srmAction[_srmIndex] += ',' + _conceptID;
  }
  catch(e){}

  if(nodeType.indexOf('What') != -1)
  {
    // what clicked
    // set selectedKGID session variable for MapView to update the MapView
    //SetSessionProperty('SelectedKGID', idvalue);
    //SetSessionProperty('PageSession_KGSelectedKnowdeID', idvalue);
    //SetSessionProperty('MapViewDisplayMode', _mapViewDisplayMode);
    //MapViewControl1_CallbackTrigger_IfVisible(_srmIndex);
    //KGTabbedWindowsControl_CallbackTrigger('KnowdeSelected', _srmIndex);
  }
  else
  {
    // concept clicked
    //SetSessionProperty('PageSession_KGSelectedConceptID', idvalue);
    //SetSessionProperty('MapViewDisplayMode', _mapViewDisplayMode);
    //MapViewControl1_CallbackTrigger_IfVisible(_srmIndex);
    //KGTabbedWindowsControl_CallbackTrigger('ConceptSelected', _srmIndex);
    
    if(m_bEditable == true)
    {
      m_bEditable = false;
      //SwitchEditableFlag();
    }
  }
  
  if(_clientSideOnConceptSeleted != null && _clientSideOnConceptSeleted.length > 0)
    eval(_clientSideOnConceptSeleted);
  
}// end function

// Highlight Tree Node
function ConceptTreeControl_HighlightTreeNode(_treeViewID, _treeNodeID)
{
  var aTreeView = null;
  var aTreeNode = null;
  var treeId = _treeViewID;
  var nodeId = _treeNodeID;
  
  if(treeId != null && treeId !='' && treeId != '-1' && eval('window.'+ treeId+'!=null'))
    aTreeNode = eval(treeId + '.FindNodeById(\'' + nodeId + '\')');

  if(aTreeNode != null)
  { 
    aTreeView = aTreeNode.ParentTreeView;
    
    if(aTreeNode.ID != null && aTreeNode.ID != '')
      conceptTreeControl_preTreeNodeID = aTreeNode.ID;
    
    if(aTreeView != null && aTreeView.TreeViewID != '')
      conceptTreeControl_preTreeViewID = aTreeView.TreeViewID;
  }

  if (aTreeView)
    aTreeView.beginUpdate();
    
  while(aTreeNode != null)
  {
    aTreeNode.set_cssClass('SelectedConcept');
    aTreeNode.SaveState();
    aTreeNode = aTreeNode.ParentNode;
  }
  
  if (aTreeView)
    aTreeView.endUpdate();
} // end function

function endUpdateNoRender(_treeView)
{
  _treeView._updating=false;
}

// Lowlight Tree Node
function ConceptTreeControl_LowlightTreeNode(_treeViewID, _treeNodeID)
{   
    var aTreeNode = null;
    var aTreeView = null;
    var treeId = _treeViewID;
    var nodeId = _treeNodeID;
    
    if(treeId != null && treeId !='' && treeId != '-1' && eval('window.'+ treeId+'!=null'))
    {
      aTreeNode = eval(treeId + '.FindNodeById(\'' + nodeId + '\')');
      
      if(aTreeNode != null)
      {
        aTreeView = aTreeNode.ParentTreeView;
      }
      
      if (aTreeView)
        aTreeView.beginUpdate();
      
      while(aTreeNode != null)
      {
        aTreeNode.set_cssClass('Concept');  // Change the class so it actually gets unhighlighted
        aTreeNode.SaveState();
        aTreeNode = aTreeNode.ParentNode;  //work up through its parents, lowlighting them as well
      }
      
      if (aTreeView)
        endUpdateNoRender(aTreeView);
    }
 }

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Scrolling functions

function DetachScrolling_Wrapped(_treeView)
{
  alert('First node ' + m_firstTopNode + '\r\nLast node ' + m_lastTopNode);
  var div = GetParentDiv(_treeView);
  div.onscroll = null;
  div.onresize = null;
}

// this needs calling after the tree is rendered - it will always show the root node, so it moves the tree down
function hideRootNode(_treeViewId)
{
  if (m_rootNodeIsHidden) // it was hidden before, and should be hidden again now
  {
    var treeView = eval(_treeViewId);
    if (treeView.Frame != null)
    {
      var rootNodeTable = treeView.Frame.childNodes[0];
      if (rootNodeTable != null)
        rootNodeTable.style.display="none";
    }
  }
}

// global variables
var m_globalConceptTreeTimerScroll = null;
var m_firstTopNode = 0; // used to determine which nodes to get from the server, whether to hide or show the root node and whether we need more nodes
var m_lastTopNode; // used to determine which nodes to get from the server, and to calculate m_firstTopNode
var m_totalTopNodes = 0; // top nodes in the *whole* tree, rather than just the visible part. Get from server.
var m_lastPosition=0; // last scrolled position
var m_rootNodeIsHidden = false;
var m_treeViewIsLoaded = false;
var m_scrolling = false; // already doing scrolling work, don't do two at once
var m_refire = false; // if m_scrolling, use m_refire to tell it to fire a new scroll when it's done

function ResetTreeScrollingVariablesWrapped(_treeView, _sessionNameForScrollPosition)
{ // reset the global variables and session variables if we're drawing a new tree (refocus, back button, click suggestion)
  m_globalConceptTreeTimerScroll = null;
  m_firstTopNode = 0;
  m_totalTopNodes = 0;
  m_lastPosition=0;
  m_rootNodeIsHidden = false;
  m_treeViewIsLoaded = false;
  m_scrolling = false;
  m_refire = false;
  setTimeout('ResetScrollbar(' + _treeView.TreeViewID + ')',1);

  SetSessionProperty(_sessionNameForScrollPosition, 0);
  SetSessionProperty('SearchResultTree_firstLoad', 'true');
}

// put the scrollbar to the top, without triggering the onscroll function
function ResetScrollbar(_treeView)
{
  var scrollingDiv = document.getElementById(scrollingDivID);
  if (scrollingDiv != null)
  {
    scrollingDiv.onscroll = null; // remove it temporarily so a callback isn't triggered when we move the scrollbar back to the top
    scrollingDiv.scrollTop = 0; 
    scrollingDiv.onscroll = SearchResult_TreeOnScrollTimer;
  }
}

function MoveScrollbar(_treeView, _position, _counter)
{
  if (scrollingDivID == null || scrollingDivID == '')
    return;
  var scrollingDiv = document.getElementById(scrollingDivID);
  if(scrollingDiv == null)
    return;
  scrollingDiv.scrollTop = _position;
  if (scrollingDiv.scrollTop != _position)
  {
    // it didn't move the div because it hasn't loaded yet, so try again
    // use _counter to make sure it doesn't get stuck in an infinite loop
    if (_counter != null)
      _counter++;
    else
      _counter = 1;
    if (_counter <= 10)
      window.setTimeout("MoveScrollbar(" + _treeView.TreeViewID + ", " + _position + ", " + _counter + ")",200);
  }
}

function TreeOnScrollTimerWrapped(_treeView, _loadingDivId)
{
  if(ConceptSelectedTab == 'Results')
  {
    if (_treeView.Frame == null)
      return;
      
    if (m_treeViewIsLoaded) // stops lots of calls on page load before the tree is fully loaded
      AddLoadingMessage(_treeView, _loadingDivId);
      
    if (m_scrolling)
      m_refire = true;
    else
    {  
      //onscroll fires too many times http://support.microsoft.com/kb/238004  
      clearTimeout(m_globalConceptTreeTimerScroll);
      m_globalConceptTreeTimerScroll = window.setTimeout('SearchResult_TreeOnScroll()', 200);
    }
  }else
  {
    clearTimeout(m_globalConceptTreeTimerScroll);
  }
}

function GetParentDiv(_treeView)
{ // this is the div that has the onscroll event attached to it, set in ConceptTabbedView.cs CreateChildControls
  var frame = _treeView.Frame;
  if (frame == null)
    return null;
  var div = frame.parentNode;
  if (div == null)
    return null;
  while (div.tagName != "DIV")
    div = div.parentNode;
  return div;
}

function AddLoadingMessage(_treeView, _loadingDivId)
{
  //debugger;
  //loadingDiv already exists (added in KGConceptTreeControl.cs), just need to position it and make it visible
  var loadingDiv = document.getElementById(_loadingDivId);
  if (loadingDiv == null)
    return;
  var div = GetParentDiv(_treeView);
  if (div == null || scrollingDivID == null || scrollingDivID == '')
    return;
  var scrollingDiv = document.getElementById(scrollingDivID);
  if(scrollingDiv == null)
    return;
    
  var titleLabel = document.getElementById(ConceptTitleLabelID);
  // get offset top
  var titleLabelTop = 0;
  var obj = titleLabel;
  if(obj.offsetParent)
  {
    do
    {
      if(obj.id == scrollingDiv.id)
        break;
      titleLabelTop += obj.offsetTop;
    }while(obj = obj.offsetParent);
  }
  titleLabelTop += 26;
  if(titleLabelTop < loadingDivOffset)
    titleLabelTop = loadingDivOffset; 

  var position = scrollingDiv.scrollTop;
  var screenHeight = scrollingDiv.clientHeight;
  
  var treeViewOuterTable = _treeView.Frame.parentNode.parentNode.parentNode;
  var spacerAbove = hkFirstChild(treeViewOuterTable.firstChild); // children are: spacerAbove, tree view, spacer below, status box
  var spacerBelow = hkFirstChild(treeViewOuterTable.childNodes[2]); 
  
  var treeStart = GetPixelHeight(spacerAbove);
  var treeEnd = treeStart + _treeView.Frame.offsetHeight + titleLabelTop;
  var totalHeight = treeEnd + GetPixelHeight(spacerBelow);
  
  if (position + screenHeight > treeEnd && totalHeight > treeEnd + 1) // there's empty space below the tree
  {
    loadingDiv.style.left = scrollingDiv.clientLeft;
    if (position > treeEnd)
      loadingDiv.style.top = scrollingDiv.clientTop + position; // Show at top of screen
    else
      loadingDiv.style.top = scrollingDiv.clientTop + treeEnd + _treeView.LineImageHeight; // Show at end of tree
       
    loadingDiv.style.display="block";
  }
  else if (position < treeStart -1) // there's empty space above the tree (initially spacerAbove.clientHeight = 1px) 
  {
    loadingDiv.style.left = scrollingDiv.clientLeft;
    loadingDiv.style.top = scrollingDiv.clientTop + position  + titleLabelTop; //Show at top of screen
    loadingDiv.style.display="block";
  }
  else
    loadingDiv.style.display="none";
}

function ResetForReturn(_loadingDivId)
{
  m_scrolling = false;
  var loadingDiv = document.getElementById(_loadingDivId);
  if (loadingDiv)
    loadingDiv.style.display="none";
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// OnScroll function to trigger callback
function TreeOnScrollWrapped(_treeView, _sessionNameForScrollPosition, _cbreference, _loadingDivId)
{
  //debugger;
  clearTimeout(m_globalConceptTreeTimerScroll);
  if(ConceptSelectedTab == 'Results')
  {
    ///debugger;
    m_scrolling = true;
    
    var nodes = _treeView.Nodes();
    if (nodes.length > 1) // multiple trees from search button - not paging this
    {
      ResetForReturn(_loadingDivId)
      return;
    }
    var rootNode = nodes[0];
    if (rootNode == null)
    {
      ResetForReturn(_loadingDivId)
      return;
    }
    if (!rootNode.Expanded)
    {
      ResetForReturn(_loadingDivId)
      return;
    }
    
    nodes = rootNode.Nodes();

    if (m_lastTopNode == 0 && m_firstTopNode == 0)
      m_lastTopNode = nodes.length;
        
    var lineHeight = _treeView.LineImageHeight; // height of one row in the tree
    var div = GetParentDiv(_treeView);
    if (div == null || scrollingDivID == null || scrollingDivID == '')
    {
      ResetForReturn(_loadingDivId)
      return;
    }
    var scrollingDiv = document.getElementById(scrollingDivID);
    if(scrollingDiv == null)
      return;
    var position = scrollingDiv.scrollTop;
    var screenHeight = scrollingDiv.clientHeight;
    
    // spacerAbove and spacerBelow keep the total height constant so the scroll bar looks right
    var treeViewOuterTable = _treeView.Frame.parentNode.parentNode.parentNode;
    var spacerAbove = hkFirstChild(treeViewOuterTable.firstChild); // children are: spacerAbove, tree view, spacer below, status box
    var spacerBelow = hkFirstChild(treeViewOuterTable.childNodes[2]); 

    // current tree start, end and total height; measured in pixels
    var initTreeStart = GetPixelHeight(spacerAbove);
    var initTreeEnd = _treeView.Frame.offsetHeight + GetPixelHeight(spacerAbove);
    var totalHeight = initTreeEnd + GetPixelHeight(spacerBelow);
    
    // required tree start and end after the scroll; measured in pixels
    var requiredTreeEnd = Math.min(totalHeight, position + 2*screenHeight);
    var requiredTreeStart = Math.max(0,position - screenHeight);
    var numExcessNodes;
    
    if (position >= m_lastPosition) // scrollbar moved down or resize screen or node(s) collapsed
    {
      if (requiredTreeEnd > initTreeEnd + 1 && (m_totalTopNodes == 0 || m_lastTopNode < m_totalTopNodes - 1)) //Do we need to load more nodes?
      {
        var numNodes = Math.floor((requiredTreeEnd - initTreeEnd)/lineHeight) + 1; // total nodes required (root + children)
          
        if (requiredTreeStart > initTreeEnd) // big change, don't need to add all the nodes
          numExcessNodes = Math.floor((requiredTreeStart - initTreeEnd)/lineHeight);
        else
          numExcessNodes = 0;
          
        var lastExistingNode = nodes[nodes.length-1];
        var nodeId = lastExistingNode.ID;
        var nodeType = nodeId.substring(0,nodeId.indexOf('_'));
        var text = lastExistingNode.Text;
        
        var sessionVariable = text + '@' + nodeType + '@' + numNodes + '@' + numExcessNodes;
        SetSessionProperty('SearchResultTree_Scrolling', sessionVariable);
        
        //Go back to the server
        var args = 'Action=scroll';
        args += '|scrollDirection=down';
        args += '|position=' + position;
        args += '|screenHeight=' + screenHeight;
        args += '|numExcessNodes=' + numExcessNodes;
        
        eval(_cbreference);
      } // end if load more nodes on scroll down
      else 
      {
        ResetForReturn(_loadingDivId)
      }
    }
    else if (position < m_lastPosition)//scrollbar moved up
    {
      if (m_firstTopNode > 0 && requiredTreeStart < initTreeStart) //Do we need to load more nodes?
      {
        //Add nodes above and fix spacer
        var numNodes = Math.floor((initTreeStart - requiredTreeStart)/lineHeight) + 1;
            
        if (requiredTreeEnd < initTreeStart) // big change, don't need to add all the nodes
          numExcessNodes = Math.floor((initTreeStart - requiredTreeEnd)/lineHeight);
        else
          numExcessNodes = 0;
        
        var lastExistingNode = nodes[0];
        var nodeId = lastExistingNode.ID;
        var nodeType = nodeId.substring(0,nodeId.indexOf('_'));
        var text = lastExistingNode.Text;
        
        var sessionVariable = text + '@' + nodeType + '@' + -numNodes + '@' + numExcessNodes;
        SetSessionProperty('SearchResultTree_Scrolling', sessionVariable);
          
        //Go back to the server
        var args = 'Action=scroll';
        args += '|scrollDirection=up';
        args += '|position=' + position;
        args += '|screenHeight=' + screenHeight;
        args += '|numExcessNodes=' + numExcessNodes;
        
        eval(_cbreference);
      } //if load more nodes on scroll up
      else
      {
        ResetForReturn(_loadingDivId)
      }
    } 
   
    // CM used to save the scroll position over a redirect/refresh
    SetSessionProperty(_sessionNameForScrollPosition, position);
    m_lastPosition = position;
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// After callback has finished
function ConceptTreeControl_CallbackDone(_args, _context)
{
  if (CheckSessionTimeout())
    return;
  
  if(_args.indexOf('Status=Error') > -1)
  {
    m_scrolling = false;
    return;
  }

  var argsSplit = _args.split('[@|@]');
  var info = argsSplit[0].split('@');
  var direction = info[0]; // the scroll direction, either 'up' or 'down'
  var treeViewId = info[1];
  var position = parseInt(info[2]); // the scroll position from the onscroll method - could have changed if there's been another scroll
  var screenHeight = parseInt(info[3]); // the screen height from the onscroll method
  var numExcessNodes = parseInt(info[4]); // for a big scroll, number of nodes between the previous tree end and the new tree start
  var lastNode = parseInt(info[5]); // the last node added to the tree - determined at the server
  var nodesPassedOver = parseInt(info[6]); // like numExcessNodes, but adjusted of there are children near the join
  var loadingDivId = info[7]; // the div that says 'Loading...'
  m_totalTopNodes = parseInt(info[8]); // number of top nodes in the tree (root node + top how, what, why children)
  
  var treeView = eval(treeViewId); 
  var rootNode = treeView.Nodes()[0];
  
  var newPosition;
  if (m_refire)
  {
    var scrollingDiv = document.getElementById(scrollingDivID);
    newPosition = scrollingDiv.scrollTop; // get this here - scrollbar sometimes moves when we edit the dom below. Need for next scroll
  }

  // lastNode is the last top node (root & first children) that was added at the server
  // if we scrolled up, the nodes were added upside down this is actually the first top node in the tree
  if (direction == "down")
    m_lastTopNode = lastNode;
  else
  {
    m_firstTopNode = lastNode;
    if (m_firstTopNode == 1)
      m_firstTopNode = 0;
  }
  
  var lineHeight = treeView.LineImageHeight
  var serverHeightChange = nodesPassedOver * lineHeight; // these nodes weren't added, just passed over

  var treeViewOuterTable = treeView.Frame.parentNode.parentNode.parentNode;
  var spacerAbove = hkFirstChild(treeViewOuterTable.firstChild); // children are: spacerAbove, tree view, spacer below, status box
  var spacerBelow = hkFirstChild(treeViewOuterTable.childNodes[2]); 
  
  var initTreeStart = GetPixelHeight(spacerAbove);
  var initTreeEnd = initTreeStart + treeView.Frame.offsetHeight;

  var requiredTreeEnd = position + 2*screenHeight;
  var requiredTreeStart = Math.max(0,position - screenHeight);

  var treeXmlString = argsSplit[1];
  //parse XmlString to XmlDocument
  //http://www.w3schools.com/dom/tryit.asp?filename=note_parsertest2
  // code for IE
  if (window.ActiveXObject)
  {
    var doc=new ActiveXObject("Microsoft.XMLDOM");
    doc.async="false";
    doc.loadXML(treeXmlString);
  }
  // code for Mozilla, Firefox, Opera, etc.
  else
  {
    var parser=new DOMParser();
    var doc=parser.parseFromString(treeXmlString,"text/xml");
  }
  var treeXml=doc.documentElement;

  if (direction == "down")
  {
    var bigChange = false;
    //If it was a big change, clear the tree
    if (numExcessNodes != 0 || initTreeEnd <= requiredTreeStart + 20)
    {
      spacerAbove.style.height = (GetPixelHeight(spacerAbove) + treeView.Frame.offsetHeight) + "px";
      ClearTree(rootNode);
      bigChange = true;
    }

    //Add nodes below and fix spacer
    var heightChange = lineHeight * AddNodesBelow(rootNode, treeXml.getElementsByTagName("Node")[1]); //start from 1 so don't add the root node
    if (m_lastTopNode == m_totalTopNodes - 1) // at the end of the tree
      spacerBelow.style.height = "1px"; // should be the same as below unless the tree changed between scrolls
    else
      spacerBelow.style.height = Math.max(1,GetPixelHeight(spacerBelow)-heightChange) + "px";

    if (!bigChange) // small change, need to remove nodes above
    {
      //Remove nodes above and fix spacer
      if (requiredTreeStart > initTreeStart)
      {
        var numNodes = Math.floor((requiredTreeStart - initTreeStart)/lineHeight);
        heightChange = lineHeight * RemoveNodesAbove(treeView, numNodes);
        spacerAbove.style.height = (GetPixelHeight(spacerAbove) + heightChange) + "px";
      }
      
      m_firstTopNode = m_lastTopNode - rootNode.Nodes().length + 1;
      
      //if the top node is 0, i.e. the root node, it will never be counted in the m_firstTopNode calculation above
      //if the top node really should be 1, it doesn't matter if you make it 0 and show the root node
      if (m_firstTopNode == 1) 
        m_firstTopNode = 0;
        
      //  render the tree
      //CMTEMP
      if (navigator.appName == "Microsoft Internet Explorer")
        PartialRenderSearchResult(treeView, 'down');
      else
        treeView.Render();
      if (m_firstTopNode != 0) // need to hide the root node. It's always in the tree so the other nodes can be children
      {
        var rootNodeTable = treeView.Frame.childNodes[0];
        rootNodeTable.style.display="none";
        if (!m_rootNodeIsHidden)
        {
          spacerAbove.style.height = (GetPixelHeight(spacerAbove) + lineHeight) + "px";
          m_rootNodeIsHidden = true;
        }
      }
    }
    else // big change, nodes above already removed - existing in ClearTree, others never added
    {
      m_firstTopNode = m_lastTopNode - rootNode.Nodes().length + 1;
      if (m_firstTopNode == 1)
        m_firstTopNode = 0;
      spacerAbove.style.height = (GetPixelHeight(spacerAbove) + serverHeightChange) + "px";
      spacerBelow.style.height = Math.max(1, GetPixelHeight(spacerBelow) - serverHeightChange) + "px";
      
      // render the tree 
      treeView.Render();
      if (m_firstTopNode != 0) // need to hide the root node. It's always in the tree so the other nodes can be children
      {
        var rootNodeTable = treeView.Frame.childNodes[0];
        rootNodeTable.style.display="none";
        m_rootNodeIsHidden = true;
      }
    }

  }
  else // scrolled up
  {
    //If it was a big change, clear the tree
    var bigChange = false;
    if (numExcessNodes != 0 || initTreeStart >= requiredTreeEnd - 20)
    {
      spacerBelow.style.height = (GetPixelHeight(spacerBelow) + treeView.Frame.offsetHeight) + "px";
      ClearTree(rootNode);
      bigChange = true;
    }

    //Add nodes above and fix spacer
    var lastXmlNode = treeXml.getElementsByTagName("Node")[1]; // Xml is upside down, so last Xml node = first tree node
    while (lastXmlNode.nextSibling != null)
      lastXmlNode = lastXmlNode.nextSibling;
    var heightChange = lineHeight * AddNodesAbove(rootNode, lastXmlNode);
    spacerAbove.style.height = Math.max(0,GetPixelHeight(spacerAbove)-heightChange) + "px";
    
    if (!bigChange)// small change, need to remove nodes above
    {
      //Remove nodes below and fix spacer
      if (requiredTreeEnd < initTreeEnd)
      {
        var numNodes = Math.floor((initTreeEnd - requiredTreeEnd)/lineHeight);
        heightChange = lineHeight * RemoveNodesBelow(treeView, numNodes);
        spacerBelow.style.height = (GetPixelHeight(spacerBelow) + heightChange) + "px";
      }
      m_lastTopNode = m_firstTopNode + rootNode.Nodes().length - 1;
      
      // render the tree
      if (navigator.appName == "Microsoft Internet Explorer")
        PartialRenderSearchResult(treeView, 'up');
      else
        treeView.Render();

      if (m_firstTopNode != 0) // hide the root node
      {
        var rootNodeTable = treeView.Frame.childNodes[0];
        rootNodeTable.style.display="none";
      }
      else if (m_rootNodeIsHidden) // show the root node
      {
        spacerAbove.style.height = "1px";
        m_rootNodeIsHidden = false;
        var rootNodeTable = treeView.Frame.childNodes[0];
        rootNodeTable.style.display="block";
      }
    }
    else // big change, nodes above already removed - existing in ClearTree, others never added
    {
      m_lastTopNode = m_firstTopNode + rootNode.Nodes().length - 1;
      spacerAbove.style.height = Math.max(1, GetPixelHeight(spacerAbove) - serverHeightChange) + "px";
      spacerBelow.style.height = (GetPixelHeight(spacerBelow) + serverHeightChange) + "px";
      
      // render the tree
      treeView.Render();
      
      if (m_firstTopNode != 0) // hide the root node
      {
        var rootNodeTable = treeView.Frame.childNodes[0];
        rootNodeTable.style.display="none";
      }
      else if (m_rootNodeIsHidden) // show the root node
      {
        spacerAbove.style.height = "1px";
        m_rootNodeIsHidden = false;
      }
    }
  }
  
  //Remove the loading message
  var loadingDiv = document.getElementById(loadingDivId);
  loadingDiv.style.display="none";
  
  m_scrolling = false;
  if (m_refire) //Scrollbar has been moved again
  {
    var scrollingDiv = document.getElementById(scrollingDivID);
    scrollingDiv.scrollTop = newPosition; 
    window.setTimeout("SearchResult_TreeOnScrollTimer()", 0);
    m_refire = false;
  }
  else
  {
    // Make sure the scrollbar is in the right place (it can move when you remove things from the dom)
    // Jumps if a scroll is stacked up, so only do this if m_refire == false
    var scrollingDiv = document.getElementById(scrollingDivID);
    scrollingDiv.scrollTop = position; 
  }
  setPaneWidths();
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function ClearTree(_rootNode)
{
  var nodesArray = _rootNode.Nodes(); // keep root node, remove all its children
  for (var nodeIndex = 0; nodeIndex < nodesArray.length; nodeIndex ++)
  {
    node = nodesArray[nodeIndex];
    node.Remove();
  }
}

function AddNodesBelow(_parent, _xmlNode)
{
//xmlNode is for first child to add
//parent is either parent treeView node, or treeView for top level root nodes
  var nodesAdded = 0;
  var treeNode;
  
  while (_xmlNode != null) //make a tree view node from the xml node
  {
    treeNode = CreateTreeNode(_xmlNode);
    _parent.AddNode(treeNode);
    nodesAdded++;
    
    if (_xmlNode.firstChild != null) // add the children
    {
      if (treeNode.Expanded)
        nodesAdded += AddNodesBelow(treeNode, _xmlNode.firstChild)
      else // still need to add children so can be expanded, don't need to count for the height change
        AddNodesBelow(treeNode, _xmlNode.firstChild) 
    }
    
    _xmlNode = _xmlNode.nextSibling; // next root node
  }
  return nodesAdded;
}

function CreateTreeNode(_xmlNode)
{ // turn a node from the xml into a tree view node
  var attributes = _xmlNode.attributes;
  var att;
  
  treeNode = new ComponentArt.Web.UI.TreeViewNode();
  for (var j=0; j<attributes.length; j++)
  {
    att = attributes[j];
    if (att.nodeValue == "True")
      treeNode.SetProperty(att.nodeName, true);
    else if (att.nodeValue == "False")
      treeNode.SetProperty(att.nodeName, false);
    else
      treeNode.SetProperty(att.nodeName, att.nodeValue);
  }
  return treeNode;
}

function RemoveNodesAbove(_treeView, _numNodes)
{
  //_numNodes is a total number including children
  //before you remove a top node, check all its children are ok to be removed
  //only need to remove top nodes
  var nRemovedNodes = 0;
  var node;
  var nChildren;
  var topNode = 0;
  
  var rootNode = _treeView.Nodes()[0];
  var rootNodeDiv = _treeView.Frame.childNodes[1];
  var nodesArray = rootNode.Nodes();
  
  var divDom; //From the Component Art Tree View inner html - remove them here then Partial Render method can be used
  var tableDom;
  
  while (nRemovedNodes < _numNodes)
  {
    node = nodesArray[topNode];
    if (node.Expanded)
    {
      nChildren = NumberOfChildNodes(node);
      if (nRemovedNodes + nChildren > _numNodes)
        break;  
      nRemovedNodes += nChildren;
    }
    else if (nRemovedNodes > _numNodes)
      break;  
    
    nRemovedNodes++;
    node.Remove();
    
    //update DOM for partial render
    tableDom = rootNodeDiv.childNodes[0]; 
    divDom = rootNodeDiv.childNodes[1];
    purge(tableDom);
    tableDom.parentNode.removeChild(tableDom);
    purge(divDom);
    divDom.parentNode.removeChild(divDom);
    
    topNode ++;
  }
  
  return nRemovedNodes;
}

function AddNodesAbove(_rootNode, _xmlNode)
{
//Can only add nodes to end of tree
//First save original nodes, remove then add again later
//xml from server has top nodes upside down, child nodes right way up
//xmlNode is for last xml child (= first tree View node)
//parent is root node
  var nodesAdded = 0;
  var treeNode;
  var originalNodes = _rootNode.Nodes();
  
  //remove original nodes
  for (var nodeIndex = 0; nodeIndex < originalNodes.length; nodeIndex ++)
  {
    node = originalNodes[nodeIndex];
    node.Remove();
  }
  
  while (_xmlNode != null) //make a tree view node from the xml node
  {
    treeNode = CreateTreeNode(_xmlNode);
    _rootNode.AddNode(treeNode);
    nodesAdded++;
    
    if (_xmlNode.firstChild != null) // add the children
    {
      if (treeNode.Expanded)
        nodesAdded += AddNodesBelow(treeNode, _xmlNode.firstChild)
      else // still need to add children so can be expanded, don't need to count for the height change
        AddNodesBelow(treeNode, _xmlNode.firstChild)
    }
    
    _xmlNode = _xmlNode.previousSibling; // next root node (xml root nodes are upside down for scroll up)
  }
  
  //re-add original nodes
  for (var nodeIndex = 0; nodeIndex < originalNodes.length; nodeIndex++)
  {
    node = originalNodes[nodeIndex];
    _rootNode.AddNode(node);
  }
  
  return nodesAdded;
}

function RemoveNodesBelow(_treeView, _numNodes)
{
  //_numNodes is a total number including children
  //before you remove a root node, check all its children are ok to be removed
  //only need to remove root nodes
  var nRemovedNodes = 0;
  var node;
  var nChildren;
  
  var rootNode = _treeView.Nodes()[0];
  var rootNodeDiv = _treeView.Frame.childNodes[1];
  var nodesArray = rootNode.Nodes();
  var nodeIndex = nodesArray.length - 1;
  
  var nodesDomArray;
  var divDom; //From the Component Art Tree View inner html - remove them here then Partial Render method can be used
  var tableDom;
  
  while (nRemovedNodes < _numNodes)
  {
    node = nodesArray[nodeIndex];
    
    if (node.Expanded)
    {
      nChildren = NumberOfChildNodes(node);
      if (nRemovedNodes + nChildren > _numNodes)
        break;  
      nRemovedNodes += nChildren;
    }
    else if (nRemovedNodes > _numNodes)
      break;  
    
    nRemovedNodes++;
    node.Remove();
    
    //update DOM for partial render
    nodesDomArray = rootNodeDiv.childNodes;
    tableDom = nodesDomArray[(nodesDomArray.length-2)];
    divDom = nodesDomArray[(nodesDomArray.length-1)];

    purge(tableDom);
    tableDom.parentNode.removeChild(tableDom);
    purge(divDom);
    divDom.parentNode.removeChild(divDom);
    
    nodeIndex --;
  }
  return nRemovedNodes;
}

function NumberOfChildNodes(_parent)
{
//loop through all the children
  var nChildNodes = 0;
  if (_parent.Expanded)
  {
    var children = _parent.Nodes();
    nChildNodes = children.length;
    for (var c=0; c<children.length; c++)
      nChildNodes += NumberOfChildNodes(children[c]);
  }
  return nChildNodes;
}   

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

function PartialRenderSearchResult(_treeView, _direction)
//window.ComponentArt_TreeView.prototype.PartialRender=function(qzja)
{
  if (_treeView == null)
    return;
  _treeView.element=_treeView.Frame=document.getElementById(_treeView.DivName);
  if (_treeView.Frame == null)
    return;
  var qzon=_treeView.GetProperty('CssClass');
  if(qzon)
    _treeView.Frame.className=qzon;
  var qza=[];

  ////////////////////-------------------------------------------------------------------------------------  
  var rootNode = _treeView.Nodes()[0];
  var qzsm=rootNode.Nodes();
  var rootNodeFrame = document.getElementById(_treeView.TreeViewID + '_item_0_div');

  var nElements = rootNodeFrame.childNodes.length;
  var nRenderedTopChildNodes = nElements/2;
  
  if (nElements == 0)
    return;
    
  if (_direction == "down")
  {
    var lastTable = rootNodeFrame.childNodes[nElements-2];
    var lastDiv = rootNodeFrame.childNodes[nElements-1];
    purge(lastTable);
    lastTable.parentNode.removeChild(lastTable);
    
    for(var qzba=nRenderedTopChildNodes-1;qzba<qzsm.length;qzba++)
    {
      if(qzsm[qzba] && qzsm[qzba].Visible)
      {
        qza[qza.length]=qzsm[qzba].GetHtml();
      };
    };

    SetOuterHtml(lastDiv,qza.join(''));
  }
  else
  {
    var firstTable = rootNodeFrame.childNodes[0];
    var firstDiv = rootNodeFrame.childNodes[1];
    firstTable.removeNode(true);
  
    for(var qzba=0; qzba<qzsm.length-nRenderedTopChildNodes+1;qzba++)
    {
      if(qzsm[qzba] && qzsm[qzba].Visible)
      {
        qza[qza.length]=qzsm[qzba].GetHtml();
      };
    };

    SetOuterHtml(firstDiv,qza.join(''));
  }
  ////////////////////-------------------------------------------------------------------------------------
  
  if(_treeView.KeyboardEnabled)
    ComponentArt_InitKeyboard(_treeView);
    
  if(!_treeView.AllowTextSelection&&cart_browser_ie)
    _treeView.Frame.onselectstart=ComponentArt_CancelEvent;
    
  if(_treeView.HoverPopupEnabled)
    setTimeout(_treeView.TreeViewID+'.GenerateHoverPopups()',200);
};

function HandleRefocusClick(_refocusDiv, _text)
{
  if(_text.substring(0,1) == ' ')
    _text = _text.substring(1); // trim out space, fix for bug 5295
  SetSessionProperty('HideSearchResultItemInfo', 'true');
  var nodeID = _refocusDiv.id.split('_');
  var displayMode = nodeID[0];
  var nodeType = nodeID[1];
  // only deal with refocus on concept, not for what at the moment
  //if(nodeType.indexOf('What') < 0)
  //{
    globalConceptTreeTimer = null;
    var itemID = nodeID[2];
    var itemName = _text;
        
     
    KGConceptsContainerControl_RefocusTreeView(itemID);
  //}
  m_contextString = _text;
}// end function

