/**
 * @author   Pascal Noordink
 * @version 12-11-2008
 */
var poGridInstance   = null;

 /**
 * Als de body geladen is dan het `PioenPartners_JS_Grid` object aan het
 * grid koppelen. 
 */
/*laOnloadActions.push(
  function() {
     // Instantie van de grid maken.
     PioenPartners_JS_Grid.initGrid("PPGrid");
  }
);*/

var PioenPartners_JS_Grid = {
   _lnSorted : 0,
 
   /**
    * Maak een instantie van het Grid en geef het Grid een standaard ordening.
    *
    * @param  lcGrid
    * @return  void
    */
   initGrid : function(lcGrid) {   
     // Grid element opvragen.
     var loGrid    = document.getElementById(lcGrid);
     var loBody     = document.getElementById(lcGrid + "Body");
     var loHeader  = document.getElementById(lcGrid + "Header");

     // Gegevens uit het grid mogen niet geselecteerd worden.
     this._disableSelect(loBody);
     this._disableSelect(loHeader);
     
     // De body van het grid resizen. (Dit kan niet in CSS)     
     try {
       if(loGrid.style.width.indexOf("%") == -1) {
         loBody.style.height = (parseInt(loGrid.style.height) - 21) + "px";
         loBody.style.width  = (parseInt(loGrid.style.width)) + "px";
       } else {
         //loBody.style.height = (parseInt(loGrid.style.height) - 21) + "px";
         //loBody.style.width  = (parseInt(loGrid.style.width)) + "%";
       }
     } catch(e) {}
     
     // Instantie van de `PioenPartners_JS_Grid` class in een globable variabele
     // opslaan. Bij het uitvoeren van functies op het grid kan de instantie
     // gebruikt worden. Deze is op dat punt namelijk niet meer bekend.
     poGridInstance = this;     

     // Lege textNodes verwijderen om problemen met FireFox te voorkomen.
    this._cleanNodes(loGrid)     
     
    // De eerste regel selecteren.
    var loRow = loHeader.getElementsByTagName("div")[0];
    
    // Alle kolommen van het grid doorlopen en deze sorteerbaar maken.
    var lnColumns = loRow.getElementsByTagName("div").length;
    
    for(var lnI = 0; lnI < lnColumns; lnI++) {
      var loColumn = loRow.getElementsByTagName("div")[lnI];
      
      // Een `onclick` event toevoegen aan de header. Als er op de header
      // wordt geklikt dan wordt de functie `doSort` voor de desbetreffende
      // kolom uitgevoerd.
      loColumn.onclick = new Function("document.getElementById('"+ lcGrid +"Wait').style.visibility = 'visible'; setTimeout(\"PioenPartners_JS_Grid.doSort('"+ lcGrid +"', "+ lnI +");\", 100);");
      
      // Standaard is geen enkele kolom geordend. In de functie `doSort`
      // wordt een kolom gekozen om op te ordenen.
      loColumn.className = 'OrderNone';
    }

     // Even en oneven regels tekenen.
     this._showLines(loBody);    
   },
   
   /**
    * De functie 'chromeFix' voegt alle regels opnieuw toe aan het Grid
    * om Chrome en Safari expliciet de grootte opnieuw te laten bepalen.
    */
   chromeFix : function(lcGrid) {
     // Grid element opvragen.
     var loGrid    = document.getElementById(lcGrid);
     var loBody     = document.getElementById(lcGrid + "Body");
     
    // Alle rows doorlopen en deze in een array opslaan, als er straks wordt
    // geordend opnieuw opbouwen. 
    var laRows = new Array();
    var lnRows = loBody.getElementsByTagName("div").length;
    
    for(var lnI = 0; lnI < lnRows; lnI++) {
      if(loBody.getElementsByTagName("div")[lnI].className != "PPGridColumn") {
        laRows.push(loBody.getElementsByTagName("div")[lnI]);
      }
    }
    
    // Alle geordende rows weer toevoegen aan de grid.
    var lnRows = laRows.length;
    
    for(var lnI = 0; lnI < lnRows; lnI++) {
      loBody.appendChild(laRows[lnI]);
    }
   },
   
   /**
    * De regels ordenen op inhoud. Tevens de weergave van de header wijzigen
    * als een sorteer volgorde wordt gewijzigd.
    *
    * @param  lcGrid
    * @param  lnIndex
    * @return  void
    */   
   doSort : function(lcGrid, lnIndex) {
     // Grid element opvragen.
     var loBody     = document.getElementById(lcGrid + "Body");
     var loHeader  = document.getElementById(lcGrid + "Header");

    // Div tonen om te laten zien dat het grid bijgewerkt wordt.
    document.getElementById(lcGrid +"Wait").style.visibility = "visible";

     // De kolom die wordt gesorteerd opslaan in de variabele `_lnSorted`
     // zodat de sorteer functie er nog bij kan.
     this._lnSorted = lnIndex;

     // De gekozen kolom opvragen.
     var loRow     = loHeader.getElementsByTagName("div")[0];
    var loColumn  = loRow.getElementsByTagName("div")[lnIndex];
    
    // Als de gekozen kolom al een order heeft dan omdraaien, als dat niet
    // het geval is dan beginnen met ASC.
    var lcOrder = 'ASC';
    
    switch(loColumn.className) {
      case 'OrderASC':
        loColumn.className  = 'OrderDESC';
        lcOrder        = 'DESC'
        break;
        
      case 'OrderDESC':
        loColumn.className = 'OrderASC';
        break;
        
      case 'OrderNone':
        loColumn.className = 'OrderASC';
        break;
    }
    
    // Alle andere kolommen mogen geen order meer bevatten. Tevens dient
    // het uiterlijk te worden gewijzigd door de css class naam te wijzigen.
    var lnColumns = loRow.getElementsByTagName("div").length;
    
    for(lnI = 0; lnI < lnColumns; lnI++) {
      if(lnI != lnIndex) {
        loRow.getElementsByTagName("div")[lnI].className = 'OrderNone';
      }
    }
    
    // Alle rows doorlopen en deze in een array opslaan, als er straks wordt
    // geordend opnieuw opbouwen. 
    var laRows = new Array();
    var lnRows = loBody.getElementsByTagName("div").length;
    
    for(var lnI = 0; lnI < lnRows; lnI++) {
      if(loBody.getElementsByTagName("div")[lnI].className != "PPGridColumn") {
        laRows.push(loBody.getElementsByTagName("div")[lnI]);
      }
    }
  
    // Initieel String.
    var lcType = "String";
    var lnRows = laRows.length;

    for(var lnI = 0; lnI < lnRows; lnI++) {
      var luValue = this._getColumnValue(laRows[lnI].childNodes[lnIndex]);
      
      // Voor uiterlijk plaatsen we vaak een streepjes tussen de datum en tijd, hier dus
      // ook op testen.
      if(luValue.length != 0) {
        if(luValue.match(/[0-9]{2}-[0-9]{2}-[0-9]{4} [0-9]{2}:[0-9]{2}/)) {
          lcType = "DateTime";
        } else if(luValue.match(/[0-9]{2}-[0-9]{2}-[0-9]{4} - [0-9]{2}:[0-9]{2}/)) {
          lcType = "DateTime";    
        } else if(luValue.match(/[0-9]{2}-[0-9]{2}-[0-9]{4}/)) {
          lcType = "Date";          
        } else if(!isNaN(luValue)) {
          lcType = "Numeric";
        } else {
          lcType = "String";
        }
        
        // Type is gevonden dus stoppen.
        lnI = laRows.length;          
      }
    }
    
    // Alle rows ordenen met de functie `_doSort.......`.
    if(lcType == "DateTime") {
      laRows.sort(this._doSortDateTime);
    } else if(lcType == "Date") {
      laRows.sort(this._doSortDate);
    } else if(lcType == "Numeric") {
      laRows.sort(this._doSortNumeric);
    } else {
      laRows.sort(this._doSortString);
    }

    // Als de order op DESC staat dan de array omdraaien.
    if(lcOrder == 'DESC') {
      laRows.reverse();
    }

    // Alle geordende rows weer toevoegen aan de grid.
    for(var lnI = 0; lnI < lnRows; lnI++) {
      loBody.appendChild(laRows[lnI]);
    }

    // Het ordenen is gereed dus de melding kan weer weg worden gehaald.
    document.getElementById(lcGrid +"Wait").style.visibility = "hidden";

     // Even en oneven regels tekenen.
     this._showLines(loBody);        
   },
   
   /**
    * De functie 'doFilter' loopt alle elementen in het Grid langs en maakt
    * de elementen die niet aan het filter voldoen onzichtbaar.
    *
    * @param  lcGrid
    * @param  lcFilterText
    * @return  Void
    */
   doFilter : function(lcGrid, lcFilterText) {
     /** 
      * Grid element opvragen.
      */
     var loBody       = document.getElementById(lcGrid + "Body");
     var lcFilterText  = lcFilterText.toUpperCase();
     
     /**
      * Alle regels in het Grid langslopen.
      */
    var lnRows = loBody.getElementsByTagName("div").length;
    for(var lnI = 0; lnI < lnRows; lnI++) {
      /**
       * De regel node opvragen.
       */
      var loRow = loBody.getElementsByTagName("div")[lnI];
        
      if(loRow.className != "PPGridColumn") {
        /**
         * Alle kolommen in de regel doorlopen, als er ook maar ��n aan
         * de voorwaarde voldoet dan blijven tonen.
         */ 
        var llFound = false;
        
        /**
         * Als er geen filter is opgegeven dan alles tonen.
         */
        if(lcFilterText == "") {
          llFound = true;
        } else {
          /**
           * Voor de snelheid gaan we niet elke kolom langs maar alleen de
           * volledige tekst van de regel. Hierin zit dan jammergenoeg
           * ook de opmaak dus bij het intikken van bijvoorbeeld 'DIV' zijn
           * alle regels gewoon zichtbaar.
           */
          llFound = loRow.innerHTML.toUpperCase().indexOf(lcFilterText) != -1;
          
          //var lnColumns = loRow.getElementsByTagName("div").length;
          //
          //for(var lnC = 0; lnC < lnColumns; lnC++) {
          //  if(poGridInstance._getColumnValue(loRow.childNodes[lnC]).toUpperCase().indexOf(lcFilterText) != -1) {
          //    llFound = true;
          //    break;
          //  }
          //}
        }
        
        /**
         * Als geen enkele waarde aan het filter voldoet dan niet meer
         * tonen.
         */
        if(llFound == false) {
          loRow.style.display = "none";
        } else {
          loRow.style.display = "block";
        }
      }
    }     

     /** 
      * Even en oneven regels tekenen.
      */
     this._showLines(loBody);
   },
   
    /**
    * Sorteer functie die wordt aangeroepen vanuit de functie `doSort`. Als de
    * methode `sort` op een array wordt uitgevoerd dan wordt deze functie 
    * aangeroepen.
    * De functie vergelijkt 2 waarden met elkaar en geeft dan.
    *  . -1 terug als A voor B ligt.
    *  . 0 terug als de waardes gelijk zijn.    
    *  . 1 terug als B voor A ligt. 
    *
    * @param  loRowA
    * @param  loRowB
    * @return  Integer
    */      
   _doSortDateTime : function(loRowA, loRowB) {
     // De waarden van regel A vergelijken met regel B.
    var lcValueA = poGridInstance._getColumnValue(loRowA.childNodes[poGridInstance._lnSorted]).toLowerCase();
    var lcValueB = poGridInstance._getColumnValue(loRowB.childNodes[poGridInstance._lnSorted]).toLowerCase();

    // De eventuele streep tussen de datum en tijd verwijderen.
    lcValueA = lcValueA.replace(" - ", " ");
    lcValueB = lcValueB.replace(" - ", " ");
    
    // De opgegeven datums en tijden omschrijven naar het formaat: `jjjjmmddhhmm`.
    var lnValueA = lcValueA.substr(6, 4) + lcValueA.substr(3, 2) + lcValueA.substr(0, 2) + lcValueA.substr(11, 2) + lcValueA.substr(14, 2);
    var lnValueB = lcValueB.substr(6, 4) + lcValueB.substr(3, 2) + lcValueB.substr(0, 2) + lcValueB.substr(11, 2) + lcValueB.substr(14, 2);
    
    // Als de waardes overeenkomen dan `0` retourneren.
    if (lnValueA == lnValueB) {
      return 0;
    }
    
    // Als de waarde van A voor de waarde van B ligt dan `-1` retourneren.
    if (lnValueA < lnValueB) {
      return -1;
    }
    
    // Als de waarde van B voor de waarde van A ligt dan `1` retourneren.
    return 1;
   },   
   
   /**
    * Sorteer functie die wordt aangeroepen vanuit de functie `doSort`. Als de
    * methode `sort` op een array wordt uitgevoerd dan wordt deze functie 
    * aangeroepen.
    * De functie vergelijkt 2 waarden met elkaar en geeft dan.
    *  . -1 terug als A voor B ligt.
    *  . 0 terug als de waardes gelijk zijn.    
    *  . 1 terug als B voor A ligt. 
    *
    * @param  loRowA
    * @param  loRowB
    * @return  Integer
    */      
   _doSortDate : function(loRowA, loRowB) {
     // De waarden van regel A vergelijken met regel B.
    var lcValueA = poGridInstance._getColumnValue(loRowA.childNodes[poGridInstance._lnSorted]).toLowerCase();
    var lcValueB = poGridInstance._getColumnValue(loRowB.childNodes[poGridInstance._lnSorted]).toLowerCase();

    // De opgegeven datums omschrijven naar het formaat: `jjjjmmdd`.
    var lnValueA = lcValueA.substr(6, 4) +"-"+ lcValueA.substr(3, 2) +"-"+ lcValueA.substr(0, 2);
    var lnValueB = lcValueB.substr(6, 4) +"-"+ lcValueB.substr(3, 2) +"-"+ lcValueB.substr(0, 2);
      
    // Als de waardes overeenkomen dan `0` retourneren.
    if (lnValueA == lnValueB) {
      return 0;
    }
    
    // Als de waarde van A voor de waarde van B ligt dan `-1` retourneren.
    if (lnValueA < lnValueB) {
      return -1;
    }
    
    // Als de waarde van B voor de waarde van A ligt dan `1` retourneren.
    return 1;
   },   
   
   /**
    * Sorteer functie die wordt aangeroepen vanuit de functie `doSort`. Als de
    * methode `sort` op een array wordt uitgevoerd dan wordt deze functie 
    * aangeroepen.
    * De functie vergelijkt 2 waarden met elkaar en geeft dan.
    *  . -1 terug als A voor B ligt.
    *  . 0 terug als de waardes gelijk zijn.    
    *  . 1 terug als B voor A ligt. 
    *
    * @param  loRowA
    * @param  loRowB
    * @return  Integer
    */      
   _doSortNumeric : function(loRowA, loRowB) {
     // De waarden van regel A vergelijken met regel B.
    var lnValueA = parseFloat(poGridInstance._getColumnValue(loRowA.childNodes[poGridInstance._lnSorted]));
    var lnValueB = parseFloat(poGridInstance._getColumnValue(loRowB.childNodes[poGridInstance._lnSorted]));

    // Als de waardes overeenkomen dan `0` retourneren.
    if (lnValueA == lnValueB) {
      return 0;
    }
    
    // Als de waarde van A voor de waarde van B ligt dan `-1` retourneren.
    if (lnValueA < lnValueB) {
      return -1;
    }
    
    // Als de waarde van B voor de waarde van A ligt dan `1` retourneren.
    return 1;    
   },      
   
   /**
    * Sorteer functie die wordt aangeroepen vanuit de functie `doSort`. Als de
    * methode `sort` op een array wordt uitgevoerd dan wordt deze functie 
    * aangeroepen.
    * De functie vergelijkt 2 waarden met elkaar en geeft dan.
    *  . -1 terug als A voor B ligt.
    *  . 0 terug als de waardes gelijk zijn.    
    *  . 1 terug als B voor A ligt. 
    *
    * @param  loRowA
    * @param  loRowB
    * @return  Integer
    */   
   _doSortString : function(loRowA, loRowB) {
     // De waarden van regel A vergelijken met regel B.
    var lcValueA = poGridInstance._getColumnValue(loRowA.childNodes[poGridInstance._lnSorted]).toLowerCase();
    var lcValueB = poGridInstance._getColumnValue(loRowB.childNodes[poGridInstance._lnSorted]).toLowerCase();

    // Als de waardes overeenkomen dan `0` retourneren.
    if (lcValueA == lcValueB) {
      return 0;
    }
    
    // Als de waarde van A voor de waarde van B ligt dan `-1` retourneren.
    if (lcValueA < lcValueB) {
      return -1;
    }
    
    // Als de waarde van B voor de waarde van A ligt dan `1` retourneren.
    return 1;    
   },
   
   /**
    * De waarde uit een opgegeven kolom opvragen.
    *
    * @param  loColumn
    * @return  Undefined
    */   
    _getColumnValue : function(loColumn) {
      // Initieel leeg.
      var luValue = "";
      
    // Alle kinderen van de opgegeven kolom doorlopen.
    var laChildren = loColumn.childNodes;

    try {
      var lnChildren = laChildren.length;
      
      for(var lnI = 0; lnI < lnChildren; lnI++) {
        if(laChildren[lnI].tagName != "DIV") {
          if(laChildren[lnI].nodeValue.length != 0) {
            luValue = laChildren[lnI].nodeValue;
            break;
          }
        } else {
          luValue = this._getColumnValue(laChildren[lnI].childNodes);
        }      
      }
    } catch(e) {}
    
    // Waarde retourneren.
    return luValue;      
    },
    
  /**
   * Opschonen van het DOM (Data Object Model).
   * textNodes vallen binnen de set van Childnodes in FireFox.
   * Binnen IE worden ze genegeerd, om de verwerking hetzelfde te houden
   * worden de textNodes verwijdert als deze leeg zijn.
   *
   * @param  loNode
   */
  _cleanNodes : function(loNode) {
    // Alle kinderen opvragen.
    var loExpr   = /\S/;
    var lnNodes = loNode.childNodes.length;
      
    for(var lnI = 0; lnI < lnNodes; lnI++) {
      try {
        var loChildNode = loNode.childNodes[lnI];
        
        // Als de node een textnode is en leeg is dan verwijderen.
        if(loChildNode.nodeType == 3 && 
           !loExpr.test(loChildNode.nodeValue)) {
          loNode.removeChild(loNode.childNodes[lnI]);
        
          lnI--;
        }
        
        // Als de node kinderen kan hebben dan deze ook opschonen.
        if (loChildNode.nodeType == 1) {
          this._cleanNodes(loChildNode);
        }
      } catch(e) {}
    }
  },
   
   /**
    * Even en oneven regels een andere kleur geven. Tevens regels waar met de muis
    * overheen wordt bewogen een andere kleur geven.
    *
    * @param  loBody
    * @return  void
    */   
   _showLines : function(loBody) {
     // Alle regels doorlopen. 
     var lnShownRows = 0;
     var lnRows    = loBody.getElementsByTagName("div").length;
      
     for(var lnI = 0; lnI < lnRows; lnI++) {
       /**
        * Rownode opvragen.
        */
       var loRow = loBody.getElementsByTagName("div")[lnI];
       
       /**
        * Kolommen opnieuw kleuren.
        */
      if(loRow.className != "PPGridColumn") {
        /**
         * Alleen zichtbare kolommen opnieuwe kleuren.
         */
        if(loRow.style.display != "none") {
           // Even krijgt de class naam `Even`.
           // Oneven krijgt de class naam `Odd`.
          if((lnShownRows % 2) == 0) {
            loRow.className = 'Even';
          } else {
            loRow.className = 'Odd';
          }
          
          lnShownRows++;
        }
        
        /**
         * Een mouseover en mouseout event koppelen, hierdoor
         * verandert de kleur van de regel bij mousover.
         */
        loRow.onmouseover = function() {
          this.className = 'Hover';
        }
        
        // Als de muis van de regel af wordt bewogen dan de className
        // veranderen in het origineel.
        loRow.classOld = loRow.className;
              
        loRow.onmouseout = function(e) {
          this.className = this.classOld;        
        } 
      }
     }
   },

   /**
    * De mogelijkheid voor de gebruiker om tekst te selecteren onmogelijk maken
    * voor het opgegeven object.
    *
    * @param  loElement
    * @return  void
    */   
   _disableSelect : function(loElement) {
     // Functie toevoegen die wordt getriggered als er met de muis tekst
     // wordt geselecteerd.
     loElement.onselectstart = function() {
          return false;
      };
      
      // Voor alle browsers zorgen dat de tekst niet geselecteerd kan worden.
      loElement.unselectable       = "on";
      loElement.style.MozUserSelect   = "none";
      loElement.style.cursor       = "default";
   }
 };
