var classAirFinstat = function(lib, settings)
{
    // Module references //
    var _lib = lib || null;
    var _modules = {};
    var _this = this;
    this.version = '1.0';
    this.toString = function(){ return _lib.toString() + ' - Finstat'; };
    arguments.callee.toString = function(){ return _lib.toString() + ' - Finstat - Constructor'; };

    // Private properties //

    /**
    * Module memory.
    * @type Object
    */
    var _memory =
    {
        meta : {},
        tables : {}
    };

    // Public properties //

    /**
    * DOM references used by module.
    * @type Object
    */
    this.dom =
    {
        actions : null,
        actionCollapse : null,
        actionExport : null,
        actionLoader : null,
        container : null,
        navigation : null,
        postbackSpan : null,
        postbackSubmit : null,
        postbackTable : null
    };

    /**
    * Module settings.
    * @type Object
    */
    this.settings =
    {
        frameName : 'alertirframe',
        classNames :
        {
            table : 'afwTable'
        },
        domIndexes :
        {
            container : 'afwFinstat',
            navigation : 'afwFinstatNavigation',
            actions : 'afwFinstatActions',
            postbackForm : 'afwPostbackForm',
            postbackSpan : 'afwPostbackSpan',
            postbackSubmit : 'afwPostbackSubmit',
            postbackTable : 'afwPostbackTable'
        },
        graph :
        {
            all : false, // if to graph enable all numerical rows or only those who have been flagged as graphable
            defaultAttribute : 'Y', // starts with ..
            maxPointsYearly : 10,
            maxPointsQuarterly : 13,
            icon :
            {
                area : '/images/shared/icon/silk/chart_pie.png',
                line : '/images/shared/icon/silk/chart_bar.png'
            },
            showDefault : true
        },
        table :
        {
            chartIcon :
            {
                states :
                {
                    active :
                    {
                        opacity : 100
                    },
                    hover :
                    {
                        opacity : 40
                    },
                    normal :
                    {
                        opacity : 15
                    }
                }
            }
        }
    };

    // Private functions //

    /**
    * Collect and adds default graph row.
    *
    * @version 1.0 2010-09-27
    * @author Mathias Petersson
    */
    function _addDefaultGraph()
    {
        var table, tableID, row, rowID, i, m, domTable, image;
        tableID = _modules.table.getCurrentTableID();
        table = _memory.tables[tableID];
        domTable = _modules.table.getTable(tableID);
        for(i = 0, m = table.rows.length; i < m; ++i)
        {
            if(table.rows[i].defaultGraph)
            {
                image = _lib.getFirstChild(domTable.rows[i].cells[0], ['img']);
                _this.addGraph(image);
            }
        }
    }

    /**
    * Add graph icon to table row.
    *
    * @param {Object} row   Table row.
    *                       Required.
    * @param {String} type  Graph type.
    *                       Optional. Default: line
    * @version 1.0 2011-03-18
    * @author Mathias Petersson
    * @return {Object} DOM reference to graph icon
    */
    function _addGraphIcon(row, type)
    {
        var firstCol, image;
        if((firstCol = _lib.getFirstChild(row, ['td', 'th'])))
        {
            type = type || 'line';
            image = document.createElement('IMG');
            image.src = (type == 'area' ? _this.settings.graph.icon.area : _this.settings.graph.icon.line);
            _lib.setOpacity(image, _this.settings.table.chartIcon.states.normal.opacity);
            switch(type)
            {
                default:
                case 'line':

                break;

                case 'area':

                break;
            }
            _lib.addEvent(image, 'click', function()
            {
                var rowID = _modules.table.getRowIdentifier(_lib.getParent(image, ['tr']));
                if(!_modules.graph.isGraphed(rowID))
                {
                    _this.addGraph(image, type);
                }
                else
                {
                    _this.removeGraph(image, type);
                }
            });
            _lib.addEvent(image, 'mouseover', function()
            {
                var rowID = _modules.table.getRowIdentifier(_lib.getParent(image, ['tr']));
                if(!_modules.graph.isGraphed(rowID))
                {
                    _lib.setOpacity(image, _this.settings.table.chartIcon.states.hover.opacity);
                }
            });
            _lib.addEvent(image, 'mouseout', function()
            {
                var rowID = _modules.table.getRowIdentifier(_lib.getParent(image, ['tr']));
                if(!_modules.graph.isGraphed(rowID))
                {
                    _lib.setOpacity(image, _this.settings.table.chartIcon.states.normal.opacity);
                }
            });
            firstCol.insertBefore(image, firstCol.firstChild);
            return image;
        }
    }

    /**
    * Enable/disable span options.
    *
    * @version 2011-03-11
    * @author Mathias Petersson
    */
    function _alterSpans()
    {
        var i, m, tableName, changeSpan = false;
        tableName = _this.dom.postbackTable.options[_this.dom.postbackTable.selectedIndex].value.toLowerCase();
        for(i = 0, m = _this.dom.postbackSpan.options.length; i < m; ++i)
        {
            _this.dom.postbackSpan.options[i].disabled = (_memory.tables[tableName + '-' + _this.dom.postbackSpan.options[i].value.toLowerCase()] ? false : true);
            if(_this.dom.postbackSpan.options[i].disabled && i == _this.dom.postbackSpan.selectedIndex)
            {
                changeSpan = true;
            }
        }
        if(changeSpan)
        {
            for(i = 0, m = _this.dom.postbackSpan.options.length; i < m; ++i)
            {
                if(!_this.dom.postbackSpan.options[i].disabled)
                {
                    _this.dom.postbackSpan.options[i].selected = true;
                    break;
                }
            }
        }
    }

    /**
    * Handle json callback table data.
    *
    * @param {Object} result
    * @version 2011-03-08
    * @author Mathias Petersson
    */
    function _handleJsonCallback(result)
    {
        eval('result = ' + result);
        if(!result)
        {
            _lib.error('Could not find requested table.');
            return;
        }
        _this.parseTableData(result.data);
        _this.changeTable(_modules.table.generateTableIDName(result.data.name, result.data.span));
    }

    /**
    * Initialize script.
    * @ignore
    */
    function _init(settings)
    {
        // Verify that library is loaded and linked
        if(_lib === null)
        {
            alert('Library missing for ' + _this.toString());
            return;
        }

        // Settings
        if (settings) {
            _this.settings.graph.icon.area = settings.resourcesPathPrefix + _this.settings.graph.icon.area;
            _this.settings.graph.icon.line = settings.resourcesPathPrefix + _this.settings.graph.icon.line;
        }
        _this.settings = _lib.mergeObjects(_this.settings, settings);
    }

    /**
    * Submit form and request table data through ajax.
    *
    * @version 2011-03-08
    * @author Mathias Petersson
    */
    function _submitAjaxForm()
    {
        var params = {}, tableID;
        params.table = _this.dom.postbackTable;
        params.span = _this.dom.postbackSpan;
        params.table = params.table.options[params.table.selectedIndex].value;
        params.span = params.span.options[params.span.selectedIndex].value;
        tableID = _modules.table.generateTableIDName(params.table, params.span);
        if(_memory.tables[tableID] && !_memory.tables[tableID].parsed)
        {
            _this.displayLoaderIcon(true);
            params = '&afw_table=' + params.table + '&afw_span=' + params.span;
            _modules.ajax.open(_this.settings.jsonPostbackUrl + params, _handleJsonCallback);
        }
        else if(_memory.tables[tableID])
        {
            _this.changeTable(tableID);
        }
    }

    // Public functions //

    /**
    * Add a graph serie.
    *
    * @param {Object} chartIcon Chart icon.
    *                           Required.
    * @param {String} tyoe      Graph type.
    *                           Optional.
    * @version 1.0 2011-03-18
    * @author Mathias Petersson
    */
    this.addGraph = function(chartIcon, type)
    {
        var options = _lib.isValidInputs();
        if(options)
        {
            var row, rowDOM, rowID, table, group, groupTableData, tableID, unitIndex, cells, i, m, i2, m2, x, maxPoints;
            rowDOM = _lib.getParent(options.chartIcon, ['tr']);
            rowID = _modules.table.getRowIdentifier(rowDOM);
            if(rowID && !_modules.graph.isGraphed(rowID))
            {
                tableID = _modules.table.getCurrentTableID();
                table = _memory.tables[tableID];
                row = table.rows[parseFloat(rowID.substring(1))];
                unitIndex = _modules.graph.getUnitIndex(row.unit);
                maxPoints = (table.columnsVisibleGraph ? table.columnsVisibleGraph : (tableID.charAt(tableID.length - 1).toLowerCase() == 'q' ? _this.settings.graph.maxPointsQuarterly : _this.settings.graph.maxPointsYearly));
                while(row.values.length > maxPoints) {
                    x = row.values.shift();
                }
                switch(options.type)
                {
                    default:
                    case 'line':
                        cells = _lib.getRowCells(rowDOM);
                        _lib.setOpacity(options.chartIcon, _this.settings.table.chartIcon.states.active.opacity);
                        _lib.addClass(rowDOM, 'graphed');
                        if(unitIndex === false)
                        {
                            unitIndex = _modules.graph.addUnit(row.unit);
                        }
                        for(i = 0, m = cells.length; i < m; ++i)
                        {
                            cells[i].style.backgroundColor = _modules.graph.settings.graph.colorsLight[row.colorIndex];
                        }
                        _modules.graph.addSerie(rowID, row.unit, row.values, row.title, null, 0, unitIndex, _modules.graph.settings.graph.colors[row.colorIndex], _modules.graph.settings.graph.symbols[row.symbolIndex]);
                    break;
                    case 'area':
                        group = row.attribute;
                        if(group = table.groups[group])
                        {
                            _this.clearViewport();
                            if(unitIndex === false)
                            {
                                unitIndex = _modules.graph.addUnit(row.unit);
                            }
                            for(i = 0, m = group.length; i < m; ++i)
                            {
                                groupTableData = _modules.table.getTable(tableID);
                                if(groupTableData)
                                {
                                    groupTableData = (groupTableData.rows[group[i].rowIndex] ? groupTableData.rows[group[i].rowIndex] : null);
                                    if(groupTableData)
                                    {
                                        groupTableData.rowDOM = groupTableData.dom;
                                        groupTableData.row = table.rows[group[i].rowIndex];
                                        _lib.setOpacity(groupTableData.row.chartIcon, _this.settings.table.chartIcon.states.active.opacity);
                                        _lib.addClass(groupTableData.rowDOM, 'graphed');
                                        if(i == 0)
                                        {
                                            _modules.graph.initGraph(groupTableData.row.title);
                                            unitIndex = _modules.graph.getUnitIndex(row.unit);
                                            if(unitIndex === false)
                                            {
                                                unitIndex = _modules.graph.addUnit(row.unit);
                                            }
                                            return;
                                        }
                                        for(i2 = 0, m2 = groupTableData.cells.length; i2 < m2; ++i2)
                                        {
                                            groupTableData.cells[i2].style.backgroundColor = _modules.graph.settings.graph.colorsLight[groupTableData.row.colorIndex];
                                        }
                                        _modules.graph.addSerie(_modules.table.getRowIdentifier(groupTableData.rowDOM), groupTableData.row.unit, groupTableData.row.values, groupTableData.row.label, 'area', 0, unitIndex, _modules.graph.settings.graph.colors[groupTableData.row.colorIndex], _modules.graph.settings.graph.symbols[groupTableData.row.symbolIndex]);
                                    }
                                }
                            }
                        }
                    break;
                }
            }
        }
    };
    this.addGraph.rules =
    {
        required : ['chartIcon'],
        types :
        {
            chartIcon : ['dom'],
            type : ['string']
        }
    };

    /**
    * Change table and do necessary parsing.
    *
    * @param {String} tableID   Table ID.
    *                           Required.
    * @version 1.0 2010-10-21
    * @author Mathias Petersson
    */
    this.changeTable = function(tableID)
    {
        var options = _lib.isValidInputs();
        if(options)
        {
            _this.clearViewport();
            var table, x, maxPoints;
            _this.displayLoaderIcon(true);
            table = _memory.tables[options.tableID];
            if(table && table.parsed)
            {
                if(!table.graphableCount)
                {
                    _this.hideGraphArea();
                }
                else
                {
                    _this.showGraphArea();
                }
                if(_modules.table.changeTable(options.tableID))
                {
                    maxPoints = (tableID.charAt(tableID.length - 1).toLowerCase() == 'q' ? (table.meta.columnsVisibleGraph ? table.meta.columnsVisibleGraph : _this.settings.graph.maxPointsQuarterly) : (table.meta.columnsVisibleGraph ? table.meta.columnsVisibleGraph : _this.settings.graph.maxPointsYearly));
                    while(table.labels.length > maxPoints) {
                        x = table.labels.shift();
                    }
                    _lib.removeClass(_this.dom.actionCollapse, 'collapsed');
                    _modules.graph.initGraph(table.title);
                    _modules.graph.setCategories(table.labels);
                    _addDefaultGraph();
                    _this.fixFrameHeight();
                }
                else
                {
                    _lib.log('Couldn\'t change to requested table (' + options.tableID + '). Make sure it has been parsed by air_finstat::parseTableData().');
                }
            }
            else
            {
                _lib.log('Requested table (' + options.tableID + ') hasn\'t been stored in memory yet. Make sure it has been parsed by air_finstat::parseTableData().');
            }
            _this.displayLoaderIcon(false);
            _alterSpans();
        }
    };
    this.changeTable.rules =
    {
        required : ['tableID'],
        types :
        {
            tableID : ['string']
        }
    };

    /**
    * Clears currently active table and its graph element.
    *
    * @version 2011-03-21
    * @author Mathias Petersson
    */
    this.clearViewport = function()
    {
        var tableID, table, tableDOM, i, m;
        tableID = _modules.table.getCurrentTableID();
        if(tableID && (table = _memory.tables[tableID]) && (tableDOM = _modules.table.getTable(tableID)))
        {
            for(i = 0, m = table.rows.length; i < m; ++i)
            {
                if(table.rows[i].type && _lib.classExists(tableDOM.rows[i].dom, 'graphed'))
                {
                    _this.removeGraph(table.rows[i].chartIcon, table.rows[i].type);
                }
            }
        }
        _modules.graph.clear();
    };

    /**
    * Change visibility state of loader icon.
    *
    * @param {Boolean} show If to show icon or not.
    *                       Required.
    * @version 1.0 2010-10-27
    * @author Mathias Petersson
    */
    this.displayLoaderIcon = function(show)
    {
        var options = _lib.isValidInputs();
        if(options)
        {
            if(_this.dom.actionLoader)
            {
                _this.dom.actionLoader.style.display = (options.show ? '' : 'none');
            }
        }
    };
    this.displayLoaderIcon.rules =
    {
        required : ['show'],
        types :
        {
            show : ['boolean']
        }
    };
    
    /**
    * Fix frame height after a change of table
    */
    this.fixFrameHeight = function() {
        try {
            if (parent.AFWElementResizer) {
                parent.AFWElementResizer.addEvent(window, 'load', function() {
                    parent.AFWElementResizer.autoHeight(_this.settings.frameName, window, true);
                }, false);
            } else if (parent.AFWIframeResize) {
                parent.AFWIframeResize.addEvent(window, 'load', function() {
                    parent.AFWIframeResize.resize(_this.settings.frameName, parent.window);
                }, false);
            } else if(parent.changeIFrameHeight) {
                parent.changeIFrameHeight();
            } else {
                _lib.debug('No resize function found');
            }
        } catch (e) {_lib.debug(e);}
    };

    /**
    * Hide graph area and related actions
    *
    * @version 1.0 2011-04-27
    * @author Mathias Petersson
    */
    this.hideGraphArea = function()
    {
        _modules.graph.hide();
        if(_this.dom.actionExport) {
            _this.dom.actionExport.style.display = 'none';
        }
    };

    /**
    * Initialize module instance.
    *
    * @param {Object} dom   Module DOM elements.
    *                       Required.
    * @param {Object} meta  Meta information.
    *                       Required.
    * @version 1.0 2010-09-21
    * @author Mathias Petersson
    * @return Result.
    * @type Boolean
    */
    this.init = function(dom, meta, tables)
    {
        var options = _lib.isValidInputs();
        var errorMessage = 'Failed to initiate air_finstat.';
        var result = false;
        if(options)
        {
            _this.dom.container = options.dom[_this.settings.domIndexes.container];
            _this.dom.navigation = options.dom[_this.settings.domIndexes.navigation];
            _this.dom.actions = options.dom[_this.settings.domIndexes.actions];
            _this.dom.postbackForm = options.dom[_this.settings.domIndexes.postbackForm];
            _this.dom.postbackSpan = options.dom[_this.settings.domIndexes.postbackSpan];
            _this.dom.postbackSubmit = options.dom[_this.settings.domIndexes.postbackSubmit];
            _this.dom.postbackTable = options.dom[_this.settings.domIndexes.postbackTable];
            _memory.meta = options.meta;
            if(!_this.dom.container
            || !_this.dom.navigation
            || !_this.dom.actions
            || !_this.dom.postbackForm
            || !_this.dom.postbackSpan
            || !_this.dom.postbackSubmit
            || !_this.dom.postbackTable)
            {
                errorMessage += '<br />- missing some DOM elements';
            }
            else
            {
                var x, i, m, tableID, actions = _lib.getDOM(null, 'a', null, null, _this.dom.actions, true, false, true);
                if(actions)
                {
                    for(x in actions)
                    {
                        if(actions[x].className && actions[x].className != '')
                        {
                            switch(actions[x].className)
                            {
                                case 'collapse':
                                    _this.dom.actionCollapse = actions[x];
                                    _lib.addEvent(_this.dom.actionCollapse, 'click', function()
                                    {
                                        if(_modules.table.collapseTable())
                                        {
                                            _lib.addClass(_this.dom.actionCollapse, 'collapsed');
                                        }
                                        else
                                        {
                                            _lib.removeClass(_this.dom.actionCollapse, 'collapsed');
                                        }
                                    });
                                break;
                                case 'export':
                                    _this.dom.actionExport = actions[x];
                                    if(_modules.graph.exportEnabled())
                                    {
                                        _lib.addEvent(_this.dom.actionExport, 'click', _modules.graph.exportChart);
                                    }
                                    else
                                    {
                                        _lib.removeElement(_this.dom.actionExport);
                                    }
                                break;
                                case 'loader':
                                    _this.dom.actionLoader = actions[x];
                                break;
                            }
                        }
                    }
                }
                if(true) // make ajax loading optional?
                {
                    _this.dom.postbackForm.onsubmit = function(){ _submitAjaxForm(); return false; };
                    _lib.addEvent(_this.dom.postbackTable, 'change', _alterSpans);
                }
                if(options.tables)
                {
                    for(x in options.tables)
                    {
                        for(i = 0, m = options.tables[x].spans.length; i < m; ++i)
                        {
                            tableID = _modules.table.generateTableIDName(x, options.tables[x].spans[i]);
                            _memory.tables[tableID] =
                            {
                                parsed : false
                            };
                        }
                    }
                }
                result = true;
            }
        }
        if(!result)
        {
            _lib.error(errorMessage);
        }
        return result;
    };
    this.init.rules =
    {
        required : ['dom', 'meta', 'tables'],
        types :
        {
            dom : ['object'],
            meta : ['object'],
            tables : ['object']
        }
    };

    /**
    * Link module pointers between modules.
    *
    * @param {Object} modules   Object containing modules.
    *                           Required.
    * @version 1.0 2010-09-21
    * @author Mathias Petersson
    */
    this.linkModules = function(modules)
    {
        var options = _lib.isValidInputs();
        if(options)
        {
            var x;
            for(x in modules)
            {
                if(modules[x].toString() != _this.toString())
                {
                    _modules[x] = modules[x];
                }
            }
        }
    };
    this.linkModules.rules =
    {
        required : ['modules'],
        types :
        {
            modules : ['object']
        }
    };

    /**
    * Parse table data and build an complete object for later use.
    *
    * @param {Object} data  Table data.
    *                       Required.
    * @version 1.0 2010-10-21
    * @author Mathias Petersson
    */
    this.parseTableData = function(data)
    {
        var options = _lib.isValidInputs();
        var result = false;
        if(options)
        {
            var i, m, iRows, mRows, iCells, mCells, iCount, table, dom, tbody, rows, row, cell, tableID, colspan, cellType, content, classNames, cellstart, colorIndex, symbolIndex, groups;
            tableID = _modules.table.generateTableIDName(options.data.name, options.data.span);
            if(_memory.tables[tableID] && !_memory.tables[tableID].parsed)
            {
                table = {};
                table.rows = [];
                table.groups = {};
                table.graphableCount = 0;
                dom = document.createElement('TABLE');
                tbody = document.createElement('TBODY');
                dom.id = tableID;
                dom.className = _this.settings.classNames.table;
                rows = options.data.rows;
                colspan = Math.floor(options.data.meta.columnsVisible) + 1;
                colorIndex = 0;
                symbolIndex = 0;
                for(iRows = 0, mRows = rows.length; iRows < mRows; ++iRows)
                {
                    rows[iRows].rowIndex = iRows;
                    rows[iRows].chartIcon = null;
                    classNames = (rows[iRows].style ? 'afw-' + rows[iRows].style : '');
                    row = document.createElement('TR');
                    row.className = 'r' + iRows;
                    row.className += (iRows % 2 == 0 ? ' even' : ' odd');
                    row.className = (iRows == 0 ? row.className + ' first' : row.className);
                    row.className = (iRows + 1 == mRows ? row.className + ' last' : row.className);
                    row.className += ' ' + classNames;
                    cellType = (rows[iRows].style.indexOf('eading') > 0 ? 'TH' : 'TD');
                    cell = document.createElement(cellType);
                    cell.colSpan = Math.floor(classNames.indexOf('long') > 0 || classNames.toLowerCase() == 'break' || classNames.toLowerCase() == 'note' || !rows[iRows].values ? colspan : 1);
                    cell.className = 'c0 even first';
                    cell.className += (rows[iRows].values ? '' : ' last');
                    cell.className += (classNames ? ' ' + classNames : '');
                    if(rows[iRows].attribute != 'u')
                    {
                        content = (rows[iRows].acm ? '<span class="acm">' + rows[iRows].acm.edit + rows[iRows].acm.remove + '</span> ' : '');
                        content += (rows[iRows].style.toLowerCase() == 'break' ? '&nbsp;' : rows[iRows].label);
                        content += (rows[iRows].unit && rows[iRows].unit != options.data.meta.unit ? '<span class="unit">, ' + rows[iRows].unit + '</span>' : '');
                        if(classNames != 'afw-note' && classNames.indexOf('long') < 0)
                        {
                            content = '<div class="indent">' + content + '</div>';
                        }
                        cell.innerHTML = content;
                    }
                    row.appendChild(cell);
                    if(rows[iRows].graphable && !rows[iRows].attribute.match(/h/))
                    {
                        if(groups = rows[iRows].attribute.match(/p[0-9]?/))
                        {
                            for(i = 0, m = groups.length; i < m; ++i)
                            {
                                if(!table.groups[groups[i]])
                                {
                                    table.groups[groups[i]] = [];
                                }
                                table.groups[groups[i]].push(rows[iRows]);
                            }
                            _lib.addClass(row, 'area');
                            rows[iRows].chartIcon = _addGraphIcon(row, 'area');
                            rows[iRows].type = 'pie';
                        }
                        else
                        {
                            rows[iRows].chartIcon = _addGraphIcon(row);
                            rows[iRows].type = 'line';
                        }
                        table.graphableCount++;
                        _lib.addClass(dom, 'graphable');
                        _lib.addClass(row, 'graphable');
                        rows[iRows].colorIndex = colorIndex;
                        rows[iRows].symbolIndex = symbolIndex;
                        ++colorIndex;
                        if(colorIndex >= _modules.graph.settings.graph.colorsLight.length)
                        {
                            colorIndex = 0;
                        }
                        ++symbolIndex;
                        if(symbolIndex >= _modules.graph.settings.graph.symbols.length)
                        {
                            symbolIndex = 0;
                        }
                    }
                    if(rows[iRows].values)
                    {
                        cellstart = rows[iRows].values.length - options.data.meta.columnsVisible;
                        _lib.intify(rows[iRows].values);
                        for(iCount = 1, iCells = cellstart, mCells = rows[iRows].values.length; iCells < mCells; ++iCells, ++iCount)
                        {
                            cell = document.createElement(cellType);
                            cell.className = 'c' + iCount + (iCells % 2 == 0 ? ' even' : ' odd');
                            cell.className += (iCells + 1 == mCells ? ' last' : '');
                            cell.className += (classNames ? ' ' + classNames : '');
                            // Don't number format headings
                            content = '';
                            if(rows[iRows].values[iCells] !== null)
                            {
                                if(rows[iRows].style.indexOf('heading') > -1)
                                {
                                    content = rows[iRows].values[iCells];
                                }
                                else
                                {
                                    content = _lib.numberFormat(rows[iRows].values[iCells], null, null, null, _memory.meta.negativeNumberParens);
                                }
                            }
                            content = (content === undefined ? '' : content);
                            cell.innerHTML = content;
                            cell.className = _lib.trim(cell.className);
                            row.appendChild(cell);
                        }
                    }
                    table.rows.push(rows[iRows]);
                    row.className = _lib.trim(row.className);
                    tbody.appendChild(row);
                }
                dom.appendChild(tbody);
                table.dom = dom;
                table.meta = options.data.meta;
                table.labels = options.data.labels;
                table.title = options.data.title;
                table.columnsVisibleGraph = options.data.meta.columnsVisibleGraph;
                table.lastUpdated = options.data.meta.lastUpdated;
                table.dom.style.display = 'none';
                table.parsed = true;
                _modules.table.dom.container.appendChild(table.dom);
                _modules.table.parseTable(tableID);
                _modules.table.autoAdjust(tableID);
                _lib.removeElement(table.dom);
                table.dom.style.display = '';
                _memory.tables[tableID] = _lib.mergeObjects(_memory.tables[tableID], table);
            }
        }
        return result;
    };
    this.parseTableData.rules =
    {
        required : ['data'],
        types :
        {
            data : ['object']
        }
    };


    /**
    * Remove a graph serie.
    *
    * @param {Object} chartIcon Chart icon.
    *                           Required.
    * @param {String} type      Grpah type.
    *                           Optional.
    * @version 1.0 2011-03-18
    * @author Mathias Petersson
    */
    this.removeGraph = function(chartIcon, type)
    {
        var options = _lib.isValidInputs();
        if(options)
        {
            var i, m, rowDOM, rowID, cells, table, row, groupTableData;
            rowDOM = _lib.getParent(options.chartIcon, ['tr']);
            rowID = _modules.table.getRowIdentifier(rowDOM);
            switch(options.type)
            {
                default:
                case 'line':
                    cells = _lib.getRowCells(rowDOM);
                    if(_modules.graph.isGraphed(rowID))
                    {
                        for(i = 0, m = cells.length; i < m; ++i)
                        {
                            cells[i].style.backgroundColor = '';
                        }
                        _lib.removeClass(rowDOM, 'graphed');
                        _lib.setOpacity(options.chartIcon, _this.settings.table.chartIcon.states.normal.opacity);
                        _modules.graph.remove(rowID);
                    }
                break;
                case 'area':
                    _this.clearViewport();
                break;
            }
        }
    };
    this.removeGraph.rules =
    {
        required : ['chartIcon'],
        types :
        {
            chartIcon : ['dom']
        }
    };

    /**
    * Show graph area and related actions
    *
    * @version 1.0 2011-04-27
    * @author Mathias Petersson
    */
    this.showGraphArea = function()
    {
        _modules.graph.show();
        if(_this.dom.actionExport) {
            _this.dom.actionExport.style.display = '';
        }
    };

    // Initialize script //

    _init(settings);

    return arguments.callee.toString();
};
