/************************************************
Grid Gadget
************************************************/
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var Dashboards;
(function (Dashboards) {
    var Models;
    (function (Models) {
        var DataTable;
        (function (DataTable_1) {
            var DataTable = (function () {
                function DataTable() {
                    this.rows = new Array();
                    // add the header row
                    this.rows.push(new DataRow());
                    this.headerRowIndex = 0;
                }
                DataTable.prototype.GetColumns = function () {
                    return this.rows[this.headerRowIndex];
                };
                // returns the column index or -1 if it can't be found
                DataTable.prototype.GetColumnIndex = function (id) {
                    return _.findIndex(this.GetColumns().dataCells, function (c) { return c.id == id; });
                };
                // assume the row id is stored in the first cell (eg first column) of the row
                DataTable.prototype.GetRowIndex = function (id) {
                    var index = -1;
                    var currentIndex = 0;
                    for (var i = 0; i < this.rows.length; i++) {
                        if (this.rows[i].dataCells[0].id == id) {
                            index = currentIndex;
                            break;
                        }
                        currentIndex++;
                    }
                    return index;
                };
                DataTable.prototype.SetCell = function (rowIndex, columnIndex, dataCell) {
                    this.rows[rowIndex].dataCells[columnIndex] = dataCell;
                };
                return DataTable;
            }());
            DataTable_1.DataTable = DataTable;
            var DataRow = (function () {
                function DataRow() {
                    this.dataCells = new Array();
                }
                return DataRow;
            }());
            DataTable_1.DataRow = DataRow;
            var DataCell = (function () {
                function DataCell() {
                    this.id = '';
                    this.cell = null;
                    this.processed = false;
                    this.realtimeData = null;
                    this.topic = null;
                }
                return DataCell;
            }());
            DataTable_1.DataCell = DataCell;
        })(DataTable = Models.DataTable || (Models.DataTable = {}));
    })(Models = Dashboards.Models || (Dashboards.Models = {}));
})(Dashboards || (Dashboards = {}));
var Dashboards;
(function (Dashboards) {
    var Models;
    (function (Models) {
        var RealtimeData = Components.RealtimeData;
        var DT = Dashboards.Models.DataTable;
        var GridGadget = (function (_super) {
            __extends(GridGadget, _super);
            function GridGadget(gadgetOptions) {
                // you must create the renderer first 
                var renderer = new Dashboards.Views.GridRender();
                gadgetOptions.renderer = renderer;
                _super.call(this, gadgetOptions);
            }
            GridGadget.CreateInstance = function (gadgetOptions) {
                var instance = new GridGadget(gadgetOptions);
                return instance;
            };
            // ******************** Gadget Overrides *******************************
            /**
             * Signal to the gadget that its configuration has changed.
             */
            GridGadget.prototype.settingsChanged = function () {
                _super.prototype.settingsChanged.call(this);
                // When settings change, we must invalidate so we do not work on the "old" table
                this.gadgetInitialized = false;
                // data handler must be set up before the setting the pairs or things blow up
                this.generateSourceMeasurementPairs();
                this.CreateDataTable();
                var settingsHandler = this.getHandler();
                var intervalSetting = settingsHandler.byName(Settings.Gadget.GridDataRefreshIntervalSeconds.name);
                var refreshRate = parseInt(intervalSetting);
                this.setupDataHandler(refreshRate);
                this.realtimeDataHandler.updateTimeout(this.pairs.length > 1000 ? 60000 : 30000);
            };
            GridGadget.prototype.canExportData = function () {
                return true;
            };
            GridGadget.prototype.getExportData = function () {
                var _this = this;
                if (!this.dataTable || !this.dataTable.rows || this.dataTable.rows.length <= 1) {
                    return null;
                }
                var allData = [];
                // Header Row for titles
                allData[0] = [];
                _.each(this.dataTable.GetColumns().dataCells, function (headerCell) {
                    allData[0].push(headerCell.cell.text);
                });
                // Set the last update time
                allData[0][0] = this.lastUpdated;
                var rowIndex = 0;
                _.each(this.dataTable.rows, function (row) {
                    // we have already added the header information
                    if (rowIndex != _this.dataTable.headerRowIndex) {
                        var currentRow = [];
                        _.each(row.dataCells, function (cell) {
                            var cellData = _this.dataPoints[cell.id];
                            if (!cellData) {
                                // Use the original data cell, as it is a header or first column
                                cellData = cell;
                            }
                            currentRow.push(cellData.cell.text);
                        });
                        allData.push(currentRow);
                    }
                    rowIndex++;
                });
                var results = {
                    FileName: this.renderer.title,
                    RowData: allData
                };
                return results;
            };
            GridGadget.prototype.destroy = function () {
                _super.prototype.destroy.call(this);
            };
            // ******************** RealtimeDataGadget Overrides ******************
            GridGadget.prototype.refreshData = function () {
                // flip pairs to datacells
                for (var i = 0; i < this.pairs.length; i++) {
                    var pair = this.pairs[i];
                    var data = this.getDataValue(pair.uniqueId);
                    if (data && data.dataPoint) {
                        // Find the data point from the global list and re-add
                        var dc = this.dataPoints[pair.uniqueId];
                        dc.id = data.uniqueId;
                        dc.realtimeData = data;
                        this.processGridCell(dc);
                    }
                }
                // now tell the renderer to update
                this.renderer.refreshData();
            };
            GridGadget.prototype.GetCurrentDataPoints = function () {
                return this.dataPoints;
            };
            GridGadget.prototype.CreateDataTable = function () {
                var _this = this;
                var firstColumnIsSources = this.firstColumnIsSourceNames();
                var sources = _.map(this.pairs, function (p) {
                    return p.source;
                });
                var measurments = _.map(this.pairs, function (p) {
                    return p.measurement;
                });
                // use these to make the source meas ids unique in the table as they are simple numbers
                var rowIdPrefix = 'R';
                var colIdPrefix = 'C';
                var colDef = firstColumnIsSources ? _.uniq(measurments) : _.uniq(sources);
                var rowDef = firstColumnIsSources ? _.uniq(sources) : _.uniq(measurments);
                var dt = new DT.DataTable();
                // we need one additional row for the header
                dt.rows = new Array(rowDef.length + 1);
                for (var i = 0; i < dt.rows.length; i++) {
                    dt.rows[i] = new DT.DataRow();
                    // we need to one additional column for the source or meas name
                    dt.rows[i].dataCells = new Array(colDef.length + 1);
                    if (i == 0) {
                        var displayText = firstColumnIsSources ? i18n.loc.s('General', 'Sources') : i18n.loc.s('General', 'Measurements');
                        var firstHeaderCell = new DT.DataCell();
                        firstHeaderCell.id = '-1';
                        firstHeaderCell.processed = true;
                        firstHeaderCell.cell = {
                            text: displayText,
                            class: '',
                            iconUri: '',
                            sort: displayText,
                            tooltip: displayText
                        };
                        dt.rows[i].dataCells[0] = firstHeaderCell;
                        for (var j = 0; j < colDef.length; j++) {
                            var dc = new DT.DataCell();
                            dc.id = colIdPrefix + colDef[j].Id;
                            this.processGridCell(dc, colDef[j].DisplayName);
                            // in the header row the column 0 is empty
                            dt.rows[i].dataCells[j + 1] = dc;
                        }
                    }
                    else {
                        var dc = new DT.DataCell();
                        dc.id = rowIdPrefix + rowDef[i - 1].Id;
                        this.processGridCell(dc, rowDef[i - 1].DisplayName);
                        dt.rows[i].dataCells[0] = dc;
                    }
                }
                this.dataPoints = {};
                // okay now fill in the value cells
                _.forEach(this.pairs, function (pair) {
                    var dc = new DT.DataCell();
                    dc.id = pair.uniqueId;
                    dc.topic = pair.measurement;
                    var colId = firstColumnIsSources ? pair.measurement.Id : pair.source.Id;
                    var rowId = firstColumnIsSources ? pair.source.Id : pair.measurement.Id;
                    var rowIndex = dt.GetRowIndex(rowIdPrefix + rowId);
                    var colIndex = dt.GetColumnIndex(colIdPrefix + colId);
                    dt.SetCell(rowIndex, colIndex, dc);
                    _this.dataPoints[dc.id] = dc;
                });
                this.dataTable = dt;
            };
            /**
            * Will parse a realtime result, and compile the context for display.
            * This includes display value, tooltip, icon to display as well as the
            * display status.
            */
            GridGadget.prototype.processGridCell = function (data, defaultDisplayText) {
                if (defaultDisplayText === void 0) { defaultDisplayText = ''; }
                var cell = {
                    text: defaultDisplayText,
                    tooltip: defaultDisplayText,
                    class: '',
                    iconUri: '',
                    sort: ''
                };
                if (!data)
                    return;
                data.cell = cell;
                data.processed = true;
                // Ensure errors appear last.
                var errorSortPrefix = 'zzz';
                if (data.realtimeData && data.realtimeData.dataPoint) {
                    var rtValue = data.realtimeData;
                    var dp = rtValue.dataPoint;
                    var responseStatus = dp.validationResults;
                    if (!responseStatus) {
                        console.error('responseStatus is null in renderDataTableCell()');
                        cell.text = 'Invalid responseStatus'; // Dev error                    
                        return;
                    }
                    switch (rtValue.dataPoint.ResponseStatus) {
                        case RealtimeData.RealtimeResponseStatus.NoError:
                            // value to show
                            this.getFormattedCellValue(data);
                            break;
                        case RealtimeData.RealtimeResponseStatus.Pending:
                            // Standard Pending
                            cell.text = '---';
                            cell.sort = errorSortPrefix + '---';
                            cell.class += ' ggCellInvalid';
                            break;
                        case RealtimeData.RealtimeResponseStatus.HierarchyNonnumeric:
                            // "Bad hierarchy agg" value to show
                            this.getFormattedCellValue(data);
                            // We are still showing a value
                            cell.class += ' ggCellWarningValue';
                            cell.iconUri = Dashboards.Views.GridRender.IconWarningUri;
                            break;
                        case RealtimeData.RealtimeResponseStatus.CommunicationError:
                            // Comms error                                
                            if (responseStatus.categoryType == Core.Diagnostics.LogEntryType.Warning) {
                                cell.class += ' ggCellWarningValue';
                                cell.iconUri = Dashboards.Views.GridRender.IconWarningUri;
                                cell.text = i18n.loc.unencoded('Gadgets', 'GridGadget_Cell_Disabled');
                            }
                            else {
                                cell.class += ' ggCellInvalid';
                                cell.iconUri = Dashboards.Views.GridRender.IconConnectionErrorUri;
                                cell.text = i18n.loc.unencoded('Gadgets', 'GridGadget_Cell_Error');
                            }
                            cell.sort = errorSortPrefix + cell.text;
                            break;
                        case RealtimeData.RealtimeResponseStatus.ConfigurationError:
                            // Configuration error                                
                            if (responseStatus.categoryType == Core.Diagnostics.LogEntryType.Warning) {
                                cell.class += ' ggCellWarningValue';
                                cell.iconUri = Dashboards.Views.GridRender.IconWarningUri;
                                cell.text = i18n.loc.unencoded('Gadgets', 'GridGadget_Cell_Disabled');
                            }
                            else {
                                cell.class += ' ggCellInvalid';
                                cell.iconUri = Dashboards.Views.GridRender.IconErrorUri;
                                cell.text = i18n.loc.unencoded('Gadgets', 'GridGadget_Cell_Error');
                            }
                            cell.sort = errorSortPrefix + cell.text;
                            break;
                        case RealtimeData.RealtimeResponseStatus.NotAvailable:
                            // Invalid Measurement
                            if (responseStatus.categoryType == Core.Diagnostics.LogEntryType.Warning) {
                                cell.class += ' ggCellWarningValue';
                                cell.iconUri = Dashboards.Views.GridRender.IconWarningUri;
                                cell.text = i18n.loc.unencoded('Gadgets', 'GridGadget_Cell_NotSupported');
                            }
                            else {
                                cell.class += ' ggCellInvalid';
                                cell.iconUri = Dashboards.Views.GridRender.IconErrorUri;
                                cell.text = i18n.loc.unencoded('Gadgets', 'GridGadget_Cell_Invalid');
                            }
                            cell.sort = errorSortPrefix + cell.text;
                            break;
                        case RealtimeData.RealtimeResponseStatus.AccessDenied:
                            // Access denied
                            cell.class += ' ggCellWarningValue';
                            cell.iconUri = Dashboards.Views.GridRender.IconWarningUri;
                            cell.text = i18n.loc.unencoded('Gadgets', 'GridGadget_Cell_NotAvailable');
                            cell.sort = errorSortPrefix + cell.text;
                            break;
                        case RealtimeData.RealtimeResponseStatus.SourceUnknown:
                            // Bad Source
                            cell.class += ' ggCellWarningValue';
                            cell.iconUri = Dashboards.Views.GridRender.IconUnknownSourceUri;
                            cell.text = i18n.loc.unencoded('Gadgets', 'GridGadget_Cell_UnknownSource');
                            cell.sort = errorSortPrefix + cell.text;
                            break;
                        case RealtimeData.RealtimeResponseStatus.SystemError:
                        case RealtimeData.RealtimeResponseStatus.Invalid:
                        case RealtimeData.RealtimeResponseStatus.Unknown:
                        default:
                            // Bad times...
                            cell.class += ' ggCellWarningValue';
                            cell.iconUri = Dashboards.Views.GridRender.IconErrorUri;
                            cell.text = i18n.loc.unencoded('Gadgets', 'GridGadget_Cell_Error');
                            cell.sort = errorSortPrefix + cell.text;
                            break;
                    }
                    // check for a stale state (but do not override any existing icon)
                    if (rtValue.dataPoint.Quality == RealtimeData.RealtimeQuality.Stale && !cell.iconUri) {
                        cell.class += ' ggCellWarningValue';
                        cell.iconUri = Dashboards.Views.GridRender.IconStaleUri;
                    }
                    // Add tooltip - Value and status if possible
                    if (rtValue.dataPoint.ResponseStatus == RealtimeData.RealtimeResponseStatus.Pending) {
                        // Special case, just show the waiting text
                        cell.tooltip = responseStatus.detail;
                    }
                    else if (responseStatus.detail) {
                        cell.tooltip = StringUtil.format('{0}: {1}', cell.text, responseStatus.detail);
                    }
                    else {
                        cell.tooltip = cell.text;
                    }
                }
            };
            GridGadget.prototype.getFormattedCellValue = function (data) {
                var displayValue = '';
                var sortValue = '';
                var rawValue = data.realtimeData.dataPoint.Value;
                if (typeof rawValue === 'number') {
                    // If the value is a number, check the metadata to 
                    // see if it is a datetime value. We can also check
                    // if the value is a cost/price, but we currently 
                    // don't have any measurements which support it.
                    if (data.topic.Metadata &&
                        data.topic.Metadata[Controls.Smp.MeasurementSelector.MetadataMeasuredProperty] &&
                        data.topic.Metadata[Controls.Smp.MeasurementSelector.MetadataMeasuredProperty] === Controls.Smp.MeasurementSelector.MetadataMeasuredPropertyDateTime) {
                        // The Date() constructor in JavaScript creates
                        // a date in the browser's local timezone. The 
                        // value being passed in is epoch ticks in UTC. 
                        var rawDate = new Date(rawValue * 1000);
                        // Add the number of minutes in the Timezone 
                        // offset so the local time is correct and 
                        // formatDate works correctly.
                        rawDate = rawDate.addMinutes(rawDate.getTimezoneOffset());
                        displayValue = i18n.formatDate(rawDate, i18n.dateFormat.shortDate + ' ' + i18n.dateFormat.longTime);
                        // We round all numbers to 2 decimals, and then convert to a string to pad out to 12 characters
                        var sortNumber = NumberUtil.round(rawValue, 3);
                        sortValue = '1d' + sortNumber;
                        data.cell.class += ' ggCellDate';
                    }
                    else {
                        var precision = 0;
                        if (data.topic.Metadata) {
                            var groupType = data.topic.Metadata[Controls.Smp.MeasurementSelector.MetadataGroupKey];
                            switch (groupType) {
                                case Controls.Smp.MeasurementSelector.MetadataGroupKeyEnergy:
                                case Controls.Smp.MeasurementSelector.MetadataGroupKeyDemand:
                                case Controls.Smp.MeasurementSelector.MetadataGroupKeyPower:
                                case Controls.Smp.MeasurementSelector.MetadataGroupKeyVoltage:
                                case Controls.Smp.MeasurementSelector.MetadataGroupKeyCurrent:
                                    precision = 0;
                                    break;
                                case Controls.Smp.MeasurementSelector.MetadataGroupKeyFrequency:
                                case Controls.Smp.MeasurementSelector.MetadataGroupKeyPowerFactor:
                                    precision = 1;
                                    break;
                                case Controls.Smp.MeasurementSelector.MetadataGroupKeyTHD:
                                case Controls.Smp.MeasurementSelector.MetadataGroupKeyCurrencies:
                                    //case Controls.Smp.MeasurementSelector.MetadataGroupKeyPowerQuality:
                                    precision = 2;
                                    break;
                                default:
                                    // For numbers with a decimal, use 1 decimal place.
                                    rawValue = parseFloat(rawValue.toString());
                                    if (rawValue % 1 != 0) {
                                        precision = 1;
                                    }
                            }
                        }
                        // We round all numbers to 2 decimals, and then convert to a string to pad out to 16 characters
                        var sortNumber = NumberUtil.round(rawValue, 2);
                        sortValue = '1a' + StringUtil.padLeft(sortNumber, '0', 16);
                        // Display format is a simple format
                        displayValue = i18n.formatNumber(rawValue, precision);
                    }
                }
                else if (typeof rawValue === 'boolean') {
                    displayValue = rawValue ? i18n.loc.s('General', 'True') : i18n.loc.s('General', 'False');
                    // this will ensure bools are grouped
                    sortValue = '1b' + displayValue;
                }
                else if (rawValue === null) {
                    displayValue = i18n.loc.unencoded('General', 'NotApplicable');
                    sortValue = 'zaNA' + displayValue; // We want these before Hierarchy warning NAs
                }
                else {
                    // Show raw
                    displayValue = rawValue;
                    sortValue = 'zRaw' + rawValue;
                }
                data.cell.text = displayValue;
                data.cell.sort = '' + sortValue; // Ensure it is a string.
                return displayValue;
            };
            // returns true is the header row should contain measurements
            GridGadget.prototype.firstColumnIsSourceNames = function () {
                var firstColumnSource = true;
                var handler = this.getHandler();
                if (handler) {
                    var value = handler.byName(Settings.Gadget.FirstColumnContents);
                    if (value) {
                        firstColumnSource = (value == Dashboards.SetupControl.GridConfiguration.sourceColumns);
                    }
                }
                return firstColumnSource;
            };
            GridGadget.TypeId = "5407e1cf-8822-4e69-bf45-6cdb0346b6e7";
            return GridGadget;
        }(Models.RealtimeDataGadget));
        Models.GridGadget = GridGadget;
    })(Models = Dashboards.Models || (Dashboards.Models = {}));
})(Dashboards || (Dashboards = {}));
var Dashboards;
(function (Dashboards) {
    var Views;
    (function (Views) {
        var GridRender = (function (_super) {
            __extends(GridRender, _super);
            function GridRender() {
                _super.call(this);
                this.configuredColumnWidth = 120;
                // This can be an increased value if we have more width avail than Columns X configuredColumnWidth.
                this.effectiveColumnWidth = 0;
                this.firstColumnWidth = GridRender.MaxFirstColumnWidth;
                this.renderedErrorState = false;
                this.gridVisible = true;
                this.isSimpleRenderMode = false;
                // jquery datatable
                this.dataTable = null;
                this.dataCellMap = {};
                if (!GridRender.IconStaleUri) {
                    // Instantiate icon uris
                    GridRender.IconStaleUri = fwk.url.combine('RootApp', 'Content/Gadgets/GridGadget/slow_48.png');
                    GridRender.IconWarningUri = fwk.url.combine('RootApp', 'Content/Gadgets/GridGadget/warning_48.png');
                    GridRender.IconErrorUri = fwk.url.combine('RootApp', 'Content/Gadgets/GridGadget/error_48.png');
                    GridRender.IconConnectionErrorUri = fwk.url.combine('RootApp', 'Content/Gadgets/GridGadget/connection_error_48.png');
                    GridRender.IconUnknownSourceUri = fwk.url.combine('RootApp', 'Content/Gadgets/GridGadget/unknown_source_48.png');
                }
            }
            GridRender.prototype.destroy = function () {
                this.dataTable.destroy(true);
                this.$gadgetRender.remove();
                _super.prototype.destroy.call(this);
            };
            GridRender.prototype.renderGadget = function () {
                var _this = this;
                var callBack = new Core.CallBack(function (template) {
                    if (!_this.$gadgetRender)
                        return; // We have been destroyed!
                    Views.Gadget.RemoveStatusMessage(_this.$gadgetRender);
                    // need to have the template added to the dom before creating table
                    _this.$gadgetRender.empty();
                    _this.$gadgetRender.html(template);
                    _this.initalizeSettings();
                    _this.dataTable = _this.createDataTable(_this.gadget.dataTable);
                    _this.$gadgetRender.find('.' + GridRender.ClassDataTable).addClass('allowSelect');
                    if (_this.isSimpleRenderMode) {
                        _this.$gadgetRender.find('.' + GridRender.ClassDataTable).addClass('simpleDataTable');
                    }
                    _this.gadget.gadgetInitialized = true;
                    // update the height and redraw if necessary
                    // sometimes the act of redrawing affects the header height
                    _this.calculateDataTableSizes();
                    _this.calculateColumnWidths();
                    _this.refreshData();
                    _this.checkTableDimensions();
                }, this);
                var loadedTemplate = TemplateUtil.LocAndLoad(GridRender.RenderTemplateUri, callBack);
            };
            GridRender.prototype.refresh = function () {
                _super.prototype.refresh.call(this);
                if (this.getDisplayFrame() && this.dataTable) {
                    // update the height and redraw if necessary
                    // sometimes the act of redrawing affects the header height
                    this.calculateDataTableSizes();
                    this.redrawDataTable(true);
                    this.checkTableDimensions();
                }
            };
            GridRender.prototype.refreshData = function () {
                _super.prototype.refreshData.call(this);
                this.redrawDataTable(false);
            };
            GridRender.prototype.statusUpdate = function (status, text) {
                var renderBadState = this.gadget.isActiveNetworkIssue() || status === Dashboards.Models.RealtimeDataHandler.RealtimeDataStatus.Paused;
                if (renderBadState && !this.renderedErrorState) {
                    this.$gadgetProper.find('.dataTables_scroll td').addClass('networkIssues');
                    this.$gadgetProper.find('.dataTables_scroll td div').addClass('networkIssues');
                    this.renderedErrorState = true;
                }
                else if (!renderBadState && this.renderedErrorState) {
                    this.$gadgetProper.find('.dataTables_scroll td ').removeClass('networkIssues');
                    this.$gadgetProper.find('.dataTables_scroll td div').removeClass('networkIssues');
                    this.renderedErrorState = false;
                }
                _super.prototype.statusUpdate.call(this, status, text);
            };
            GridRender.prototype.initalizeSettings = function () {
                this.renderedErrorState = false;
                // Get the configured Column Width value
                var minColWidthString = this.getHandler().byName(Settings.Gadget.MinimumColumnWidth);
                this.configuredColumnWidth = this.getValue(minColWidthString) || 120;
                // Get render mode value
                var simpleRenderEnabled = this.getHandler().byName(Settings.Gadget.SimpleRenderEnabled);
                this.isSimpleRenderMode = simpleRenderEnabled === 'true';
            };
            GridRender.prototype.createDataTable = function (dt) {
                var _this = this;
                var colIdx = 0;
                var cols = _.map(dt.GetColumns().dataCells, function (c) {
                    var $header = $('<div/>')
                        .addClass('ggHeaderCell ellipsis')
                        .prop('title', c.cell.tooltip)
                        .text(c.cell.text);
                    if (colIdx != 0) {
                        $header.attr('style', 'width:' + _this.configuredColumnWidth + 'px');
                    }
                    colIdx++;
                    return { title: $header[0].outerHTML };
                });
                var colDefs = new Array();
                // first col is source or meas name column
                colDefs.push({
                    targets: 0,
                    type: 'string',
                    render: function (data, type, row) {
                        if (type == 'sort') {
                            return data.cell && data.cell.sort ? data.cell.sort : data.cell.text;
                        }
                        else {
                            return _this.renderFirstColumnCell(data);
                        }
                    }
                });
                // rest of the columns contain data
                colDefs.push({
                    targets: '_all',
                    type: 'string',
                    render: function (data, type, row) {
                        if (type == 'display') {
                            return _this.renderDataTableCell(data);
                        }
                        else if (type == 'sort') {
                            console.log(data.cell ? data.cell.sort : '-');
                            return data.cell ? data.cell.sort : '-';
                        }
                        else {
                            return '';
                        }
                    }
                });
                // don't have the typing for fixed columns so we need to use any
                var tableOptions = {
                    columns: cols,
                    columnDefs: colDefs,
                    scrollX: true,
                    paging: false,
                    aaSorting: [],
                    fixedColumns: true,
                    ordering: !this.isSimpleRenderMode,
                    searching: false,
                    info: false
                };
                var table = this.$gadgetRender.find('.' + GridRender.ClassDataTable).DataTable(tableOptions);
                var fixedColumnNames = new Array();
                // now add all the rows but skip the header row as the table already has it
                for (var i = 1; i < dt.rows.length; i++) {
                    table.row.add(dt.rows[i].dataCells);
                    fixedColumnNames.push(dt.rows[i].dataCells[0].cell.text);
                }
                this.firstColumnWidth = this.calculateFirstColumnWidth(fixedColumnNames);
                // stuff cells into hash map to speed look up
                var dataCells = table.cells().data();
                _.forEach(dataCells, function (dc) {
                    _this.dataCellMap[dc.id] = dc;
                });
                return table;
            };
            GridRender.prototype.redrawDataTable = function (calculateColumnWidths) {
                if (this.dataTable) {
                    var $scrollBody = this.getDisplayFrame().find('.dataTables_scrollBody');
                    var origScrollTop = $scrollBody.scrollTop();
                    if (calculateColumnWidths) {
                        this.calculateColumnWidths();
                    }
                    this.dataTable.rows().invalidate().draw();
                    if (origScrollTop != 0) {
                        $scrollBody.scrollTop(origScrollTop);
                    }
                }
            };
            GridRender.prototype.calculateColumnWidths = function () {
                var originalColumnWidth = this.effectiveColumnWidth;
                // Calculate to see if we are going to be smaller than configured for
                var totalDataColumns = this.gadget.dataTable.GetColumns().dataCells.length - 1;
                var actualColWidth = this.configuredColumnWidth + 5;
                var totalDataColumnWidth = totalDataColumns * actualColWidth;
                var totalColumnWidth = totalDataColumnWidth + this.firstColumnWidth + 10; // 5 for buffer
                var availableWidth = Math.min(this.getDisplayFrame().find('.dataTables_scroll').width(), this.getDisplayFrame().find('.gridGadgetWrapper').width());
                this.effectiveColumnWidth = this.configuredColumnWidth; // Default
                if (totalColumnWidth < availableWidth) {
                    // We have more room than we are configured for, so we need to increase the column size.
                    var effectiveTotalWidth = availableWidth - (this.firstColumnWidth + 10) - 20; // Sub an extra 20 incase there is a scroll bar
                    this.effectiveColumnWidth = Math.floor(effectiveTotalWidth / totalDataColumns) - 10; // There is always 5px of padding/margin
                    if (this.effectiveColumnWidth < this.configuredColumnWidth) {
                        this.effectiveColumnWidth = this.configuredColumnWidth; // Failsafe
                    }
                }
                if (originalColumnWidth != this.effectiveColumnWidth) {
                    // Update the headers
                    var cols = this.dataTable.columns().header();
                    cols.shift(); // Pop off the first column
                    $(cols).find('.ggHeaderCell').attr('style', 'width:' + this.effectiveColumnWidth + 'px');
                }
            };
            GridRender.prototype.renderFirstColumnCell = function (data) {
                var output = '';
                if (data) {
                    var $output = $('<div/>');
                    $output.prop('title', data.cell.tooltip);
                    $output.addClass('ggFirstColumnCell ellipsis');
                    $output.width(this.firstColumnWidth);
                    $output.text(data.cell.text);
                    output = $output[0].outerHTML;
                }
                return output;
            };
            GridRender.prototype.calculateFirstColumnWidth = function (displayStrings) {
                var width = GridRender.MaxFirstColumnWidth;
                // find the longest string
                var longestString = displayStrings.reduce(function (a, b) { return a.length > b.length ? a : b; });
                // append to the dom and get the width
                var span = $(document.createElement('span')).html(longestString);
                span.css('position', 'absolute');
                span.css('visibility', 'hidden');
                span.css('height', 'auto');
                span.css('width', 'auto');
                span.css('white-space', 'nowrap');
                this.$gadgetContent.append(span);
                var textWidth = span.width() + 45; // +30 for Padding and 5 to ensure it all fits
                // add remove it
                span.remove();
                // keep it within the min and max
                if (textWidth < GridRender.MinFirstColumnWidth) {
                    width = GridRender.MinFirstColumnWidth;
                }
                else if (textWidth < GridRender.MaxFirstColumnWidth) {
                    width = textWidth;
                }
                return width;
            };
            GridRender.prototype.renderDataTableCell = function (data) {
                if (!data.processed) {
                    data.cell = {
                        text: '---',
                        sort: '---',
                        class: 'ggCellInvalid',
                        iconUri: '',
                        tooltip: ''
                    };
                }
                var output = '';
                if (this.isSimpleRenderMode) {
                    output = data.cell.text;
                }
                else {
                    var $output = $('<div/>');
                    $output.addClass('ggCell');
                    $output.addClass(data.cell.class);
                    $output.prop('title', data.cell.tooltip);
                    var $value = $('<div/>');
                    $value.text(data.cell.text);
                    $value.addClass('ggValue ellipsis');
                    // TD Width is 10 px + Col Width.  Icon is 24.  
                    // ColWidth + 10 = Cell - 24px icon - 6px padding/margin
                    // Cell = ColWidth + 10 - 24 - 6
                    // Cell = ColWidth - 20
                    $value.css('max-width', this.effectiveColumnWidth - 20);
                    $output.append($value);
                    if (data.cell.iconUri) {
                        var $iconWrapper = $('<img/>');
                        $iconWrapper.addClass('ggIcon');
                        $iconWrapper.prop('src', data.cell.iconUri);
                        $output.append($iconWrapper);
                    }
                    else {
                        var $fakeIconWrapper = $('<div/>');
                        $fakeIconWrapper.addClass('ggIcon');
                        $output.append($fakeIconWrapper);
                    }
                    output = $output[0].outerHTML;
                }
                return output;
            };
            // Calculates the grid size, and sets the appropriate size parameters for a sane rendering.
            // Update the heights of the jquery data table if necessary
            GridRender.prototype.calculateDataTableSizes = function () {
                var proposedHeight = this.calculateDataTableHeight();
                // the official way to update a datatable's height
                this.$gadgetContent.find('div.dataTables_scrollBody').height(proposedHeight);
            };
            GridRender.prototype.checkTableDimensions = function () {
                if (this.getDisplayFrame().height() > 80 && this.getDisplayFrame().width() > 200) {
                    if (!this.gridVisible) {
                        // we have enough room
                        this.ClearGridStatusMessage();
                        // using show() and hide() will set the dimensions of the table to zero which then 
                        // means we can show the table so instead we will use visiblity which doesn't affect the table dimensions
                        this.changeDataTableVisibility('visible');
                        this.gridVisible = true;
                    }
                }
                else {
                    if (this.gridVisible) {
                        // not enough room
                        this.RenderGridStatusMessage();
                        this.changeDataTableVisibility('hidden');
                        this.gridVisible = false;
                    }
                }
            };
            GridRender.prototype.changeDataTableVisibility = function (value) {
                this.$gadgetRender.find('.' + GridRender.ClassDataTable).css('visibility', value);
                this.$gadgetRender.find('.' + GridRender.ClassDataTablesScroll).css('visibility', value);
            };
            GridRender.prototype.RenderGridStatusMessage = function () {
                var div = this.getDisplayFrame().find('#GridStatusMessage');
                div.height(this.getDisplayFrame().height());
                this.getDisplayFrame().find('.gridGadgetWrapper').hide();
                Views.Gadget.RenderStatusMessage(div, i18n.loc.unencoded('Gadgets', 'GridGadget_NotEnoughRoomToRenderGrid'));
            };
            GridRender.prototype.ClearGridStatusMessage = function () {
                var div = this.getDisplayFrame().find('#GridStatusMessage');
                div.height(0);
                this.getDisplayFrame().find('.gridGadgetWrapper').show();
                Views.Gadget.RemoveStatusMessage(this.getDisplayFrame().find('#GridStatusMessage'));
            };
            GridRender.prototype.calculateDataTableHeight = function () {
                var availableHeight = this.getDisplayFrame().height();
                availableHeight = availableHeight - 40 - 20; //40px for the Table Header and 20 px for table padding
                return availableHeight;
            };
            GridRender.prototype.getValue = function (valueString) {
                var value = parseFloat(valueString);
                return (isNaN(value) ? 0 : value);
            };
            GridRender.ClassDataTablesScroll = 'dataTables_scroll';
            GridRender.ClassDataTable = 'dataTable';
            GridRender.MaxFirstColumnWidth = 250;
            GridRender.MinFirstColumnWidth = 100;
            GridRender.RenderTemplateUri = 'Content/Gadgets/GridGadget/GridGadgetTemplate.html';
            return GridRender;
        }(Views.RealtimeDataRender));
        Views.GridRender = GridRender;
    })(Views = Dashboards.Views || (Dashboards.Views = {}));
})(Dashboards || (Dashboards = {}));
// Register the gadget type
Dashboards.Controllers.GadgetType.RegisterDefinition({
    typeId: Dashboards.Models.GridGadget.TypeId,
    create: Dashboards.Models.GridGadget.CreateInstance,
    resourceSet: 'Gadgets'
});
//# sourceMappingURL=GridGadget.js.map