function TableGenerator(data, id, opts){
  this.headerRow = data[0].row;
  this.data = data.slice(1, data.length);
  this.id = id;
  this.divId = id;
  this.position = 0;
  this.currentSort = 0;
  this.currentSortType = 1; //Defaults to Asc
  
  if(opts){
    this.opts = opts;
  }else{
	this.opts = new Object();
  }
  
  // Initialize the options.
  if(!this.opts.cellpadding){
    this.opts.cellpadding  = '0';
  }
  if(!this.opts.cellspacing){
    this.opts.cellspacing  = '0';
  }
  if(!this.opts.border){
    this.opts.border       = '0';
  }
  if(!this.opts.width){
    this.opts.width        = '0';
  }
  if(!this.opts.rowsPerPage){
    this.opts.rowsPerPage  = '0';
  }
  if(!this.opts.mainClass){
    this.opts.mainClass    = '';
  }
  if(!this.opts.oddClass){
    this.opts.oddClass     = '';
  }
  if(!this.opts.evenClass){
    this.opts.evenClass    = '';
  }
  if(!this.opts.headingClass){
    this.opts.headingClass = '';
  }
  if(!this.opts.prependCountText){
    this.opts.prependCountText = '';
  }
  if(!this.opts.prependCountText){
    this.opts.rowRemoveLabel = 'Remove';
  }
  if(!this.opts.noDataMessage){
    this.opts.noDataMessage = "No data to display";
  }
}

function renderHtml(table, direction, name){
	//alert(table+" "+direction+" "+name);
  var data = table.data;
  var html = "";
  if(name==null)
    name='table';
  var tableStart = "<table ";
  tableStart += "cellpadding='"+table.opts.cellpadding+"' ";
  tableStart += "cellspacing='"+table.opts.cellspacing+"' ";
  tableStart += "border='"+table.opts.border+"' ";
  if(table.opts.mainClass){
    tableStart += "class='"+table.opts.mainClass+"' ";
  }
  if(table.opts.width){
    tableStart += "width='" + table.opts.width + "' ";
  }
  tableStart += ">";
  html += tableStart;
  
  var start,end = 0;
  if(direction == "next"){
    table.position += table.opts.rowsPerPage;
  }else if(direction == "prev"){
    table.position -= table.opts.rowsPerPage;
  }
  if(table.opts.rowsPerPage > 0){
    start = table.position;
    end   = table.position + table.opts.rowsPerPage;
    if(end > data.length){
      end = data.length;
    }
  }else{
    start = 0;
    end   = data.length;
  }

  if(table.headerRow){
    html += "<tr class='" + table.opts.headingClass + "'>";
    for(var i=0; i < table.headerRow.length; ++i){

      var disableSort = false;
      if(table.opts.disableSortColumns){
        for(var j=0; j<table.opts.disableSortColumns.length; ++j){
          if(i == table.opts.disableSortColumns[j]){
            disableSort = true;
            break;
          }
        }
      }
      
      if(disableSort){
        html += "<td nowrap>" + table.headerRow[i] + "</td>";
      }else{
	    if(table.currentSort == i){
		  var image = "";
		  if(table.currentSortType > 0){
		    html += "<td nowrap><a href=\"javascript: "+name+".sortByColumnDesc('" + i + "', '" + name + "');\">" + table.headerRow[i] + "</a>&nbsp;<a href=\"javascript: "+name+".sortByColumnDesc('" + i + "', '" + name + "');\">";
		    image = table.opts.sortArrowUp;
		  }else{
	        html += "<td nowrap><a href=\"javascript: "+name+".sortByColumnAsc('" + i + "', '" + name + "');\">" + table.headerRow[i] + "</a>&nbsp;<a href=\"javascript: "+name+".sortByColumnAsc('" + i + "', '" + name + "');\">";
		    image = table.opts.sortArrowDown;
		  }
	      html += "<img src='" + image + "' border='0'>";
	    }else{
		  html += "<td nowrap><a href=\"javascript: "+name+".sortByColumnAsc('" + i + "', '" + name + "');\">" + table.headerRow[i];
	    }
	    html += "</a></td>";
	  }
    }
    
    if(table.opts.enableRowRemove){
      html += "<td width='1%'>&nbsp;</td>";
    }
    
    html += "</tr>";
	if(table.displayFilters){
	  html += "<tr>";
      var filts = new Array(table.headerRow.length);
      for(var i=0; i<table.data.length; ++i){
        var row = table.data[i].row;
	    for(var j=0; j<table.headerRow.length; ++j){
		  if(contains(table.filterColumns, j)){
	        if(!filts[j]){
	          filts[j] = new Array();
	        }
		    if(!contains(filts[j], row[j])){
	          filts[j].push(row[j]);
		    }
		  }else{
		    filts[j] = null;
		  }
	    }
      }

	  for(var k=0; k < table.headerRow.length; ++k){
          html += "<td class='" + table.opts.filterClass + "'>";
		  if(filts[k]){
		    html += "<select multiple size='4'><option selected>All</option>";
		    filts[k].sort();
	        for(var j=0; j<filts[k].length; ++j){
	          html += "<option>" + filts[k][j] + "</option>";
	        }
		    html += "</select>";
		  }else{
		    html += "&nbsp;";
		  }
		
	      html += "</td>";  
	  }
	
	  if(table.opts.enableRowRemove){
        html += "<td>&nbsp;</td>";
      }
	
      html += "</tr>";
	}
  }

  // Always display the first row.
  var oldstart = start;
  for(var i = start ; i < end ; i++){
    var row = data[i].row;
    var rowStart = "<tr ";
    if(table.opts.evenClass && table.opts.oddClass){
      if(i % 2 == 0){
        rowStart += "class='"+table.opts.evenClass+"'";
      }else{
        rowStart += "class='"+table.opts.oddClass+"'";
      }
    }
    rowStart += ">";
    html += rowStart;
    for(var j = 0 ; j < row.length ; j++){
      var cellStart = "<td ";
	  if(data[i]["cell"+ j +"Class"]){
	    cellStart += "class='" + data[i]["cell" + j + "Class"] + "'";
	  }
      cellStart += ">";
      var cellEnd   = "</td>";
      if(row[j] && row[j] != 'null'){
        html += cellStart + row[j] + cellEnd;
      }else{
        html += cellStart + "&nbsp;" + cellEnd;
      }
    }
    
    if(table.opts.enableRowRemove){
      html += "<td><input type='button' value='" + table.opts.rowRemoveLabel
            + "' onClick='" + table.id + ".removeRow(" + i + "); " + table.id + ".refresh();'></td>"
    }
    
    var rowEnd = "</tr>";
    html += rowEnd;
    if(i == 0){
      i = oldstart;
    }
  }
  if(end - start < 1){
    html += "<tr><td colspan='" + table.headerRow.length + "' align='center'>" + table.opts.noDataMessage + "</td></tr>";
  }
//  position = end + 1;

  var tableEnd = "</table>";
  html += tableEnd;
  return html;
}

TableGenerator.prototype.setFilterColumns = function(filtColumns){
  this.filterColumns = filtColumns;
}

TableGenerator.prototype.checkFilter = function(row){
  // If an unmatched item in row is found return false, otherwise return true.
  
}

TableGenerator.prototype.toggleFilters = function(){
  if(this.displayFilters){
    this.displayFilters = false;
  }else{
	this.displayFilters = true;
  }
  this.display();
}


TableGenerator.prototype.display = function(direction, name){
  //alert(direction +" "+ name);
	var html = renderHtml(this, direction, name);
  var max = this.position + this.opts.rowsPerPage;
  if(max > this.data.length - 1 ){
    max = this.data.length;
  }
  if(this.data.length > 0){
    html = this.opts.prependCountText + (this.position + 1) + " - "
          + max + " of " + (this.data.length) + ".<br>" + html;
  }

  document.getElementById(this.divId).innerHTML = html;
  
  var cntrWin = document;
  if(this.opts.externalControl){
    cntrWin = this.opts.externalControl;
  }
    
  if(cntrWin.getElementById(this.id + "next")){
    if(this.position < 1){
      cntrWin.getElementById(this.id + "prev").disabled = true;
    }else{
      cntrWin.getElementById(this.id + "prev").disabled = false;
    }

    if(this.position + this.opts.rowsPerPage > this.data.length - 1){
      cntrWin.getElementById(this.id + "next").disabled = true;
    }else{
      cntrWin.getElementById(this.id + "next").disabled = false;
    }
  }
}



function contains(list, val){
  if(list){
    for(var i=0; i<list.length; ++i){
      if(list[i].toString() == val.toString()){
	    return true;
	  }
    }
  }
  return false;
}

TableGenerator.prototype.sortByColumnAsc = function(i, tablename){
  if((this.data.length > 0) && (this.data[0].row.length > 0)){
    if(typeof this.data[0].row[i] == "string"){
      this.data.sort(function(a,b){
        if(a.row[i] > b.row[i]){
	      return 1;
	    }else if (a.row[i] < b.row[i]){
	      return -1;
	    }else{
	      return 0;
  	    }
      });
	}else{
	  this.data.sort(function(a,b){
	    return a.row[i]-b.row[i];
	  });
	}
  }
  this.currentSort = i;
  this.currentSortType = 1;
  this.display(null, tablename);
}

TableGenerator.prototype.sortByColumnDesc = function(i, tablename){
  if((this.data.length > 0) && (this.data[0].row.length > 0)){
    if(typeof this.data[0].row[i] == "string"){
      this.data.sort(function(a,b){
        if(a.row[i] < b.row[i]){
	      return 1;
	    }else if (a.row[i] > b.row[i]){
	      return -1;
	    }else{
	      return 0;
  	    }
      });
	}else{
	  this.data.sort(function(a,b){
	    return b.row[i]-a.row[i];
	  });
	}
  }
  this.currentSort = i;
  this.currentSortType = -1;
  this.display(null, tablename);
}

TableGenerator.prototype.setPosition = function(pos){
  this.position = pos;
}

TableGenerator.prototype.quickAddRow = function(hash){
  var length = this.data.length;
  hash.id = length;
  this.data[length] = hash;
}

TableGenerator.prototype.addRow = function(hash){
  this.quickAddRow(hash);
  this.refresh();
}

TableGenerator.prototype.removeById = function(id){
  var tmp = "";
  for(var i=0; i<this.data.length; ++i){
    tmp += this.data[i].id + "|" + id + "\n";
    if(this.data[i].id == id){
      this.removeRow(i);
      break;
    }
  }
  this.refresh();
}

TableGenerator.prototype.removeRow = function(rowNum){
  if(this.data.length > 1){
    this.data = this.data.slice(0,rowNum).concat(this.data.slice(rowNum+1));
  }else if(this.data.length == 1){
    this.data = [];
  }
}

TableGenerator.prototype.clear = function(){
  this.data = [];
}

TableGenerator.prototype.refresh = function(){
  if(this.currentSortType < 0){
    this.sortByColumnDesc(this.currentSort);
  }else{
    this.sortByColumnAsc(this.currentSort);
  }
}
