function SortableCheckTable(tablename,options) {
   this.tablename = tablename;
   this.dom = document.createElement("div");
   this.table = document.createElement("table");
   this.table.id=tablename;
   this.table.className="SortableTable";
   this.dom.appendChild(this.table);
   this.options = {};

   this.setOptions(options);

   this.h = document.createElement("thead");
   this.b = document.createElement("tbody");
   this.ccch = [];
   this.movch = [];
   this.mooch = [];
   this.rcch = [];
   this.numrows = 0;
   this.checkcount = 0;
   this.lastrow = "even";

   /* Create Header Checkbox Node */
   this.hcheck = document.createElement("input");
   this.hcheck.type = "checkbox";
   this.hcheck.checked= "CHECKED";
    GEvent.addDomListener(this.hcheck,'click',function(event) {
        var parent = this.parentNode.parentNode.parentNode.nextSibling;
        pcheck = this.checked; 
        for ( var i = 0; i < parent.childNodes.length; i++ ) {
            var c = parent.childNodes[i].firstChild.firstChild;
            if ( c.checked != pcheck ) {
                c.checked = !c.checked;
                GEvent.trigger(c,'click',c);
            }
        }
    });


   this.cnode = document.createElement("td");
   var ccheck = document.createElement("input");
   ccheck.type = "checkbox";
   ccheck.checked = "CHECKED";
   this.cnode.appendChild(ccheck);
   
   var checkcol = document.createElement("td");
   checkcol.style.width = "20px";
   checkcol.sortable = false;
   checkcol.className="normal";
   this.hrow = document.createElement("tr");
   this.h.appendChild(this.hrow);
   this.hrow.appendChild(checkcol);
   checkcol.appendChild(this.hcheck);
}

SortableCheckTable.prototype.setOptions = function(options) {
    if ( typeof(options) == "undefined" ) return;
    if ( typeof(this.options) == "undefined" ) this.options = {};
    for (var key in options) {
        this.options[key] = options[key];
    }
}


SortableCheckTable.prototype.setHeaders = function(headers) {
    this.headers = headers;
    var h = this.hrow.childNodes;
    for ( var i = h.length-1; i > 1; i-- ) {
        h[i].parentNode.removeChild(h[i]);
    }
    for ( var i = 0; i < headers.length; i++ ) {
        var hel = document.createElement("td");
        hel.sortable = true;
        hel.id = "st_" + (i+1) + "_" + this.tablename;
        hel.className="normal";
        hel.innerHTML = headers[i];
        this.hrow.appendChild(hel);
    }
}


SortableCheckTable.prototype.setMouseoverCallback = function(callback) {
    this.mouseovercallback = callback;
    for ( var i = 0; i < this.movch.length; i++ ) {
        GEvent.removeListener(this.movch[i]);
        GEvent.removeListener(this.mooch[i]);
    }

    for ( var i = 0; i < this.numrows; i++ ) {
        this.movch[i] = GEvent.addDomListener(this.b.childNodes[i],'mouseover',this.mouseovercallback);
        this.mooch[i] = GEvent.addDomListener(this.b.childNodes[i],'mouseout',this.mouseovercallback);
    }

}

SortableCheckTable.prototype.setRowClickCallback = function(callback) {
    this.rowclickcallback = callback;

    for ( var i = 0; i < this.rcch.length; i++ ) {
        GEvent.removeListener(this.rcch[i]);
    }

    this.rcch = [];
    for ( var i = 0; i < this.numrows; i++ ) {
        this.b.childNodes[i].style.cursor="pointer";
        this.rcch[i] = GEvent.addDomListener(this.b.childNodes[i],'click',this.rowclickcallback);
    }

}

SortableCheckTable.prototype.setCheckboxCallback = function(callback) {
    this.checkcallback = callback;

    for ( var i = 0; i < this.ccch.length; i++ ) {
        GEvent.removeListener(this.ccch[i]);
    }
     
    this.ccch = [];
    for ( var i = 0; i < this.numrows; i++ ) {
        this.ccch[i] = GEvent.addDomListener(this.b.childNodes[i].firstChild.firstChild,'click',this.checkcallback);
    }
}

SortableCheckTable.prototype.setCaption = function(caption) {
    if ( caption ) {
        this.caption = caption;
        if ( this.captionel ) this.dom.removeChild(this.captionel);
        this.captionel = document.createElement("caption");
        this.captionel.innerHTML = caption;
        if (this.options['collapsible']) {
            var sct = this;
            sct.captionel.className = "expanded";
            sct.captionel2 = document.createElement("div");
            sct.captionel2.innerHTML = this.captionel.innerHTML;
            sct.captionel2.className = "collapsed_sct";
            this.dom.appendChild(sct.captionel2);

            // Note: ie8 is to blame for all of this collapse 
            // and expand code for its poor table rendering.  
            var collapse = function() {
                sct.state = 'collapsed';
                sct.table.style.display = "none";
                sct.captionel2.style.display = "block";
            }

            var expand = function() {
                sct.state = 'expanded';
                sct.table.style.display = "block";
                sct.captionel2.style.display = "none";
            }

            if (this.options['collapsed']) {
                collapse();
            } else {
                expand();
            }
            GEvent.addDomListener(this.captionel2,'click',function() {
                expand();
            });
            GEvent.addDomListener(this.captionel,'click',function() {
                collapse();
            });
        }
        this.table.appendChild(this.captionel);
    }
}

SortableCheckTable.prototype.addRow = function(row) {
    this.rows += row;
    this.lastrow = this.lastrow=="even"?"odd":"even";
    
    var rowel = document.createElement("tr");
    rowel.className=this.lastrow;

    var checkcol = this.cnode.cloneNode(true);
    checkcol.firstChild.checked = row[0];
    this.checkcount += row[0];
    rowel.appendChild(checkcol);

    for ( var i = 1; i < row.length; i++ ) {
        var col = document.createElement("td");
        col.innerHTML = row[i];
   
        rowel.appendChild(col);
    }

    this.b.appendChild(rowel);
    this.numrows += 1;
    if ( (this.checkcount != this.numrows) && this.hcheck.checked ) {
        this.hcheck.checked = false;
    }

    if ( this.checkcallback ) {
        this.ccch += GEvent.addDomListener(checkcol.firstChild,'click',this.checkcallback);
    }

    if ( this.rowclickcallback ) {
        this.rcch += GEvent.addDomListener(rowel,'click',this.rowclickcallback);
    }
    if ( this.mouseovercallback ) {
        rowel.style.cursor="pointer";
        this.movch += GEvent.addDomListener(rowel,'mouseover',this.mouseovercallback);
        this.mooch += GEvent.addDomListener(rowel,'mouseout',this.mouseovercallback);
    }

    return this.numrows-1;
}

SortableCheckTable.prototype.deleteRows = function() {
    this.movch = [];
    this.mooch = [];
    this.ccch = [];
    this.rcch = [];
    this.numrows = 0;
    for ( var i = this.b.childNodes.length-1; i > -1; i-- ) {
        GEvent.clearNode(this.b.childNodes[i]); 
        this.b.removeChild(this.b.childNodes[i]); 
    }
}

SortableCheckTable.prototype.setSortColumns = function(primary,secondary) {
    if ( this.sortrep ) {
        this.sortrep.sortColumn=typeof(primary)!=="undefined"?primary:0;
        this.sortrep.secondarySortColumn=typeof(secondary)!=="undefined"?secondary:1;
        //GEvent.trigger(this.hrow.childNodes[primary],'click');
    }
}

SortableCheckTable.prototype.toDom = function() {
    if ( this.table.childNodes.length < 2 ) {
        this.table.appendChild(this.h);
        this.table.appendChild(this.b);
        this.sortrep = new SortableTable(this.table); 
        this.setSortColumns(this.sortColumn,this.secondarySortColumn);
    }
    return this.dom;
}
