// Tri un tableau en fonction d'une colonne donnee
// Si l'une des colonnes du tableau est de classe 'sort_main', elle representera un critere de tri principal
function sortColumn(strId_P, iColumn_P)
{
  // la colonne de tri principale
  this.mainColumn;
  // la liste des colonnes servant de critere de tri
  this.sortList=[];
  
  this.table = document.getElementById(strId_P);
  this.arrayClassColor = ["bgWhite","bgBlue"];
  head=this.table.tHead.rows[0];

  // on cherche la colonne principale si elle n'est pas definie
  if (this.mainColumn==undefined)
  {
    var iColumn=0;
    
    // on cherche jusqu'a ce qu'il n'y est plus de colonnes ou que la colone principale est ete trouvee
    while(iColumn<head.cells.length && this.mainColumn==undefined)
    {
      if (head.cells[iColumn].className.search(/\bsort_main\b/) != -1)
      {
        this.mainColumn=getColumnInfo(iColumn);
      }

      iColumn++;
    }
  }
  else
  {
    // mise a jour des informations
    this.mainColumn=getColumnInfo(this.mainColumn[0]);
  }

  // si la colonne a triee n'est pas la colonne principale ou si cette derniere n'est pas definie
  if (this.mainColumn==undefined || this.mainColumn[0]!=iColumn_P)
  {
    // on recupere les informations de tri de la colonne...
    var arrayColumn=getColumnInfo(iColumn_P);
    // ...et on les ajoute a la sortList
    this.sortList.push(arrayColumn);
  }
  
  for(var i=0;i<head.cells.length;i++)
  {
    checkColumnClassName(i);
  }
  
  if (this.mainColumn!=undefined)
  {
    removeRowSpan();
  }
  
  multisort();
  
  if (this.mainColumn!=undefined)
  {
    addRowSpan();
  }
}

// Supprime la classe 'sorted' de chacune des colonnes
// puis l'ajoute le cas echeant
function checkColumnClassName(iColumn_P)
{
  // si la sortList est vide ou que la colonne iColumn_P n'est pas la colonne principale...
  if (this.sortList.length==0 || (this.mainColumn[0]!=undefined && this.mainColumn[0]!=iColumn_P))
  {
    //...on supprime la classe 'sorted'
    this.table.tHead.rows[0].cells[iColumn_P].className=this.table.tHead.rows[0].cells[iColumn_P].className.replace('sorted','');
  }

  // si la sortList est vide, qu'une colonne principale est definie, qu'elle correspond a la colonne iColumn_P
  // et que le tri doit etre croissant... 
  if (this.sortList.length==0 && this.mainColumn[0]!=undefined && this.mainColumn[0]==iColumn_P && this.mainColumn[1]==0)
  {
    //...on ajoute la classe 'sorted'
    this.table.tHead.rows[0].cells[iColumn_P].className+=' sorted';
  }
  else
  {
    var i=0;
    var bFind=false;
    
    // recherche si la colonne iColumn_P fait partie des colonnes a trier
    while(i<this.sortList.length && !bFind)
    {
      // recherche si la colonne iColumn_P fait partie des colonnes a trier
      if (this.sortList[i][0]==iColumn_P)
      {
        bFind==true;
        
        // ajout de la classe 'sorted' seulement si la colonne doit etre triee dans l'ordre croissant
        if (this.sortList[i][1]==0)
        {
          this.table.tHead.rows[0].cells[iColumn_P].className+=' sorted';
        }
      }
      
      i++;
    }
  }
}

// Retourne un tableau contenant le numero de la colonne et le sens du tri
function getColumnInfo(iColumn_P)
{
  // Le sens du tri a effectuer
  // Par defaut 0, acsendant
  // 1 pour descendant
  var iOrder_Ret=0;
  
  // Le type de tri a effectuer
  // Par defaut 0, texte
  // 1 pour numerique
  var iSortType_Ret=0;

  // si la colonne est triee dans l'ordre croissant, on la trie dans l'ordre decroissant
  if (this.table.tHead.rows[0].cells[iColumn_P].className.search(/\bsorted\b/) != -1)
  {
    iOrder_Ret=1;
  }

  // si la colonne est triee dans l'ordre croissant, on la trie dans l'ordre decroissant
  if (this.table.tHead.rows[0].cells[iColumn_P].className.search(/\bnumeric\b/) != -1)
  {
    iSortType_Ret=1;
  }

  return [iColumn_P,iOrder_Ret,iSortType_Ret];
}

// On supprime les rowspan de la premiere colonne de la table dont l'id est passe en parametre 
function removeRowSpan()
{
  var rows = this.table.tBodies[0].rows;
  
  var i=0;
  
  // parcours de l'ensemble des lignes du tableaux
  while (i<rows.length-1)
  {
    this.iRowSpan = rows[i].cells[this.mainColumn[0]].rowSpan;
    
    // si le rowspan est superieur a 1...
    if (this.iRowSpan>1)
    {
      // on le met a 1...
      rows[i].cells[this.mainColumn[0]].rowSpan=1;
      
      // ...et on ajoute une nouvelle cellule possedant les memes caracteristiques
      for(var j=i+1;j<i+this.iRowSpan;j++)
      {
        cell=rows[j].insertCell(0);
        cell.innerHTML=rows[i].cells[this.mainColumn[0]].innerHTML;
        cell.className=rows[i].cells[this.mainColumn[0]].className;
        cell.vAlign=rows[i].cells[this.mainColumn[0]].vAlign;
        cell.align=rows[i].cells[this.mainColumn[0]].align;
      }
    }
    
    i=i+this.iRowSpan;
  }
}

// On fusionne les cellules de meme contenu de la premiere colonne de la table dont l'id est passe en parametre
function addRowSpan()
{
  var rows = this.table.tBodies[0].rows;
  
  var i=0;
  
  // Nombre de sites differents (utilise pour l'affichage alternatif de couleur)
  var iSite=0;
  var iNbColor=this.arrayClassColor.length;
  
  while (i<rows.length)
  {
    var iRowSpan=rows[i].cells[this.mainColumn[0]].rowSpan;
    // insertion le nom de la classe couleur
    rows[i].className=this.arrayClassColor[iSite%iNbColor];
    
    // tant qu'il reste une ligne a lire et que les contenus des cellules de la colonne principale sont egaux  
    while (i+iRowSpan<rows.length && 
      rows[i].cells[this.mainColumn[0]].innerHTML==rows[i+iRowSpan].cells[this.mainColumn[0]].innerHTML)
    {
      // suppression de la cellule inutile 
      rows[i+iRowSpan].deleteCell(0);
      // insertion du nom de la classe couleur
      rows[i+iRowSpan].className=this.arrayClassColor[iSite%2];
      
      iRowSpan++;
    }
    
    // mise a jour de la valeur du rowspan
    rows[i].cells[this.mainColumn[0]].rowSpan=iRowSpan;
    
    // incrementation de la ligne a lire
    i=i+iRowSpan;
    iSite++;
  }
}

// Retourne la valeur correspondant au type type de tri iSortType_P pour l'ordre iOrder_P
function sortTd(a,b,iOrder_P,iSortType_P)
{
  // tri croissant
  if(iOrder_P==0)
  {
    // tri numerique
    if(iSortType_P==1)
    {
      return sortNumAsc(a,b);
    }
    else
    {
	    // tri textuel
      return sortTextAsc(a,b);
    }
  }
  else
  {
    // tri numerique
    if(iSortType_P==1)
    {
      return sortNumDesc(a,b);
    }
    else
    {
      // tri textuel
      return sortTextDesc(a,b);
    }
  }
}

// Tri de 2 nombres dans l'ordre croissant
// Retourne un nombre negatif si a doit etre avant b, un nombre positif si b doit etre avant a ou 0 si les 2 sont egaux
function sortNumAsc(a,b)
{
  return a-b;
};

// Tri de 2 nombres dans l'ordre decroissant
// Retourne un nombre negatif si b doit etre avant a, un nombre positif si a doit etre avant b ou 0 si les 2 sont egaux
function sortNumDesc(a,b)
{
  return b-a;
};

// Tri de 2 nombres dans l'ordre croissant
// Retourne -1 si a doit etre avant b, 1 si b doit etre avant a ou 0 si les 2 sont egaux
function sortTextAsc(a,b)
{
  if (a<b)
  {
    return -1;
  }
  else
  {
    if (a>b)
    {
      return 1;
    }
    else
    {
      return 0;
    }
  }
};

// Tri de 2 nombres dans l'ordre decroissant
// Retourne -1 si b doit etre avant a, 1 si a doit etre avant b ou 0 si les 2 sont egaux
function sortTextDesc(a,b)
{
  if (a>b)
  {
    return -1;
  }
  else
  {
    if (a<b)
    {
      return 1;
    }
    else
    {
      return 0;
    }
  }
};

// Retourne un tableau cache[row[[cell-1-1,...,cell-1-n],...],normalized[[cell1.contenu,...,celln.contenu,numero de la ligne],...]]
// Le sous-tableau row contient une copie de chacune des cellules du tableau qui permettra de restaurer les cellules correctement
// Le sous-tableau normalized sert a faciliter le tri
function buildCache()
{
  var totalCells = (this.table.tBodies[0].rows[0] && this.table.tBodies[0].rows[0].cells.length) || 0,
      totalRows = (this.table.tBodies[0] && this.table.tBodies[0].rows.length) || 0,
      cache = {row: [], normalized: []};
      
  for (var i=0;i < totalRows; ++i)
  {
    var c = this.table.tBodies[0].rows[i], 
        cols = [],
        row = [];

    for(var j=0; j < totalCells; ++j)
    {
      // creation d'une copie de la cellule
      var cell=document.createElement('td');
      cell.innerHTML=c.cells[j].innerHTML;
      cell.className=c.cells[j].className;
      cell.vAlign=c.cells[j].vAlign;
      cell.align=c.cells[j].align;
      
      // ajout de la cellule
      row.push(cell); 
      // ajout du contenu de la cellule
      cols.push(c.cells[j].innerHTML); 
    }
    
    // on stocke en cache la ligne generee
    cache.row.push(row);
    // on ajoute le numero de la ligne
    cols.push(i);
    // on stocke en cache la ligne de contenu generee
    cache.normalized.push(cols);
    cols = null;
  };
  
  return cache;
};

// Retourne -1 si a doit etre avant b, 1 si b doit etre avant a ou 0 si les 2 sont egaux
function sortRow(a,b)
{
  var iSort_Ret = 0;
  var iSortMain = 0;
  
  // si une colonne principale est definie, on compare les valeurs pour les 2 lignes  
  if (this.mainColumn!=undefined)
  {
    iSortMain=sortTd(a[this.mainColumn[0]], b[this.mainColumn[0]],this.mainColumn[1],this.mainColumn[2]);
  }

  // s'il existe un critere de tri
  if (this.sortList.length!=0)
  {
    // si la colonne principale n'est pas definie
    // ou si les 2 lignes ont la meme valeur pour la dite colonne...
	  if (iSortMain==0)
	  {
	    var i=0;
	
	    // ...on trie en fonction de chacune des colonnes de la sortList
	    // en s'arretant des que les lignes different
	    while(i<this.sortList.length && iSort_Ret==0)
	    {
        iSort_Ret=sortTd(a[this.sortList[i][0]], b[this.sortList[i][0]],this.sortList[i][1],this.sortList[i][2]);
	      
	      i++;
	    }
    }
  }
  else
  {
    iSort_Ret=iSortMain;
  }
  
  return iSort_Ret;
};

function multisort()
{
  // mise en cache du contenu du tableau
  var cache=buildCache();
  // tri du tableau
  cache.normalized.sort(sortRow);

  var totalRows = cache.normalized.length,
      totalCells = cache.normalized[0].length-1,  
      checkCell = (cache.normalized[0].length-1);

  // On efface toutes les lignes du tableau...
  for(var i=0;i<totalRows;i++)
  {
    this.table.tBodies[0].deleteRow(0);
  }
  
  // et on les reinserent triees
  for (var i=0;i<totalRows; i++)
  {
    var row = this.table.tBodies[0].insertRow(i);
    
    // creation des cellules de la ligne
    for(var j=0;j<totalCells;j++)
    {
	    var cell=row.insertCell(j);
	    
	    // remplissage des donnees de la cellule
	    cell.innerHTML=cache.row[cache.normalized[i][checkCell]][j].innerHTML;
      cell.className=cache.row[cache.normalized[i][checkCell]][j].className;
      cell.vAlign=cache.row[cache.normalized[i][checkCell]][j].vAlign;
      cell.align=cache.row[cache.normalized[i][checkCell]][j].align;
    }
  }
};
