function Table( name_id, rows, cols, withTHead, withTFoot, initDefaultCellStyle ){
    return{
        instance   : document.createElement("table"),
        name_id : name_id,
		rows : rows,
		cols : cols,

        init : function(){
            this.instance.name = this.name_id;
            this.instance.id   = this.name_id;

            if ( withTHead ){
				this.createTHead( undefined, initDefaultCellStyle );
            }
            if ( withTFoot ){
				this.createTFoot( undefined, initDefaultCellStyle );
            }

            this.createTBody( undefined, true, undefined, rows, initDefaultCellStyle );
        },

        createTHead : function( id, initDefaultCellStyle ){
			var _id = "default_thead";
            if( !this.instance.tHead ){
                var thead = document.createElement( "thead" );
                this.instance.appendChild( thead );
                thead.appendChild( document.createElement( "tr" ) );
                thead.rows[0].appendChild( document.createElement("td") );
                thead.rows[0].cells[0].setAttribute( "colSpan", cols );
                if( initDefaultCellStyle ){
                    thead.rows[0].cells[0].style.border = "1px solid #e0e0e0";
                    thead.rows[0].cells[0].style.fontSize = "small";
                }
                if( id )
                        _id = id
                thead.id = _id;		
            }
        },

        getTHead : function(){
            if ( this.instance.tHead )
                return this.instance.tHead;
            else
                alert( "getTHead: thead does not exist!" );
        },

        createTBody : function( id, alternating_rows, row_class, row_count, initDefaultCellStyle ){
			try{
				var _id = "default_tbody";
				var tbody = document.createElement("tbody");
				if( id )
						_id = id;
				tbody.id = _id;
				this.instance.appendChild( tbody );
				var index = this.instance.tBodies.length-1;

				if( row_count ){
					for( var i=0; i<row_count; i++ ){
						this.addRow( index, alternating_rows, row_class, initDefaultCellStyle );
					}
				}
			}catch( e ){
				alert( "error in createTBody: " + e );
			}
        },

        getTBody : function( tbody_index ){
            try{
                if( this.instance.tBodies && this.instance.tBodies.length >= 0 ){
					return this.instance.tBodies[tbody_index];
                }
                alert ("getTBody: tBodies[" + tbody_index + "] does not exist!"); 
            }catch(e){
                alert( "error in getTBody: " + e );
            }
        },

        createTFoot : function( id, initDefaultCellStyle ){
			var _id = "default_tfoot";
            if( !this.instance.tFoot ){
                var tfoot = document.createElement( "tfoot" );
                this.instance.appendChild( tfoot );
                tfoot.appendChild( document.createElement( "tr" ) );
                tfoot.rows[0].appendChild( document.createElement("td") );
                tfoot.rows[0].cells[0].setAttribute("colSpan",cols);
                if( initDefaultCellStyle ){
                    tfoot.rows[0].cells[0].style.border = "1px solid #e0e0e0";
                    tfoot.rows[0].cells[0].style.fontSize = "small";
                }
                if( id )
                        _id = id;
                tfoot.id = _id;
            }
        },

        getTFoot : function(){
            if ( this.instance.tFoot )
                return this.instance.tFoot;
            else
                alert( "getTFoot: tfoot does not exist!" );
        },

        addRow : function( tbody_index, alternate, row_class, initDefaultCellStyle, beforeIndex ){
			try{
				var table_section = this.instance.tBodies[tbody_index];
				this.addTableRow( table_section, alternate, row_class, initDefaultCellStyle, beforeIndex );
			}catch( e ){
				alert( "error in addRow: " + e );
			}
        },

        addTHeadRow : function( alternate, row_class, initDefaultCellStyle ){
                if( this.instance.tHead ){
                        var table_section = this.instance.tHead;
                        this.addTableRow( table_section, alternate, row_class, initDefaultCellStyle );
                }else{
                        this.createTHead();			
                }
        },

        addTFootRow : function( alternate, row_class, initDefaultCellStyle ){
                if ( this.instance.tFoot ){
                        var table_section = this.instance.tFoot; 
                        this.addTableRow( table_section, alternate, row_class, initDefaultCellStyle );			
                }else{
                        this.createTFoot();
                }
        },

        addTableRow : function( table_section, alternate, row_class, initDefaultCellStyle, beforeIndex ){
            var row = document.createElement("tr");
            var _class = "default_row";

            if( beforeIndex >= 0 && beforeIndex < table_section.rows.length ){
                table_section.insertBefore( row, table_section.rows[beforeIndex] );
            }else{
                table_section.appendChild( row );
            }
            for( var i=0; i<cols; i++ ){
                row.appendChild( document.createElement( "td" ) );
                    if( initDefaultCellStyle ){
                        row.lastChild.style.border = "1px solid #e0e0e0";
                    }
                        row.lastChild.style.fontSize = "x-small";
                }
        },

        removeRow : function( tbody_index, index ){
            table_section = this.instance.tBodies[tbody_index];
            this.removeTableRow( table_section, index );
        },

        removeTableRow : function( table_section, index ){
            table_section.removeChild( table_section.rows[index] );
        }, 

        getTableSection : function( section, tbody_index ){
            switch( section ){
                case "thead": return this.instance.tHead; 
                case "tfoot": return this.instance.tFoot;
                case "tbody": return this.instance.tBodies[tbody_index];
			}		
        },

        mergeCells : function( tbody_index, row_index, start_index, count ){
            var table_section = this.instance.tBodies[tbody_index];
            this.mergeTableCells( table_section, row_index, start_index, count );
        },

        mergeTHeadCells : function( row_index, start_index, count ){
            var table_section = this.instance.tHead;
            this.mergeTableCells( table_section, row_index, start_index, count );
        },

        mergeTFootCells : function( row_index, start_index, count ){
            var table_section = this.instance.tFoot;
            this.mergeTableCells( table_section, row_index, start_index, count );
        },


        mergeTableCells : function( section, row_index, start_index, count ){
            var c = count;
            try{
				if( ( section.rows[row_index].cells.length - start_index) < count )
					c = section.rows[row_index].cells.length - start_index;
				section.rows[row_index].cells[start_index].setAttribute( "colSpan", c );
				for( var i=start_index+1; i<start_index+c; i++ ){

						if( section.rows[row_index].cells[start_index].nextSibling )
							section.rows[row_index].removeChild( section.rows[row_index].cells[start_index].nextSibling );
				}
            }catch(e){
                 alert( "ERROR in merge cells: " + e );
            }
        },

        setAttribute : function( table_attribute, table_attribute_value ){
            try{
                setAttribute( table_attribute, table_attribute_value, this.instance );
            }catch( e ){
                alert( "setAttribute: unable to set table attribute: \n" + e );
            }
        },

        setTHeadAttribute : function( thead_attribute, thead_attribute_value ){
            try{
                this.instance.tHead.setAttribute( thead_attribute, thead_attribute_value );
            }catch( e ){
                alert( "setTHeadAttribute: unable to set tHead attribute: \n" + e );
            }		
	},

        setTBodyAttribute : function( tbody_index, tbody_attribute, tbody_attribute_value ){
            try{
                this.instance.tbodies[ tbody_index ].setAttribute( tbody_attribute, tbody_attribute_value );
            }catch( e ){
                alert( "setTBodyAttribute: unable to set tbody attribute: \n" + e );
            }
        },

        setTFootAttribute : function( tfoot_attribute, tfoot_attribute_value ){
            try{
                this.instance.tFoot.setAttribute( tfoot_attribute, tfoot_attribute_value );
            }catch( e ){
                alert( "setTFootAttribute: unable to set tFoot attribute: \n" + e );
            }		
		},

        setRowAttribute : function( tbody_index, row_index, row_attribute, row_attribute_value ){
            var table_section = this.instance.tBodies[tbody_index];
            try{
                table_section.rows[ row_index ].setAttribute( row_attribute, row_attribute_value ); 
            }catch( e ){
                alert( "setRowAttribute: unable to set row attribute: \n" + e );
            }
        },

        setTHeadRowAttribute : function( row_index, row_attribute, row_attribute_value ){
            var table_section = this.instance.tHead;
            try{
                table_section.rows[ row_index ].setAttribute( row_attribute, row_attribute_value ); 
            }catch( e ){
                alert( "setRowAttribute: unable to set thead row attribute: \n" + e );
            }
        },

        setTFootRowAttribute : function( row_index, row_attribute, row_attribute_value ){
            var table_section = this.instance.tFoot;
            try{
                table_section.rows[ row_index ].setAttribute( row_attribute, row_attribute_value ); 
            }catch( e ){
                alert( "setRowAttribute: unable to set tfoot row attribute: \n" + e );
            }
        },

        setCellAttribute : function( table_index, row_index, cell_index, cell_attribute, cell_attribute_value ){
            var table_section = this.instance.tBodies[ table_index ];
            try{
                setAttribute( cell_attribute, cell_attribute_value, table_section.rows[ row_index ].cells[ cell_index ]);
            }catch( e ){
            }
        },

        setTHeadCellAttribute : function( row_index, cell_index, cell_attribute, cell_attribute_value ){
            var table_section = this.instance.tHead;
            try{
                table_section.rows[ row_index ].cells[ cell_index ].setAttribute( cell_attribute, cell_attribute_value ); 
            }catch( e ){
                alert( "setTHeadCellAttribute: unable to set cell attribute: \n" + e );
            }
        },

        setTFootCellAttribute : function( row_index, cell_index, cell_attribute, cell_attribute_value ){
            var table_section = this.instance.tFoot;
            try{
                table_section.rows[ row_index ].cells[ cell_index ].setAttribute( cell_attribute, cell_attribute_value ); 
            }catch( e ){
                alert( "setTFootCellAttribute: unable to set cell attribute: \n" + e );
            }
        },

        setCellData : function ( tbody_index, row_index, cell_index, data ){
			try{
				var table_section = this.instance.tBodies[tbody_index];			
				this.setTableCellData( table_section, row_index, cell_index, data );
			}catch(e){
				alert( "error in setCellData : " + e );
			}
        },

        setTHeadCellData : function( row_index, cell_index, data ){
			try{
				var table_section = this.instance.tHead;
				var bold_tag = document.createElement( "b" );

				try{
					bold_tag.appendChild( data );
				}catch(e){
					bold_tag.innerHTML = data;
				}
				this.setTableCellData( table_section, row_index, cell_index, bold_tag );			
			}catch( e ){
				alert( "error in setTHeadCellData : " + e );									
			}
        },

        setTFootCellData : function( row_index, cell_index, data ){
                try{
                        var table_section = this.instance.tFoot;
                        this.setTableCellData( table_section, row_index, cell_index, data );			
                }catch(e){
                        alert( "error in setTFootCellData : " + e );							
                }
        },	

        setTableCellData : function( table_section, row_index, cell_index, data ){
            try{
                    if( data.length ){
                        if( table_section.rows[ row_index ].cells[ cell_index ].firstChild ){
                            table_section.rows[ row_index ].cells[ cell_index ].replaceChild( document.createTextNode(data), table_section.rows[ row_index ].cells[ cell_index ].firstChild );
                        }else{
                            table_section.rows[ row_index ].cells[ cell_index ].appendChild( document.createTextNode(data) );
                        }
                    }else{
                        if( table_section.rows[ row_index ].cells[ cell_index ].firstChild ){
                            table_section.rows[ row_index ].cells[ cell_index ].replaceChild( data, table_section.rows[ row_index ].cells[ cell_index ].firstChild );
                        }else{
                            table_section.rows[ row_index ].cells[ cell_index ].appendChild( data );
                        }
                    }
            }catch(e){
            }		
        },

        appendCellData : function ( section, tbody_index, row_index, cell_index, data ){
            var table_section = this.getTableSection( section, tbody_index );
            try{
                    table_section.rows[ row_index ].cells[ cell_index ].appendChild( data );
            }catch(e){
                alert( "appendCellData: unable to append cell data: \n" + e );
            }
        },

        insertRowDataToRow : function( row_data ){
            var row = document.createElement("tr");
            for( var i=0; i<row_data.length; i++ ){
                var cell = document.createElement("td");
                cell.innerHTML = row_data[i];
                row.appendChild( cell );
            }
            this.insertRow( row );
        }

    }
}

function createNewTable( id, rows, cols, withHeader, withFooter, initDefaultCellStyle ){
    var t = new Table( id, rows, cols, withHeader, withFooter, initDefaultCellStyle );
    t.init();
    return t;
}

