/**
	pics.table.js
	Desc:	Framework für Tabellen-Funktionen

	basiert auf pics.base
	
	Author: Christian Grösswang
	
	20070221,gc - v0.01		Prototype + Test
	20080328,gc - v0.10		Umstellung auf tbodies+rows+cells
	20080329,gc - v0.20		Bessere sortierung, Berücksichtigung des Spaltentpys
	20080611,gc - v0.21		neue Funktion pics.Table.showAllRows
	20080829,gc - v0.22		neue Funktion pics.Table.showHideRows
**/




/*
	Funktionsübersicht 
	
		pics.Table 			Das Tabellen-Objekt
		pics.Table.sort		Tabelle Sortieren
		pics.Table.sortUp	Aktuelle Spalte in der Tabelle aufsteigend sortieren
		pics.Table.sortDown	Aktuelle Spalte in der Tabelle absteigend sortieren
*/

// Constructor, falls das PICS-Framework nicht geladen ist
	if (typeof pics == 'undefined') pics = {};

/* 
 *	====================================================================================
 *	===== FRAMEWORK: pics.Table													====
 *	====================================================================================
 */

 
/* ========================= Constructor ========================= */

	/**
	 * pics.Table
	 *	neues Table-Objekt erstellen
	 */
	pics.Table = function(pObject)
	{
		// parameter pruefen
		if (typeof pObject == 'undefined') 	return false;
		
		// ist es ein Objekt oder nur der Name?
		if (pObject.nodeName)
		{
			// jetzt mal die Werte alle merken
			this.Name=pObject.nodeName;
			// Tabellenbody holen
			this.object=pObject;
		}
		else
		{
			// jetzt mal die Werte alle merken
			this.Name=pObject;
			// Tabellenbody holen
			this.object=document.getElementById(this.Name);
		}

		// wenn wir noch nicht im Body sind, dann holen
	    if(this.object.nodeName != "TBODY") this.object = this.object.getElementsByTagName("TBODY")[0];
		// wenn wir keinen Body finden
		if(this.object.nodeName != "TBODY") return false;
		// Zeilen holen
		this.rows = this.object.rows;
		// Vergleichskritierium
		this.compareType = 'auto';

		// Anzahl der Zeilen setzen
		this.size = this.rows.length;
	}


/* ========================= Basis-Funktionen ========================= */
	
	var gSortLog="";
	
	/**
	 * pics.Table.sort
	 *	Tabelle nach der angegebenen Spalte Sortieren
	 *	@param	string	pObjectName		Name der Tabelle oder des TBodies
	 *	@param	string	pSortCol		zu sortierende Spalte
	 *	@param	string	pDesc			aufsteigend ( false ) oder absteigend ( true )
	 *	@param	string	pCompareType	vergleichstyp für Spalte, gültige werte sind auto, text, number, date
	 */
	pics.Table.sort = function(pObjectName, pSortCol, pDesc, pCompareType)
	{
		// parameter pruefen
		if (typeof pObjectName == 'undefined') 	return false;
		if (typeof pSortCol == 'undefined') 	pSortCol=0;
		if (typeof pDesc == 'undefined') 		pDesc=false;
		if (typeof pCompareType == 'undefined') pCompareType='auto';

		oTable=new pics.Table(pObjectName);

		gSortLog="";
		// jetzt mal die Werte alle merken
		oTable.sortcol=pSortCol;
		oTable.desc=pDesc;
		oTable.compareType = pCompareType;

		// jetzt ermitteln wir den Typ der Spalte, wenn compareType=auto
		if (oTable.compareType=='auto') oTable.compareType=oTable.getColType(oTable.sortcol);
		
		// jetzt sortieren
		oTable.quicksort(0,oTable.size);
		
	} // pics.Table.sort


	/**
	 * pics.Table.sortUp
	 *		Aktuelle Spalte in der Tabelle aufsteigend sortieren
	 *	@param	string	pObject			this des Links in der Kopfzeile der zu sortirenden Tabelle
	 */
	pics.Table.sortUp = function(pObject)
	{
		// parameter pruefen
		if (!pObject) 	return false;

		// Zelle und Tabelle ermitteln
		if (pObject.nodeName=='TD')
		{
			oTD=pObject;
		}
		else
		{
			oTD=pics.findParentID(pObject, 'TD') ;
		}
		if (!oTD) return false;
		lSortCol=oTD.cellIndex;
		// Tabelle suchen
		oTDTable=pics.findParentID(oTD, 'TABLE') ;
		
		oTable=new pics.Table(oTDTable);

		gSortLog="";
		// jetzt mal die Werte alle merken
		oTable.sortcol=lSortCol;
		oTable.desc=false;
		oTable.compareType=oTable.getColType(oTable.sortcol);
		
		// jetzt sortieren
		oTable.quicksort(0,oTable.size);
		
	} // pics.Table.sortUp

	
	/**
	 * pics.Table.sortDown
	 *		Aktuelle Spalte in der Tabelle absteigend sortieren
	 *	@param	string	pObject			this des Links in der Kopfzeile der zu sortirenden Tabelle
	 */
	pics.Table.sortDown = function(pObject)
	{
		// parameter pruefen
		if (!pObject) 	return false;

		// Zelle und Tabelle ermitteln
		if (pObject.nodeName=='TD')
		{
			oTD=pObject;
		}
		else
		{
			oTD=pics.findParentID(pObject, 'TD') ;
		}
		if (!oTD) return false;
		lSortCol=oTD.cellIndex;
		// Tabelle suchen
		oTDTable=pics.findParentID(oTD, 'TABLE') ;
		
		oTable=new pics.Table(oTDTable);

		gSortLog="";
		// jetzt mal die Werte alle merken
		oTable.sortcol=lSortCol;
		oTable.desc=true;
		oTable.compareType=oTable.getColType(oTable.sortcol);
		
		// jetzt sortieren
		oTable.quicksort(0,oTable.size);
//		oTable.shakersort();
		
	} // pics.Table.sortDown


// ========================= ZEILEN VERSCHIEBEN ==========================

	/**
	 * pics.Table.moveUp
	 *		Aktuelle Zeile in der Tabelle nach oben schieben
	 *	@param	string	pObject			this des Links 
	 *	@param	string	pField			ID des Felds mit der Position
	 */
	pics.Table.moveUp = function(pObject,pField)
	{
		// parameter pruefen
		if (!pObject) 	return false;
		if (typeof pField == 'undefined') 	pField='';

		// Zeile und Tabelle finden
		oTR=pics.findParentID(pObject, 'TR') ;
		if (!oTR) return false;
		// Aktuelle Zeile merken
		lPos=oTR.sectionRowIndex;
		// weiter rauf geht nicht
		if (lPos==0) return false;
		// Tabelle suchen
		oTRTable=pics.findParentID(oTR, 'TABLE') ;
		oTable=new pics.Table(oTRTable);
		oTable.exchangeRow(lPos, lPos-1);
		// wenn ein Feld angegeben, dann tragen wir jetzt noch die Positionen ein
		if (pField!='')
		{
			oField=pics.findElementsById(oTable.rows[lPos], pField);
			oField.value=lPos;
			oField=pics.findElementsById(oTable.rows[lPos-1], pField);
			oField.value=lPos-1;
		}
		
	} // pics.Table.moveUp

	
	/**
	 * pics.Table.moveDown
	 *		Aktuelle Zeile in der Tabelle nach unten schieben
	 *	@param	string	pObject			this des Links 
	 *	@param	string	pField			ID des Felds mit der Position
	 */
	pics.Table.moveDown = function(pObject,pField)
	{
		// parameter pruefen
		if (!pObject) 	return false;

		// Zeile und Tabelle finden
		oTR=pics.findParentID(pObject, 'TR') ;
		if (!oTR) return false;
		// Aktuelle Zeile merken
		lPos=oTR.sectionRowIndex;
		// Tabelle suchen
		oTRTable=pics.findParentID(oTR, 'TABLE') ;
		oTable=new pics.Table(oTRTable);
		// weiter runter geht nicht
		if (lPos>=oTable.rows.length-1) return false;


		oTable.exchangeRow(lPos, lPos+1);
		// wenn ein Feld angegeben, dann tragen wir jetzt noch die Positionen ein
		if (pField!='')
		{
			oField=pics.findElementsById(oTable.rows[lPos], pField);
			oField.value=lPos;
			oField=pics.findElementsById(oTable.rows[lPos+1], pField);
			oField.value=lPos+1;
		}
		
	} // pics.Table.moveDown
	
		
// ========================= ALLGEMEINE METHODEN =========================

	/**
	 * pics.Table.prototype.version
	 *	Versionsnummer
	 */
	pics.Table.prototype.version = function()
	{
		return "pics.sortTable v1.0 / 2007-02-21";
	}

	/**
	 * pics.Table.prototype.quicksort
	 *	Tabelle sortieren
	 */
	pics.Table.prototype.quicksort = function(pLeft,pRight)
	{
		gSortLog+='<br> QS ('+pLeft+','+pRight+')<br> ';
		// Überschneidung, dann fertig
	    if(pRight <= pLeft+1) return;
	    if((pRight - pLeft) == 2) 
		{
	      	if (this.compare(this.getCellValue(pRight-1), this.getCellValue(pLeft))) this.exchangeRow(pRight-1, pLeft);
	      	return;
	    }
		
		// weiter rein
	    var i = pLeft + 1;
	    var j = pRight - 1;
	
	    if(this.compare(this.getCellValue(pLeft), this.getCellValue(i))) 		this.exchangeRow(i, pLeft);
	    if(this.compare(this.getCellValue(j), 	 this.getCellValue(pLeft))) 	this.exchangeRow(pLeft, j);
	    if(this.compare(this.getCellValue(pLeft), this.getCellValue(i))) 	 	this.exchangeRow(i, pLeft);
	
	    lCurrentCell = this.getCellValue(pLeft);

	    while(true) 
		{
	      j--;
	      while(this.compare(lCurrentCell, this.getCellValue(j))) j--;
	      i++;
	      while(this.compare(this.getCellValue(i), lCurrentCell)) i++;
	      if(j <= i) break;
	      this.exchangeRow(i, j);
	    }
	
	    this.exchangeRow(pLeft, j);
	
	    if((j-pLeft) < (pRight-j)) 
		{
	      this.quicksort(pLeft, j);
	      this.quicksort(j+1, pRight);
	    } 
		else 
		{
	      this.quicksort(j+1, pRight);
	      this.quicksort(pLeft, j);
	    }

	} // pics.Table.prototype.quicksort

	
	/**
	 * pics.Table.prototype.shakersort
	 *	Tabelle sortieren
	 */
	pics.Table.prototype.shakersort = function()
	{
	    // A stable sort function to allow multi-level sorting of data
	    // see: http://en.wikipedia.org/wiki/Cocktail_sort
	    // thanks to Joseph Nahmias
	    var b = 0;
	    var t = this.size - 1;
	    var swap = true;
		
	    while(swap) 
		{
			swap = false;
		    for(var i = b; i < t; ++i) 
			{
			    if(this.compare(this.getCellValue(i), this.getCellValue(i+1)))
				{
					this.exchangeRow(i, i+1);
	                swap = true;
	            }
	        } // for
	        t--;

	        if (!swap) break;
		
	        for(var i = t; i > b; --i) 
			{
			    if(this.compare(this.getCellValue(i), this.getCellValue(i-1))) 		
				{
					this.exchangeRow(i, i-1);
	                swap = true;
	            }
	        } // for
	        b++;
		
		} // while(swap)
	} // pics.Table.prototype.shakersort
	
	/**
	 * pics.Table.prototype.getCell
	 *	Wert einer Zelle liefern
	 */
	pics.Table.prototype.getCell = function(pRow,pCol)
	{
		if (typeof pCol == 'undefined') 	pCol=this.sortcol;
	
	    var oNode = this.rows[pRow].cells[pCol];    
		
		return this.getValue(oNode);
	} // pics.Table.prototype.getCell


	/**
	 * pics.Table.prototype.getCellValue
	 *		typ-richtigen Wert einer Zelle liefern
	 */
	pics.Table.prototype.getCellValue = function(pRow,pCol)
	{
		if (typeof pCol == 'undefined') 	pCol=this.sortcol;
		
		if (!this.rows[pRow]) alert(pRow+'/'+pCol+'/'+this.size);
	
	    var oNode = this.rows[pRow].cells[pCol];    
		var lValue=this.getValue(oNode);
		switch(this.compareType)
		{
			case 'date':
				lValue=pics.convertDate(lValue);
				break;
			case 'number':
				lValue=1*lValue;
				break;
		}
		
		return lValue;
	} // pics.Table.prototype.getCellValue

	
	/**
	 * pics.Table.prototype.getValue
	 *	Wert eines Objekts liefern
	 */
	pics.Table.prototype.getValue = function(pObject)
	{
	    var oNode = pObject
		
		if (!oNode) return oNode;
		
		// sind Input-Felder vorhanden
		if (!oNode.getElementsByTagName("INPUT"))
		{
			hasInputs=false;
		}
		else
		{
			hasInputs=(oNode.getElementsByTagName("INPUT").length>0);
		}
		
		// Inhalt abhängig von den Eigenschaften liefern
	    if (typeof oNode.textContent != 'undefined' && !hasInputs) 
		{
			lReturn=oNode.textContent;
	    }
	    else if (typeof oNode.innerText != 'undefined' && !hasInputs) 
		{
			lReturn=oNode.innerText;
	    }
	    else if (typeof oNode.text != 'undefined' && !hasInputs)  
		{
			lReturn=oNode.text;
	    }
	    else 
		{
			switch (oNode.nodeType) 
			{
		    	case 3:
					if (oNode.nodeName.toLowerCase() == 'input') 
					{
		            	lReturn=oNode.value;
		          	}
					else
					{
		            	lReturn=oNode.nodeValue;
		          	}
					break;
		        case 4:
		          	lReturn=oNode.nodeValue;
					break;
		        case 1:
		        case 11:
		          	lReturn = '';
		          	for (var i=0; i<oNode.childNodes.length; i++) 
					{
		            	lReturn += this.getValue(oNode.childNodes[i]);
					}
					break;
		      } // switch
	    } // else
		
		return lReturn.replace(/^\s+|\s+$/g, '');
	} // pics.Table.prototype.getValue
	
	
	/**
	 * pics.Table.prototype.exchangeRow
	 *	2 Zeilen vertauschen
	 */
	pics.Table.prototype.exchangeRow = function(pRow1, pRow2)
	{
		gSortLog+='---- ER ('+pRow1+','+pRow2+')<br> ';
		if(pRow1 == pRow2+1) 
		{
	      this.object.insertBefore(this.rows[pRow1], this.rows[pRow2]);
	    } 
		else if(pRow2 == pRow1+1) 
		{
	      this.object.insertBefore(this.rows[pRow2], this.rows[pRow1]);
	    } 
		else 
		{
	      var oRow = this.object.replaceChild(this.rows[pRow1], this.rows[pRow2]);
	      if(typeof(this.rows[pRow1]) == "undefined") 
		  {
	        this.object.appendChild(oRow);
	      } 
		  else 
		  {
	        this.object.insertBefore(oRow, this.rows[pRow1]);
	      }
	    }
	} // pics.Table.prototype.exchangeRow

	/**
	 * pics.Table.prototype.compare
	 *	2 Werte vergleichen
	 */
	pics.Table.prototype.compare = function(pValue1, pValue2)
	{
		var lComp=(this.desc) ? pValue1 > pValue2 : pValue1 < pValue2;
		gSortLog+='-- CP ('+pValue1+','+pValue2+'='+lComp+')<br> ';
	    return lComp;
	} // pics.Table.prototype.compare


	/**
	 * pics.Table.prototype.compareOLD
	 *	2 Werte vergleichen
	 */
	pics.Table.prototype.compareOLD = function(pValue1, pValue2)
	{
		gSortLog+='-- CP ('+pValue1+','+pValue2+'='+((this.desc) ? pValue1 > pValue2 : pValue1 < pValue2)+')<br> ';
	    return (this.desc) ? pValue1 > pValue2 : pValue1 < pValue2;
	} // pics.Table.prototype.compare
	
	
	/**
	 * pics.Table.prototype.getColType
	 *	ermittelt den Datentyp der Spalte
	 *	@return text, number, date ,mixed
	 */
	pics.Table.prototype.getColType = function(pCol)
	{
		lType='';
		// alle Zeilen in dieser Spalte durchlaufen und den Datentyp ermitteln
		for (var i=0;i<this.size;i++)
		{
			lNewType='';
			lValue=this.getCell(i,pCol);
			if (lValue!="")
			{
//				alert(i+':'+pCol+'='+lValue+' date='+pics.isDate(lValue));
				// ist es eine Zahl?
				if (pics.isDate(lValue))
				{
					lNewType='date';
				}
				else if (lValue.match(/^-?[£$¤]?[\d,.]+%?$/)) 
				{
					lNewType='number';
				}
				else
				{
					lNewType='text';
				}
				// ist der Typ gleich dem letzten
				if (lType!='' && lType!=lNewType) return 'mixed';
				lType=lNewType;
			}
		} // for
	    return lType;
	} // pics.Table.prototype.getColType


	/**
	 * pics.Table.prototype.setRowStyle
	 *		Stil einer Tabellenzeile ändern
	 *	@param	object	pRow		Objekt der Zeile
	 *	@param	string	pNewStyle	Neuer Stil
	 *	@return	
	 */
	pics.Table.setRowStyle = function(pRow,pNewStyle)
	{
		// Aktuellen Stil auslesen und alle anderen Formatierungen entfernen außer wenn Aktiv
		var aktStyle = pRow.className.replace(/Hover/,"");
		
		switch (pNewStyle)
		{
			case "changed":
				if (aktStyle.indexOf("Changed")==-1) aktStyle+="Changed";
				break;
			case "normal":
				aktStyle=aktStyle.replace(/Changed/,"").replace(/Active/,"");
				break;
			case "over":
				if (aktStyle.indexOf("Active")==-1 && aktStyle.indexOf("Changed")==-1) aktStyle+="Hover";
				break;
			case "out":
				break;
			case "click":
				if (aktStyle.indexOf("Active")==-1) aktStyle=aktStyle.replace(/Hover/,"")+"Active";
				else aktStyle=aktStyle.replace(/Active/,"");
				break;
		}
		pRow.className = aktStyle;
	} // pics.Table.setRowStyle

	
	/**
	 * pics.Table.prototype.showAllRows
	 *		ausgeblendete Tabellenzeilen anzeigen
	 *	@param	string	pTableID	ID der Tabelle
	 *	@return	
	 */
	pics.Table.showAllRows = function(pTableID)
	{
		// Scrollposition merken
		gScrollPos=document.documentElement.scrollTop;
		oTable=document.getElementById(pTableID);
		for (var i=0;i<oTable.rows.length;i++)
		{
			oTable.rows[i].style.display='';
		}
		// und wieder zurückscrollen
		window.scrollTo(0,gScrollPos);
	} // pics.Table.showAllRows
	

	/**
	 * pics.Table.prototype.showHideRows
	 *		Tabellenzeilen mit dem angegeben Attribut anzeigen und andere ausblenden
	 *	@param	string	pTableID	ID der Tabelle
	 *	@param	string	pValue		Wert, der enthalten sein muss
	 *	@param	string	pAttrib		Attribut, standard ist group
	 *	@return	
	 */
	pics.Table.showHideRows = function(pTableID, pValue, pAttrib)
	{
		if (typeof pAttrib == 'undefined') 	pAttrib='group';
		// Scrollposition merken
		gScrollPos=document.documentElement.scrollTop;
		oTable=document.getElementById(pTableID);
		for (var i=0;i<oTable.rows.length;i++)
		{
			// nur zeilen, die dieses Attribut haben
			if (oTable.rows[i].attributes[pAttrib])
			{
				if (oTable.rows[i].attributes[pAttrib].value.indexOf(pValue)>=0)
				{
					oTable.rows[i].style.display='';
				} // if
				else
				{
					oTable.rows[i].style.display='none';
				} // else
			} // if
		} // for
		// und wieder zurückscrollen
		window.scrollTo(0,gScrollPos);
	} // pics.Table.showAllRows
	

	/**
	 * pics.Table.prototype.setRowMarker
	 *		Marker-Combobox und Stil einer Tabellenzelle ändern
	 *	@param	object	pRowID		ID der Zeile
	 *	@param	bool	pActive		neuer Status
	 */
	pics.Table.setRowMarker = function(pRowID,pActive)
	{
		// Checkbox aktivieren
		var oCB = document.getElementsByName("fMarker[]")[pRowID];
		lChecked = pActive ? true : oCB.checked;
		oCB.checked = lChecked;
		
		// Zeile einfärben
		this.setRowStyle(pRowID,(lChecked ? "changed" : "normal"));
	} // pics.Table.prototype.setRowMarker
	
	
/* ========================= globle Hilfsfunktionen ========================= */

