///////////////////////////////////////////////////////////////////////////////////////// 
// SUPER TABLES - VERSION 0.24 - MIT Style License
// Copyright (c) 2008 MATT MURPHY --- visit www.matts411.com
///////////////////////////////////////////////////////////////////////////////////////// 
// TO CALL: 
// new superTable([string] tableId, { options });
//
// OPTIONS: (order does not matter )
// cssSkin : string
// headerRows : integer
// fixedCols : integer
// colWidths : integer array ( -1 for auto sizing )
//
// EXAMPLES:
// myST = new superTable("myTableId");
//
// myST = new superTable("myTableId", {
//      cssSkin : "Sky",
//      fixedCols : 2,
//      colWidths : [100, 230, 220, -1, 120, -1, -1, 120]
//  });
///////////////////////////////////////////////////////////////////////////////////////// 
// ISSUES / NOTES:
// 1. Does not check to see if rows are horizontally aligned if fixedCols > 0
// 2. colSpan not supported (yet)
// 3. No quirksmode support
///////////////////////////////////////////////////////////////////////////////////////// 

var superTables = [];

function superTable(tableId) {
    // add this instance to the supertables array
    this.index = superTables.length; 
    var x = this.index;
    superTables[this.index] = this;
    
    // initialize the parameters
    var table = document.getElementById(tableId);
    var hasOptions = (arguments.length > 1) ? true : false;
    this.skin = (hasOptions && arguments[1].cssSkin) ? "_" + arguments[1].cssSkin : "_Default";
    this.headerRows = (hasOptions && arguments[1].headerRows) ? parseInt(arguments[1].headerRows) : 1;
    this.fixedCols = (hasOptions && arguments[1].fixedCols) ? parseInt(arguments[1].fixedCols) : 0;
    this.columnWidths = (hasOptions && arguments[1].colWidths) ? arguments[1].colWidths : [];

    // get the column widths
    this.columnCount = (table.tHead) ? table.tBodies[0].rows[0].cells.length : table.tBodies[0].rows[this.headerRows + 1].cells.length;
    table.className = "sTempTable";
    for(i=0; i<this.columnCount; i++) {
        if(!this.columnWidths[i] || this.columnWidths[i] == -1) {
            this.columnWidths[i] = (table.tHead) ? table.tBodies[0].rows[0].cells[i].offsetWidth : table.tBodies[0].rows[this.headerRows + 1].cells[i].offsetWidth;
        }
    }

    // create the framework dom
    this.sParent = table.parentNode;
    this.sParentHeight = this.sParent.clientHeight - (this.sParent.offsetHeight - this.sParent.clientHeight);
    this.sParentWidth = this.sParent.clientWidth - (this.sParent.offsetWidth - this.sParent.clientWidth);
    this.sParent.removeChild(table);
	
	var cloneDiv = document.createElement('DIV');
	this.sBase = cloneDiv.cloneNode(false);
	this.sFHeader = cloneDiv.cloneNode(false);
	this.sHeader = cloneDiv.cloneNode(false);
	this.sFData = cloneDiv.cloneNode(false);
	this.sData = cloneDiv.cloneNode(false);

    // create the row dom molds
    if(this.fixedCols > 0) { 
        var fRowMold = ["<TR>\n"]; 
        for(i=0; i<this.fixedCols; i++) {
            fRowMold.push("<TD><DIV>&nbsp;</DIV></TD>");
        }
        fRowMold.push("\n</TR>\n");
        fRowMold = fRowMold.join("");
    }
    var rowMold = ["<TR>\n"];
    for(i=0; i<(this.columnCount - this.fixedCols); i++) {
        rowMold.push("<TD><DIV>&nbsp;</DIV></TD>");
    }
    rowMold.push("\n</TR>\n");
    rowMold = rowMold.join("");

    // create the header dom framework
    if(this.fixedCols > 0) {
        var fHeaderMold = ["\n<TABLE><TBODY>\n" + fRowMold];
        for(i=1; i<this.headerRows; i++) {
            fHeaderMold.push(fRowMold);
        }
        fHeaderMold.push("</TBODY></TABLE>\n");
        this.sFHeader.innerHTML = fHeaderMold.join("");
        this.sFHeaderTable = this.sFHeader.getElementsByTagName("TABLE")[0];
    }
    var headerMold = ["\n<TABLE><TBODY>\n" + rowMold];
    for(i=1; i<this.headerRows; i++) {
        headerMold.push(rowMold);
    }
    headerMold.push("</TBODY></TABLE>\n");
    this.sHeader.innerHTML = headerMold.join("");
    this.sHeaderTable = this.sHeader.getElementsByTagName("TABLE")[0];

    // fill the header dom framework
    var rootDest, rootSource, dest, source;
    if(this.fixedCols > 0) {
        rootDest = this.sFHeaderTable.tBodies[0];
        rootSource = (table.tHead) ? table.tHead : table.tBodies[0];
        for(i=0; i<this.headerRows; i++) {
            dest = rootDest.rows[i];
            source = rootSource.rows[i];
            for(j=0; j<this.fixedCols; j++) {
                try {
                    dest.cells[j].firstChild.innerHTML = source.cells[j].innerHTML;
                    dest.cells[j].style.width = this.columnWidths[j] + "px";
                } catch(e) { }
            }
        }
    }
    rootDest = this.sHeaderTable.tBodies[0];
    rootSource = (table.tHead) ? table.tHead : table.tBodies[0];
    for(i=0; i<this.headerRows; i++) {
        dest = rootDest.rows[i];
        source = rootSource.rows[i];
        for(j=0; j<(this.columnCount - this.fixedCols); j++) {
            try {
                dest.cells[j].firstChild.innerHTML = source.cells[j + this.fixedCols].innerHTML;
                dest.cells[j].style.width = this.columnWidths[j + this.fixedCols] + "px";
            } catch(e) { }
        }
    }

    // create the data dom framework
    this.rowDataCount = (table.tHead) ? table.tBodies[0].rows.length : table.tBodies[0].rows.length - this.headerRows;
    if(this.fixedCols > 0) {
        var fDataMold = ["\n<TABLE><TBODY>\n"];
        for(i=(table.tHead) ? 0 : this.headerRows; i<this.rowDataCount; i++) {
            fDataMold.push(fRowMold);
        }
        fDataMold.push("</TBODY></TABLE>\n");
        this.sFData.innerHTML = fDataMold.join("");
        this.sFDataTable = this.sFData.getElementsByTagName("TABLE")[0];
    }
    var dataMold = ["\n<TABLE><TBODY>\n"];
    for(i=(table.tHead) ? 0 : this.headerRows; i<this.rowDataCount; i++) {
        dataMold.push(rowMold);
    }
    dataMold.push("</TBODY></TABLE>\n");
    this.sData.innerHTML = dataMold.join("");
    this.sDataTable = this.sData.getElementsByTagName("TABLE")[0];

    // fill the data dom framework
    if(this.fixedCols > 0) {
        rootDest = this.sFDataTable.tBodies[0];
        rootSource = table.tBodies[0];
        for(i=(table.tHead) ? 0 : this.headerRows; i<this.rowDataCount; i++) {
            dest = rootDest.rows[i - this.headerRows];
            source = rootSource.rows[i];
            for(j=0; j<this.fixedCols; j++) {
                try {
                    dest.cells[j].firstChild.innerHTML = source.cells[j].innerHTML;
                } catch(e) { }
            }
        }
        for(i=0; i<this.fixedCols; i++) {
            rootDest.rows[0].cells[i].style.width = this.columnWidths[i] + "px";
        }
    }
    rootDest = this.sDataTable.tBodies[0];
    rootSource = table.tBodies[0];
    for(i=(table.tHead) ? 0 : this.headerRows; i<this.rowDataCount; i++) {
        dest = rootDest.rows[i - this.headerRows];
        source = rootSource.rows[i];
        for(j=0; j<(this.columnCount - this.fixedCols); j++) {
            try {
                dest.cells[j].firstChild.innerHTML = source.cells[j + this.fixedCols].innerHTML;
            } catch(e) { }
        }
    }
    for(i=0; i<(this.columnCount - this.fixedCols); i++) {
        rootDest.rows[0].cells[i].style.width = this.columnWidths[i + this.fixedCols] + "px";
    }

    // place everything into the page
	if(this.fixedCols > 0) { this.sBase.appendChild(this.sFHeader); }
	this.sBase.appendChild(this.sHeader);
	if(this.fixedCols > 0) { this.sBase.appendChild(this.sFData); }
	this.sBase.appendChild(this.sData);
    
    // style the tables
	this.sBase.className = 'sBase' + this.skin;
	this.sFHeader.className = 'sFHeader' + this.skin;
	this.sHeader.className = 'sHeader' + this.skin;
	this.sFData.className = 'sFData' + this.skin;
	this.sData.className = 'sData' + this.skin;
    
    // render and align the tables
    setTimeout(function() {
        superTables[x].sParent.appendChild(superTables[x].sBase);
    	if(superTables[x].fixedCols > 0) {
            superTables[x].sHeader.style.right = (superTables[x].sFHeaderTable.offsetWidth * -1) + "px";
            superTables[x].sData.style.marginLeft = superTables[x].sFDataTable.offsetWidth + "px"; 
            superTables[x].sData.style.width = (superTables[x].sParentWidth - superTables[x].sFHeaderTable.offsetWidth) + "px";
        }
        superTables[x].sData.style.height = (superTables[x].sParentHeight - superTables[x].sHeaderTable.offsetHeight) + "px";
        superTables[x].sData.style.overflow = "auto"; 
        if(superTables[x].fixedCols > 0) {
            superTables[x].sFHeaderTableOffsetWidth = superTables[x].sFHeaderTable.offsetWidth;
            superTables[x].sFHeaderTableOffsetHeight = superTables[x].sFHeaderTable.offsetHeight;
            if(superTables[x].sData.clientWidth < superTables[x].sDataTable.clientWidth) {
                superTables[x].sHorOverflow = document.createElement('DIV');
                superTables[x].sHorOverflow.className = 'sHorOverflow';
                superTables[x].sHorOverflow.style.width = superTables[x].sFDataTable.offsetWidth + 'px';
                superTables[x].sBase.appendChild(superTables[x].sHorOverflow);
            }
        }
        if(superTables[x].sData.clientHeight < superTables[x].sDataTable.clientHeight) {
            superTables[x].sVertOverflow = document.createElement('DIV');
            superTables[x].sVertOverflow.className = 'sVertOverflow';
            superTables[x].sVertOverflow.style.height = superTables[x].sHeaderTable.offsetHeight + 'px';
            superTables[x].sBase.appendChild(superTables[x].sVertOverflow);
        }
    }, 0);
    
    // set up table events
    if(this.fixedCols > 0) {
        this.sData.onscroll = function() {
            superTables[x].sHeader.style.right = (superTables[x].sData.scrollLeft - superTables[x].sFHeaderTableOffsetWidth) + "px";
            superTables[x].sFData.style.top = ((superTables[x].sData.scrollTop * -1) + superTables[x].sFHeaderTableOffsetHeight) + "px";
            return true;
        }
    } else {
        this.sData.onscroll = function() {
        	superTables[x].sHeader.style.right = superTables[x].sData.scrollLeft + "px";
    		return true;
        }
    }
}


