/**
 * DropDownHierarchyTree
 **/
subclass(DropDownHierarchyTree, HierarchyTree);
function DropDownHierarchyTree(id, parentDropDown, nodeMap)
{
  HierarchyTree.call(this, id);
  
  this.nodeMap = nodeMap;
  this.parentDropDown = parentDropDown;
  this.onClickItem.addEventListener    ( new REventListener(DropDownHierarchyTree.prototype.onClickItemListener, this) );
}
DropDownHierarchyTree.prototype.onClickItemListener = function(nodeId, nodeText)
{
  this.parentDropDown.setSelectedItem(nodeId, nodeText);
}
DropDownHierarchyTree.prototype.setSelectedItemId = function(selectedItemId)
{
    // clear list
    for(var id in this.selectedItemIdList) this.selectedItemIdList[id] = null;
    
    this.selectedItemIdList[ selectedItemId ] = true;
}




/**
 * DropDown
 **/
function DropDown(id, rootNodeList, nodeMap)
{
  this.tree = null;

  this.bUseExternalDropDown = false;

  // hierarchytree options
  this.bAddNoneOptionToNodeMap = false;
  this.bAddAllOptionToNodeMap = false;
  this.bAddNoChangeOptionToNodeMap = false;
  
  this.idAll = 'All';
  this.idNone = 'None';
  this.idNoChange = 'NoChange';

  this.textAll  = '< All >';
  this.textNone = '< None >';
  this.textNoChange = '< No Change >';
  
  this.enableCheckBox = false;
  
  // data to populate treectrl
  this.rootNodeList = rootNodeList;
  this.nodeMap = nodeMap;

  this.id = id;
  this.idTextCtrl = RegisterControl.statics.encodeId( this, "DropDownText" );

  this.selectedValue = null;
  this.selectedText = null;

  this.dropDownWindowWidth = '200px';
  this.dropDownWindowHeight = '300px';

  this.onClickItem = new REvent();

  RegisterControl.statics.getInstance().add(this);
}
DropDown.prototype.setUseExternalDropDown = function(bUseExternalDropDown)
{
    this.bUseExternalDropDown = bUseExternalDropDown;
}
DropDown.prototype.setSize = function(width, height)
{
    this.dropDownWindowWidth = width;
    this.dropDownWindowHeight = height;
}
DropDown.statics = new Object();
DropDown.statics.idActiveDropDown = '';

/*** Events ***/
DropDown.prototype._click = function()
{
  var instance = $I(this.instanceId);
  
  // show or hide dropdown window
  var bShow = true;
  if(instance.isDropDownWindowVisible()) bShow = false;
  instance.showDropDownWindow(bShow);
}

// required to register control
DropDown.prototype.getId = function()
{
  return this.id;
}
/**
* getIdCtrlIFrame
*   return: appropriate idCtrl string
*/
DropDown.prototype.getIdCtrlIFrame = function()
{
    var idGui = this.id;
    var idCtrlIframe = idGui+'IFrame';     
    return idCtrlIframe;            
}

DropDown.prototype.setSelectedItem = function(value, text)
{
    if (text == null)
      text = this.nodeMap[value].getText();
    
    // data
    this.selectedValue = value;
    this.selectedText = text;

    // gui
    var nodeValue = this.nodeMap[value];
    if( nodeValue && nodeValue.getDisabled() == true )
    {
        this.setText(text + " (Disabled)");
        this.setTextColor( "808080" );
    }
    else
    {
       this.setText(text);
       this.setTextColor( "000000" );
    }
    this.showDropDownWindow(false);

    this.onClickItem.trigger(value, text);
}

DropDown.prototype.setTextColor = function(color)
{
    var ctrl = $(this.idTextCtrl);
    if(!IsNullOrUndefined(ctrl)) ctrl.style.color = color;
}

DropDown.prototype.getSelectedItemId = function()
{
    return this.selectedValue;
}

DropDown.prototype.getSelectedItemText = function()
{
    return this.selectedText;
}

DropDown.statics._mouseOver = function()
{
  var instance = $I(this.instanceId);
  var idDropDownButton = RegisterControl.statics.encodeId( instance, "DropDownButton" );
  $(idDropDownButton)["className"] = "buttonDropDownOver";
}
DropDown.statics._mouseDown = function()
{
  var instance = $I(this.instanceId);
  var idDropDownButton = RegisterControl.statics.encodeId( instance, "DropDownButton" );
  $(idDropDownButton)["className"] = "buttonDropDownDown";
}
DropDown.statics._mouseUp = function()
{
  var instance = $I(this.instanceId);
  var idDropDownButton = RegisterControl.statics.encodeId( instance, "DropDownButton" );
  $(idDropDownButton)["className"] = "buttonDropDownUp";
}

// entry point dom insert the control display
DropDown.prototype.attach = function( e )
{
    var tableContainer = $C("table");
    tableContainer["className"] = DropDown.statics.dropDownWindowClass+' '+DropDown.statics.dropDownWindowClass+this.getId();
    var tbodyContainer = $C( "tbody" );
    tableContainer.appendChild(tbodyContainer);
    
    var trControlContainer = $C( "tr" );
    tbodyContainer.appendChild(trControlContainer);
    var tdControlContainer = $C( "td" );
    trControlContainer.appendChild(tdControlContainer);
  
    if(!this.bUseExternalDropDown)
    {
        var trDropDownWindowContainer = $C( "tr" );
        tbodyContainer.appendChild(trDropDownWindowContainer);
        var tdDropDownWindowContainer = $C( "td" );
        trDropDownWindowContainer.appendChild(tdDropDownWindowContainer);
    }
  
      var table = $C( "table" );
      table.id = RegisterControl.statics.encodeId( this, "Table" );
      table.instanceId = this.getId();
      table["className"] = "dropDownControl";
      table.onmouseover = DropDown.statics._mouseOver;
      table.onmousedown = DropDown.statics._mouseDown;
      table.onmouseup = DropDown.statics._mouseUp;
      table.onmouseout = DropDown.statics._mouseUp;
    
      var tbody = $C( "tbody" );
    
        var trControl = $C( "tr" );
        var tdTextCtrl = $C( "td" );
        // text
        var divText = $C( "input" );
        divText.type="text";
        //var divText = $C( "div" );
        divText.id = RegisterControl.statics.encodeId( this, "DropDownText" );
        divText.instanceId = this.getId();
        divText["className"] = "dropDownText";
        divText.onkeydown = DropDown.statics.handleKeyPress;
        divText.readOnly = true;
        divText.value = this.selectedText;
        
        tdTextCtrl.appendChild(divText);
        trControl.appendChild( tdTextCtrl );
        
        var tdButton = $C( "td" );
        tdButton.id = RegisterControl.statics.encodeId( this, "DropDownButton" );
        tdButton["className"] = "buttonDropDownUp";
        tdButton.style.width = '16px';
        trControl.appendChild( tdButton );
    
        // dropdown event listener onclick
        trControl.id = RegisterControl.statics.encodeId( this, "DropDownControl" );
        trControl.instanceId = this.getId();
        trControl.onclick = this._click;
        tbody.appendChild( trControl );
      table.appendChild( tbody );
    tdControlContainer.appendChild(table);
    
    var dropDownWindow = $C( "div" );
    dropDownWindow["className"] = "dropDownWindowContainer "+DropDown.statics.dropDownWindowClass+this.getId();
    dropDownWindow.id = RegisterControl.statics.encodeId( this, "DropDownWindow" );
    dropDownWindow.style.display = 'none';
        
    if(!this.bUseExternalDropDown)
    {
        tdDropDownWindowContainer.appendChild(dropDownWindow);
    }
    else 
    {
        document.body.appendChild(dropDownWindow);
    }
    e.appendChild( tableContainer );
}

DropDown.prototype.setText = function(text)
{
    var ctrl = $(this.idTextCtrl);
    if(!IsNullOrUndefined(ctrl)) ctrl.value = text;
}
DropDown.prototype.getText = function()
{
    var retval = null;
    var ctrl = $(this.idTextCtrl);
    
    if(!IsNullOrUndefined(ctrl)) retval = ctrl.value;
    return retval;
}
DropDown.prototype.isDropDownWindowVisible = function()
{
    var bVisible = false;
    var dropDownWindow = $(RegisterControl.statics.encodeId( this, "DropDownWindow" ));
    if(dropDownWindow.style.display != 'none') bVisible = true;
    return bVisible;
}
/**
* Position DropDown
*/
DropDown.prototype.PositionDropDown = function()
{
    var doc = document;
    var dropDownWindow = $(RegisterControl.statics.encodeId( this, "DropDownWindow" ));
    var dropDownWindowScrollable = $(RegisterControl.statics.encodeId( this, "DropDownWindowScrollable" ));
    var textCtrl = $(RegisterControl.statics.encodeId( this, "DropDownText" ));
    var targetPos = Coordinate.Statics.findAbsolutePos(textCtrl);

    // start small then grow depending on the available space and contents
    dropDownWindowScrollable.style.width = '1px';
    dropDownWindowScrollable.style.height = '1px';

    var windowHeight = 0;
    if (doc.documentElement && doc.documentElement.clientHeight)
        windowHeight = doc.documentElement.clientHeight;
    else if (doc.body)
        windowHeight = doc.body.clientHeight;

    var availableTopSpace = targetPos.y - doc.body.scrollTop - 10;
    var availableBottomSpace = doc.body.scrollTop + windowHeight - targetPos.y - textCtrl.offsetHeight - 20;
    
    // determine dimentions for div
    var width = dropDownWindowScrollable.scrollWidth + 22;
    if(width < textCtrl.scrollWidth)
        width = textCtrl.scrollWidth;
    dropDownWindowScrollable.style.width = width+'px';

    var contentHeight = dropDownWindowScrollable.scrollHeight + 2;
    if (availableBottomSpace < contentHeight && availableBottomSpace < availableTopSpace && 200 < availableTopSpace)
    {
        var divHeight = (availableTopSpace<contentHeight)?(availableTopSpace):(contentHeight);
        dropDownWindowScrollable.style.height = divHeight+'px';
        dropDownWindow.style.top = (targetPos.y - divHeight) + 'px';
    }
    else
    {
        var divHeight = (50<availableBottomSpace)?availableBottomSpace:50;
        dropDownWindowScrollable.style.height = (divHeight<contentHeight)?(divHeight+'px'):(contentHeight+'px');
        dropDownWindow.style.top = (targetPos.y + textCtrl.offsetHeight) + 'px';
    }

    dropDownWindow.style.left = targetPos.x + 'px';

    var browser = new RBrowserDetector();
    if(browser.msie)
    {
        var iframe = $(this.getIdCtrlIFrame());
        iframe.style.height = dropDownWindowScrollable.style.height;
        iframe.style.width = dropDownWindowScrollable.style.width;
    }
}

DropDown.prototype.showDropDownWindow = function(bShow)
{
    var dropDownWindow = $(RegisterControl.statics.encodeId( this, "DropDownWindow" ));
    if(bShow == true)
    {
        DropDown.statics.hideOpenDropDownWindow();
        DropDown.statics.idActiveDropDown = this.id;
        
        if(IsNullOrUndefined(this.tree)) 
        {
            // scrollable window
            var divScrollable = $C("div");
            divScrollable.id = RegisterControl.statics.encodeId( this, "DropDownWindowScrollable" );
            divScrollable["className"] = "dropDownWindowScrollable";
            divScrollable.style.width = this.dropDownWindowWidth;
            divScrollable.style.height = this.dropDownWindowHeight;
        
            this.tree = new DropDownHierarchyTree(this.id+"HierarchyTree", this);
            this.tree.setSelectedItemId(this.selectedValue);
            this.tree.attach(divScrollable);
            
            var browser = new RBrowserDetector();
            if(browser.msie)
            {
                // IE hack (this trick covers the <SELECT> that shows on the top layer)
                // this iframe is approximate coverage
                var iFrameHack = $C("iframe");
                iFrameHack.id = this.getIdCtrlIFrame();
                iFrameHack["className"] = "dropDownWindowIFrame";        
                dropDownWindow.appendChild(iFrameHack);
            }
            
            dropDownWindow.appendChild(divScrollable);
            
            this.tree.instanceId = this.getId();
            this.tree.rootNodeList = this.rootNodeList;
            this.tree.nodeMap = this.nodeMap;

            this.tree.refresh();
            dropDownWindow.style.display = "block";   

            this.PositionDropDown();
        }
        else 
        {
            this.tree.setSelectedItemId(this.selectedValue);
            this.tree.refresh();
            dropDownWindow.style.display = "block";        
            
            this.PositionDropDown();
        }
    }
    else
    {
        dropDownWindow.style.display = "none";
    }
    
    var dropDownText = $(RegisterControl.statics.encodeId( this, "DropDownText" ));
    if(!IsNullOrUndefined()) dropDownText.focus();
}
DropDown.prototype.addTextNodeToTop = function( id, text )
{
  // ensure adding only once
  if(IsNullOrUndefined(this.nodeMap[id]))
  {
      var node = new HierarchyTreeNode(id, null, text );
      node.setStateTextOnly();
      this.nodeMap[id] = node;
    
      this.rootNodeList.splice(0,0,node);
  }
}
// call after nodemap is set and before refresh()
DropDown.prototype.addNoneOptionToNodeMap = function()
{
  this.addTextNodeToTop(this.idNone, this.textNone);
}
// call after nodemap is set and before refresh()
DropDown.prototype.addAllOptionToNodeMap = function()
{
  this.addTextNodeToTop(this.idAll, this.textAll);
}
// call after nodemap is set and before refresh()
DropDown.prototype.addNoChangeOptionToNodeMap = function()
{
  this.addTextNodeToTop(this.idNoChange, this.textNoChange);
}











// tree options
DropDown.prototype.treeSetEnableCheckBox = function( bEnable )
{
    this.enableCheckBox = bEnable;
}
DropDown.prototype.treeSetOptionAllText = function( text )
{
    this.textAll = text;
}
DropDown.prototype.treeSetOptionNoneText = function( text )
{
    this.textNone = text;
}
DropDown.prototype.treeSetOptionNoChangeText = function( text )
{
    this.textNoChange = text;
}












/**
* hoverFirstVisibleIndex
*/
DropDown.prototype.hoverFirstVisibleIndex=function()
{
    var idTableSelectedBody = this.getIdDropDownTableBodyGui();
    var elementTableBody = $(idTableSelectedBody);
    
    var idDivTableGui = this.getIdDropDownDivTableGui();
    var elementDiv = $(idDivTableGui);
    var pos = Coordinate.Statics.findPos(elementDiv);
    
    var hoverTop = parseInt(elementDiv.scrollTop+pos.y+1);
    this.pivotToHighlight(elementTableBody, hoverTop, 1, elementTableBody.childNodes.length-1);
}




/*** KEYBOARD EVENT HANDLING **********************************************************************/
/**
* handleKeyPressUp
*/
DropDown.prototype.handleKeyPressUp = function(event)
{
    // show dropdown
    if(!this.isDropDownWindowVisible()) this.showDropDownWindow(true);
    
    var bHoverFound = false;
    var tbody = $( RegisterControl.statics.encodeId( this.tree, "tree" ) );
    var i;
    for(i = 0; i<tbody.childNodes.length; i++)
    {
        var tr = tbody.childNodes[i];
        var textNodeId =  RegisterControl.statics.encodeId( this.tree, tr.nodeId, "node" );
        var textNode = $(textNodeId);
        
        if(textNode["className"] == "treeNodeOver")
        {
            var iPrevNode = i-1;
            if(iPrevNode > -1)
            {
                this.tree.setMouseOutStyle(textNode);
                
                var prevTr = tbody.childNodes[iPrevNode];
                var prevTextNodeId =  RegisterControl.statics.encodeId( this.tree, prevTr.nodeId, "node" );
                var prevTextNode = $(prevTextNodeId);

                this.tree.setMouseOverStyle(prevTextNode);
            }
            bHoverFound = true;
            break;
        }
    }
    if(bHoverFound == false)
    {
        // hover first item
        var tr = tbody.childNodes[0];
        var textNodeId =  RegisterControl.statics.encodeId( this.tree, tr.nodeId, "node" );
        var textNode = $(textNodeId);
        this.tree.setMouseOverStyle(textNode);
    }
}
/**
* handleKeyPressDown
*/
DropDown.prototype.handleKeyPressDown = function(event)
{
    // show dropdown
    if(!this.isDropDownWindowVisible()) this.showDropDownWindow(true);

    var bHoverFound = false;
    var tbody = $( RegisterControl.statics.encodeId( this.tree, "tree" ) );
    var i;
    for(i = 0; i<tbody.childNodes.length; i++)
    {
        var tr = tbody.childNodes[i];
        var textNodeId =  RegisterControl.statics.encodeId( this.tree, tr.nodeId, "node" );
        var textNode = $(textNodeId);
        
        if(textNode["className"] == "treeNodeOver")
        {
            var iNextNode = i+1;
            if(iNextNode < tbody.childNodes.length)
            {
                this.tree.setMouseOutStyle(textNode);
               
                var nextTr = tbody.childNodes[iNextNode];
                var nextTextNodeId =  RegisterControl.statics.encodeId( this.tree, nextTr.nodeId, "node" );
                var nextTextNode = $(nextTextNodeId);

                this.tree.setMouseOverStyle(nextTextNode);
            }
            bHoverFound = true;
            break;
        }
    }
    if(bHoverFound == false)
    {
        // hover first item
        var tr = tbody.childNodes[0];
        var textNodeId =  RegisterControl.statics.encodeId( this.tree, tr.nodeId, "node" );
        var textNode = $(textNodeId);
        this.tree.setMouseOverStyle(textNode);
    }
}
/**
* handleKeyPressEnter
*/
DropDown.prototype.handleKeyPressEnter = function(event)
{
    var domElement = this.tree.elementHovered;
    if(this.isDropDownWindowVisible() && domElement != null)
    {
        var node = this.nodeMap[domElement.nodeId];
        this.tree.onClickItem.trigger(node.getId(), node.getText());
    }
}
/**
* handleKeyPressPageUp
*/
DropDown.prototype.handleKeyPressPageUp = function(event)
{
}
/**
* handleKeyPressPageDown
*/
DropDown.prototype.handleKeyPressPageDown = function(event)
{
}
/**
* handleKeyPress
*   handles the navigation keys
*/
DropDown.statics.handleKeyPress = function(event)
{
    if(IsNullOrUndefined(event)) event = window.event;
    
    var instance = $I(this.instanceId);
    var keyCode = event["keyCode"];
    if(keyCode == 38) 
    {
        // up
        instance.handleKeyPressUp(event);
    }
    else if(keyCode == 40)
    {
        // down
        instance.handleKeyPressDown(event);
    }
    else if(keyCode == 13)
    {
        // enter
        instance.handleKeyPressEnter(event);
    }
    else if(keyCode == 33)
    {
        // pageup
        instance.handleKeyPressPageUp(event);
    }
    else if (keyCode == 34)
    {
        // pagedown
        instance.handleKeyPressPageDown(event);
    }
    else if (keyCode == 9)
    {
        // tab
        return true;
    }
    return false;
}















/*** DOCUMENT LEVEL EVENT HANDLING **********************************************************************/
DropDown.statics.dropDownWindowClass = 'dropDownControlContainer'; // 
/**
* hideOpenDropDownWindowFromEvent
*   given event, hide active dropdown on from a document event
*/
DropDown.statics.hideOpenDropDownWindowFromEvent=function(event)
{
    var doHide = true;
    if(event && DropDown.statics.idActiveDropDown)
    {
        var target = GetElementTargetFromEvent(event);
        while(target && doHide)
        {
            var strClassName = DropDown.statics.dropDownWindowClass+DropDown.statics.idActiveDropDown;
            if(IsClassName(target, strClassName))// do not interfere with dropdown's internal event listening
            {
                doHide = false;
                break;
            }
            target=target.parentNode;        
        }
        if(doHide) // handle all other clicks (non-dropdown specific)
        {
            DropDown.statics.hideOpenDropDownWindow();
        }
    }
}
/**
* hideOpenDropDownWindow
*   hides the last stored active dropdown
*/
DropDown.statics.hideOpenDropDownWindow=function()
{
    if(DropDown.statics.idActiveDropDown == '') return;
    
    var instance = $I(DropDown.statics.idActiveDropDown);
    var dropDownWindowId = RegisterControl.statics.encodeId( instance, "DropDownWindow" );
    var dropDownWindow = $(dropDownWindowId);
    
    if(dropDownWindow.style.display != 'none') instance.showDropDownWindow(false);
    DropDown.statics.idActiveDropDown='';
}
/**
* registerOnDocumentClick
*   register the event listener to hide active dropdowns when clicking anywhere inside the document
*/
DropDown.statics.registerOnDocumentClick=function()
{
    if(document.addEventListener)
    {
        document.addEventListener('click', DropDown.statics.hideOpenDropDownWindowFromEvent, false);
    }
    else if(document.attachEvent)
    {
        document.attachEvent('onclick', DropDown.statics.hideOpenDropDownWindowFromEvent);    
    }    
}


// event listening to hide open dropdowns
//if(!IsNullOrUndefined(WindowControl))
//{
//    var windowControl = WindowControl.statics.getInstance();
//    windowControl.onClick.addEventListener(new REventListener(DropDown.statics.hideOpenDropDownWindow,null));
//}
//else 
//{
    DropDown.statics.registerOnDocumentClick();
//}