Polymer({is: "ti-rov-customview",
    behaviors: [
      rovBehaviors.viewBehaviors
    ],

    properties: {

        moduleName: {
          type: String,
          value: ''
        },

        viewName: {
            type:  String,
            value: ''
        },

        viewRefresh: { /* recommended view state indicator */
            type:  Boolean,
            value: false
        },

        viewList : {
            type: Object,
            value: {}
        },

        tableName: {
            type: String,
            value: ''
        },

        sameModuleView : {
            type: Boolean,
            value: true
        },

        requests: {        /* outstanding requests */
            type: Number,
            value: 0
        },

        rovCells : {
            type: Array,
            value: []
        },

        removeButtonHidden: {
            type: Boolean,
            value: false
        },

        selectedCell: {
            type: Object,
            value: function() { return {};}
        },

        primaryKeyMenuItems: {
            type: Array,
            value: []
        },

        primaryKeyMenuLabel: {
            type: String,
            value: ''
        },

        primaryKeySectionHidden: {
            type: Boolean,
            value: false
        },

        persistProperties: {
            type: Array,
            value: ['tableName', 'rovCells']
        },

        dataRefresh: {
            type:  Boolean,
            value: false
        },

        viewsData : {
          type: Object,
          value: null
        }

    },

/*
    rovCell = {module,
                view,
                args,
                viewArgs,
                argsId,
                viewType,
                firstArg,
                selectedColumnName,
                displayColumnName,
                primaryKeyColumnName,
                primaryKeyColumnValue,
                primaryKeyColumns,
                assignedName,
                viewData,
                columns,
                format,
                formula,
                origVal,
                val,
                status,
                viewData
    }
*/
    parseCellFormula : function (cellName, cellFormula) {
        var decls = [];
        for (var i = 0; i < this.rovCells.length; i++) {
            if (this.rovCells[i].displayColumnName != cellName) {
                var pattern = RegExp(this.rovCells[i].displayColumnName);
                if (cellFormula.match(pattern)) {
                    var decl = 'var ' + this.rovCells[i].displayColumnName + '=' + this.rovCells[i].val;
                    decls.push(decl);
                }
            }
        }
        return (decls.length > 0 ? decls.join(';') + ';': null);
    },
    addCustomCell : function (e) {
        var cell = {};
        cell.isCustom = true;
        cell.displayColumnName = this.$.assignedCellNameInput.value;
        var val = '';
        if (this.$.cellFormulaInput.value != '') {
            var decls = this.parseCellFormula(cell.displayColumnName,
                                              this.$.cellFormulaInput.value);
            var eStr = decls + this.$.cellFormulaInput.value + ';';
            try {
                val = String(eval(eStr));
            }
            catch (e) {
                this.$.cellFormulaInputInvalid.hidden = false;
                return;
            }
        }
        cell.val = val;
        cell.formula = this.$.cellFormulaInput.value;
        this.rovCells.push(cell);
        this.set('removeButtonHidden', this.rovCells.length == 1);
        var tableData = this.formatTableData();
        this.$.tiRovTable.displayTable(tableData.data, this.viewName, 'CUSTOM', tableData.columns, true);
        this.$.cellPropertiesDialog.close();
    },
    newCustomCell : function (e) {
        this.set('selectedCell', {newCell: true, isCustom: true, displayColumnName: this.newCustomCellName(), formula: ''});
        this.cellPropertiesDialog(e);
    },
    newCustomCellName : function () {
        return ('cell_0');
    },
    getCustomCellValue : function (cell) {
        var value = {};
        value.val = String(Number(cell.val) + 1);
        value.status = null;
        return (value);
    },

   /*
    *  ======== addCell ========
    */
    addCell : function (newCell) {
/*
        if (this.$.customViewOptionsMenuDialog.opened) {
            this.$.customViewOptionsMenuDialog.close();
        }
*/
        if (this.sameModuleView) {
            this.sameModuleView = this.isSameModuleView(this.rovCells[0], newCell);
        }

        var cell = {};
        cell.args = newCell.args;
        cell.module = newCell.module;
        cell.view = newCell.view;
        cell.viewType = this.getViewType(cell.module, cell.view);
        cell.viewArgs = rovUtils.shallowCopy(newCell.viewArgs);
        cell.argsId = newCell.argsId;
        cell.selectedColumnName = newCell.selectedColumnName;
        cell.primaryKeyColumnName = newCell.primaryKeyColumnName;
        cell.primaryKeyColumnValue = newCell.primaryKeyColumnValue;
        cell.val = newCell.selectedColumnValue;
        if (this.sameModuleView && this.rovCells[0].viewData) {
            cell.viewData = this.rovCells[0].viewData;
        }
        else {
            cell.viewData = newCell.viewData;
        }
        if (cell.args) {
            cell.firstArg = cell.args.substr(1, cell.args.indexOf(',') - 1);
        }
        else if (cell.viewType != 'MODULE') {
            cell.columns = this.getViewColumns(cell.module, cell.view);
            cell.primaryKeyColumns = [];
            for (var i = 0; i < cell.columns.length; i++) {
                if (cell.columns[i] != cell.selectedColumnName) {
                    cell.primaryKeyColumns.push(cell.columns[i]);
                }
            }
        }
        cell.displayColumnName = this.checkDisplayColumnName(this.nameCell(cell));
        this.rovCells.push(cell);
        this.set('removeButtonHidden', this.rovCells.length == 1);
        var tableData = this.formatTableData();
        this.$.tiRovTable.displayTable(tableData.data, this.viewName, 'CUSTOM', tableData.columns, true);
    },

   /*
    *  ======== attached ========
    */
    attached : function () {
        this.rovCells = [];
        this.viewList = document.querySelector('ti-rov-panel').getViewList();
        this.viewName = this.tableName;
        for (var i = 0; i < this.viewCells.length; i++) {
            var cell = {};
            cell.args = this.viewCells[i].args;
            cell.module = this.viewCells[i].module;
            cell.view = this.viewCells[i].view;
            cell.viewType = this.getViewType(cell.module, cell.view);
            cell.viewArgs = rovUtils.shallowCopy(this.viewCells[i].viewArgs);
            cell.argsId = this.viewCells[i].argsId;
            cell.selectedColumnName = this.viewCells[i].selectedColumnName;
            cell.primaryKeyColumnName = this.viewCells[i].primaryKeyColumnName;
            cell.primaryKeyColumnValue = this.viewCells[i].primaryKeyColumnValue;
            if (this.viewCells[i].selectedColumnValue) {
                cell.format = rovUtils.getFormat(this.viewCells[i].selectedColumnValue);
            }
            cell.formula = this.viewCells[i].formula ? this.viewCells[i].formula : '';
            if (cell.args) {
                cell.firstArg = cell.args.substr(1, cell.args.indexOf(',') - 1);
            }
            else if (cell.viewType != 'MODULE') {
                cell.columns = this.getViewColumns(cell.module, cell.view);
                cell.primaryKeyColumns = [];
                for (var j = 0; j < cell.columns.length; j++) {
                    if (cell.columns[j] != cell.selectedColumnName) {
                        cell.primaryKeyColumns.push(cell.columns[j]);
                    }
                }
            }
            cell.displayColumnName = this.viewCells[i].displayColumnName ?
                                     this.viewCells[i].displayColumnName : this.nameCell(cell);
            this.rovCells.push(cell);
        }
        this.set('removeButtonHidden', this.rovCells.length == 1);

        /* initialize all our state */
        this.sameModuleView = true;
        for (var i = 0; i < this.rovCells.length - 1; i++) {
            for (j = i + 1; j < this.rovCells.length; j++) {
                if (!this.isSameModuleView(this.rovCells[i], this.rovCells[j])) {
                    this.sameModuleView = false;
                    break;
                }
            }
            if (!this.sameModuleView) {
                break;
            }
        }
        if (this.viewsData != null) {
            this.$.tiRovTable.setViewsData(this.viewsData);
        }
        this.onRefresh();
    },

   /*
    *  ======== cellNameMenuItemSelected ========
    */
    cellNameMenuItemSelected : function (e) {
        this.$.cellNamesMenu.selected = -1;
        if (e.srcElement.id != 'icon') {  /* delete trace button */
            var idElem = e.currentTarget.lastElementChild;
            var i = Number(idElem.id.substr(idElem.id.indexOf('_') + 1));
            this.set('selectedCell', this.rovCells[i]);
            this.selectedCell.index = i;
            this.cellPropertiesDialog(e);
        }
    },

   /*
    *  ======== cellPropertiesDialog ========
    */
    cellPropertiesDialog : function (event) {
        this.$.cellFormulaInputInvalid.hidden = true;
        this.cellPropertiesDlgTitle = this.selectedCell.newCell ? 'New cell properties' : 'Cell properties';
        if (!this.selectedCell.args && this.selectedCell.viewType != 'MODULE' && !this.selectedCell.isCustom) {
            this.primaryKeySectionHidden = false;
            var primaryKeyMenuItems = [];
            var primaryKeyColumns = this.selectedCell.primaryKeyColumns;
            var maxStr = '';
            var pKeyIndex = 0;
            for (var i = 0; i < primaryKeyColumns.length; i++) {
                var value = this.getCellValue(this.selectedCell.viewType,
                                              this.selectedCell.primaryKeyColumnName, this.selectedCell.primaryKeyColumnValue,
                                              primaryKeyColumns[i], this.selectedCell.viewData);
                primaryKeyMenuItems.push(primaryKeyColumns[i] + ':  ' + value.val);
                if (primaryKeyColumns[i] == this.selectedCell.primaryKeyColumnName) {
                    pKeyIndex = i;
                }
                if (primaryKeyMenuItems[i].length > maxStr.length) {
                    maxStr = primaryKeyMenuItems[i];
                }
            }

            this.set('primaryKeyMenuItems', primaryKeyMenuItems);
            this.set('primaryKeyMenuLabel', this.selectedCell.primaryKeyColumnName + ':  ' +  this.selectedCell.primaryKeyColumnValue);
        }
        else {
            this.primaryKeySectionHidden = true;
        }
        this.$.assignedCellNameInput.value = this.selectedCell.displayColumnName;
        this.$.cellFormulaInput.value = this.selectedCell.formula;

        /* for margins, checkbox and droplists */
        var width = rovUtils.getStringWidth(maxStr);
        this.$.primaryKeyMenu.$.menuButton.style.width = width + 'px';

        if (this.selectedCell.newCell) {
            var left = document.querySelector('ti-rov-panel').isNarrow() ?
                       this.offsetLeft + this.offsetWidth :
                       this.offsetLeft + this.offsetWidth + rovUtils.leftPaneWidth;
        }
        else {
            var left = event.x;
        }
        if ((left + width + 100) > document.documentElement.clientWidth) {
            left -= (width + 100);
        }
        var dialog = this.$.cellPropertiesDialog;
        dialog.resetFit();
        dialog.style.left = left + 'px';
        dialog.style.top = event.y + 'px';
        dialog.open();
        dialog.style.zIndex = String(document.querySelector('ti-rov-panel').getMaxZindex() + 1);
        if (this.$.tableSettingsMenu.selected != undefined) {
            this.$.tableSettingsMenu.selected = -1;
        }
    },

   /*
    *  ======== cellPropertiesDialogOkClicked ========
    */
    cellPropertiesDialogOkClicked : function (e) {
        if (this.selectedCell.newCell) {
            this.addCustomCell(e);
            return;
        }
        var keyChanged = false;
        if (!this.selectedCell.args && this.selectedCell.viewType != 'MODULE' && !this.selectedCell.isCustom) {
            var label = this.$.primaryKeyMenu.selectedItemLabel ?
                        this.$.primaryKeyMenu.selectedItemLabel :
                        this.$.primaryKeyMenu.label;
            var props = this.getSelectedKeyProperties(label);
            if (this.selectedCell.primaryKeyColumnName != props.key) {
                this.selectedCell.primaryKeyColumnName = props.key;
                this.selectedCell.primaryKeyColumnValue = props.value;
                keyChanged = true;
            }
        }
        var titleChanged = this.selectedCell.displayColumnName != this.$.assignedCellNameInput.value;
        var formulaChanged = this.selectedCell.formula != this.$.cellFormulaInput.value;
        if (keyChanged) {
            this.set('cellNamesMenuItems.' + this.selectedCell.index + '.id', props.value + ',' + props.key);
        }
        if (titleChanged) {
            var prevTitle = this.selectedCell.displayColumnName;
            this.set('cellNamesMenuItems.' + this.selectedCell.index + '.label',  this.$.assignedCellNameInput.value);
        }
        if (keyChanged || titleChanged) {
            this.$.cellNamesMenuTemplate.render();
        }
        if (formulaChanged) {
            if (this.$.cellFormulaInput.value != '') {
                if (this.selectedCell.isCustom) {
                    var decls = this.parseCellFormula(this.selectedCell.displayColumnName,
                                                      this.$.cellFormulaInput.value);
                    var eStr = decls + this.$.cellFormulaInput.value + ';';
                }
                else {
                    /* must start with an operator for now */
                    var eStr = String(this.selectedCell.val);
                    eStr += String(this.$.cellFormulaInput.value);
                }
                try {
                    var val = String(eval(eStr));
                }
                catch (e) {
                    this.$.cellFormulaInputInvalid.hidden = false;
                    return;
                }
                this.selectedCell.val = val;
            }
            else if (!this.selectedCell.isCustom) {
                this.selectedCell.val = this.selectedCell.origVal;
            }
        }
        this.selectedCell.displayColumnName = this.$.assignedCellNameInput.value;
        this.selectedCell.formula = this.$.cellFormulaInput.value;
        if (titleChanged || formulaChanged) {
            if (titleChanged) {
                this.$.tiRovTable.columnNameChanged(prevTitle, this.selectedCell.displayColumnName);
            }
            var tableData = this.formatTableData();
            this.$.tiRovTable.displayTable(tableData.data, this.viewName, 'CUSTOM', tableData.columns, true);
        }
        this.$.cellPropertiesDialog.close();
    },

   /*
    *  ======== cellTooltip ========
    */
    cellTooltip : function (cell) {
        if (cell.isCustom) {
            var tooltip = 'Custom cell';
        }
        else {
            var tooltip = 'Module: ' + cell.module;
            if (cell.args) {
                if (cell.view == 'Variable') {
                    tooltip += '\nVariable: ' + cell.firstArg;
                }
                else {
                    tooltip += '\nView: ' + this.rovCells[i].view;
                    var args = cell.viewArgs[cell.argsId].args;
                    for(var j = 0; j < args.length; j++) {
                        tooltip += '\n' + args[j].name + ': ' + args[j].value;
                    }
                }
            }
            else {
                tooltip += '\nView: ' + cell.view;
            }
            tooltip += '\nColumn: ' + cell.selectedColumnName;
            tooltip += '\n' + cell.primaryKeyColumnName + ': ' + cell.primaryKeyColumnValue;
        }
        return (tooltip);
    },

   /*
    *  ======== checkDisplayColumnName ========
    */
    checkDisplayColumnName : function (displayColumnName) {
        var maxId = -1;
        for (var i = 0; i < this.rovCells.length; i++) {
            if (this.rovCells[i].displayColumnName == displayColumnName) {
                if (maxId == -1) {
                    maxId = 0;
                }
                if (this.rovCells[i].displayColumnName.indexOf(displayColumnName + '_') >= 0) {
                    var arr = this.rovCells[i].displayColumnName.split('_');
                    if (Number(arr[1]) > maxId) {
                        maxId = Number(arr[1]);
                    }
                }
            }
        }
        return ((maxId == -1) ? displayColumnName : displayColumnName + '_' + (maxId + 1));
    },


   /*
    *  ======== closeTableSettingsClicked ========
    */
    closeTableSettingsClicked : function (e) {
        this.$.tableSettingsMenuDialog.close();
    },

   /*
    *  ======== columnsTapped ========
    */
    columnsTapped : function(e) {
        var panel = document.querySelector('ti-rov-panel');
        this.$.tiRovTable.columnsContextMenu(e, panel.viewContainer, panel.isNarrow() ? 0: rovUtils.leftPaneWidth);
    },

   /*
    *  ======== customViewOptionsMenuItemSelected ========
    */
    customViewOptionsMenuItemSelected : function (e) {
        var selected = e.currentTarget.selectedItem.id;
        this.$.customViewOptionsMenu.selected = -1;
        if (selected != 'dividerItem') {
            this.$.customViewOptionsMenuDialog.close();
        }
        if (selected != 'fixedFontItem' && selected != 'dividerItem') {
            this[selected](e); /* id of the item is the function name */
        }
    },

   /*
    *  ======== deleteCell ========
    */
    deleteCell : function (e) {
        var i = Number(e.currentTarget.id.substr(e.currentTarget.id.indexOf('_') + 1));
        var cellNamesMenuItems = [];
        for (var j = 0; j < this.cellNamesMenuItems.length; j++) {
            if (j != i) {
                var k = cellNamesMenuItems.length;
                cellNamesMenuItems.push(this.cellNamesMenuItems[j]);
                cellNamesMenuItems[k].cellId = 'cell_' + k;
            }
        }
        this.set('cellNamesMenuItems', cellNamesMenuItems);
        var selectedName = this.rovCells[i].selectedColumnName;
        document.querySelector('ti-rov-panel').removeCellFromCustomViewData(this, this.rovCells[i]);
        this.rovCells.splice(i, 1);
        if (this.rovCells.length == 1) {
            this.set('removeButtonHidden', true);
        }
        var tableData = this.formatTableData();
        this.$.tiRovTable.displayTable(tableData.data, this.viewName, 'CUSTOM', tableData.columns, false);
    },

   /*
    *  ======== displayTableView ========
    */
    displayTableView : function (e) {
        var i = Number(e.currentTarget.id.substr(e.currentTarget.id.indexOf('_') + 1));
        var cell = this.rovCells[i];
        var rowKeys = {primaryKeyColumnName: cell.primaryKeyColumnName,
                       primaryKeyColumnValue: cell.primaryKeyColumnValue,
                       selectedColumnName: cell.selectedColumnName};
        document.querySelector('ti-rov-panel').viewFromGraphOrCustom(cell.module, cell.view,
                                                                     cell.viewArgs, rowKeys);
        if (this.$.tableSettingsMenuDialog.opened) {
            this.$.tableSettingsMenuDialog.close();
        }
    },

   /*
    *  ======== fixedFontChanged ========
    */
    fixedFontChanged : function (e) {
        this.$.tiRovTable.fontChanged(e);
    },

   /*
    *  ======== formatMutiRowTableData ========
    *  just in case...
    */
    formatMutiRowTableData : function () {
        /* columns are always in order of rovCells.selectedColumnName */
        var columns = [];
        for (var i = 0; i < this.rovCells.length; i++) {
            if (columns.indexOf(this.rovCells[i].selectedColumnName) == -1) {
                columns.push(this.rovCells[i].selectedColumnName);
            }
        }

        /* map cells by column name to calc num rows */
        var map = {};
        for (var i = 0; i < columns.length; i++) {
            map[columns[i]] = [];
            for (var j = 0; j < this.rovCells.length; j++) {
                if (this.rovCells[j].selectedColumnName == columns[i]) {
                    map[columns[i]].push(j);
                }
            }
        }

        /* number of rows */
        var numRows = 1;
        for (var i = 0; i < columns.length; i++) {
            if (map[columns[i]].length > numRows) {
                numRows = map[columns[i]].length;
            }
        }

        /* init data */
        var data = [];
        for (var i = 0; i < numRows; i++) {
            data.push({});
        }

        /* populate data */
        for (var i = 0; i < columns.length; i++) {
            for (var j = 0; j < map[columns[i]].length; j++) {
                var rowIndex = j;
                var cellIndex = map[columns[i]][j];
                var cell = this.rovCells[cellIndex];
                data[rowIndex][cell.selectedColumnName] ={};
                data[rowIndex][cell.selectedColumnName].val = cell.val;
                if (cell.status) {
                    data[rowIndex][cell.selectedColumnName].status = cell.status;
                }
                data[rowIndex][cell.selectedColumnName].cellIndex = cellIndex;
                data[rowIndex][cell.selectedColumnName].primaryKeyColumnValue = cell.primaryKeyColumnValue;
                data[rowIndex][cell.selectedColumnName].selectedColumnName = cell.selectedColumnName;
            }
        }

        /* fill in empty cells */
        for (var i = 0; i < data.length; i++) {
            for (var j = 0; j < columns.length; j++) {
                if (data[i][columns[j]] == undefined) {
                    data[i][columns[j]] = {};
                    data[i][columns[j]].val = '';
                    data[i][columns[j]].cellIndex = -1;
                }
            }
        }
        return ({data: data, columns: columns});
    },

   /*
    *  ======== formatTableData ========
    */
    formatTableData : function () {
        var columns = [];
        var data = {};
        for (var i = 0; i < this.rovCells.length; i++) {
            var cell = this.rovCells[i];
            columns.push(cell.displayColumnName);
            data[cell.displayColumnName] = {};
            data[cell.displayColumnName].val = cell.val;
            data[cell.displayColumnName].cellIndex = i;
            data[cell.displayColumnName].displayColumnName = cell.displayColumnName;
            data[cell.displayColumnName].tooltip = this.cellTooltip(cell);
            data[cell.displayColumnName].isCustom = cell.isCustom;
            if (!cell.isCustom) {
                if (cell.status) {
                    data[cell.displayColumnName].status = cell.status;
                }
                data[cell.displayColumnName].primaryKeyColumnValue = cell.primaryKeyColumnValue;
                data[cell.displayColumnName].selectedColumnName = cell.selectedColumnName;
            }

        }
        return ({data: [data], columns: columns});
    },

   /*
    *  ======== formatVal ========
    */
    formatVal : function (val, format) {
        var valFormat = rovUtils.getFormat(val);
        if (valFormat == format) {
            return (val);
        }
        if (format == 'Decimal') {
            if (valFormat == 'Hex') {
                return (parseInt(val, 16));
            }
            if (valFormat == 'Scientific') {
                return (Number(val));
            }
        }
        else if (format == 'Hex') {
            var retVal = Number(val).toString(16);
            if (retVal == 'NaN') {
                return (val);
            }
            if (retVal.search(/^0x/i) == -1) {
                retVal = '0x' + retVal;
            }
            return (retVal);
        }
        else if (format == 'Scientific') {
            return (Number(val).toExponential());
        }
    },


   /*
    *  ======== getCellValue ========
    */
    getCellValue : function (viewType, primaryKeyColumnName, primaryKeyColumnValue, columnName, viewData) {
        var data = null;
        var value = {};
        if (viewType == 'INSTANCE') {
            if (rovUtils.isArray(viewData)) {
                for (var i = 0; i < viewData.length; i++) {
                    if (viewData[i][primaryKeyColumnName] == primaryKeyColumnValue) {
                        data = viewData[i];
                        break;
                    }
                }
            }
            else if (viewData[primaryKeyColumnName] == primaryKeyColumnValue) {
                data = viewData;
            }
        }
        else if (viewType == 'MODULE') {
            data = viewData;
        }
        else if (viewType == 'INSTANCE_DATA' || viewType == 'MODULE_DATA') {
            if (rovUtils.isArray(viewData)) {
            }
            else {
                var elemArr = viewData.elements;
                for (var i = 0; i < elemArr.length; i++) {
                    if (elemArr[i][primaryKeyColumnName] == primaryKeyColumnValue) {
                        data = elemArr[i];
                        break;
                    }
                }
            }
        }
        if (data) {
            value.val = data[columnName];
            if (data[columnName + '$status']) {
                value.status = data[columnName + '$status'];
            }
        }
        else {
            value.val = '';
            value.status = columnName + ' not found for ' + primaryKeyColumnName + ' ' + primaryKeyColumnValue;
        }
        return (value);
    },

   /*
    *  ======== getProperties ========
    */
    getProperties : function () {
        var props = this.behaviors[0].getProperties(this);  /* call super, pass scope */
        props.viewsData = {};
        props.viewsData[this.moduleName + '.' + this.viewName] =
            this.getViewsData()[this.moduleName + '.' + this.viewName];
        return (props);
    },

   /*
    *  ======== getSelectedKeyProperties ========
    */
    getSelectedKeyProperties : function (sel) {
        var sepIdx = sel.indexOf(':');
        var props = {key: sel.substr(0, sepIdx), value: sel.substr(sepIdx + 3)};
        return (props);
    },

    /*
     *  ======== getViewCallback ========
     *  Callback from rovData.getView()
     *
     *  Params
     *    error      - null when there is no error; otherwise an error
     *                 message string
     *    viewData   - the ROV view data requested as a JSON object
     *    module     - module name string for the returned view data
     *    view       - view name string for the returned view data
     */
    getViewCallback : function (error, viewData, module, view, handle) {
        /* show the refresh button and hide the refresh spinner */
        if (--this.requests == 0 && this.viewRefresh) {
            this.viewRefresh = false;
        }

        /* handle data acquisition error (if any) */
        if (error != null) {
            return;
        }

        for (var i = 0; i < this.rovCells.length; i++) {
            var cellView = this.rovCells[i].args ? this.rovCells[i].view + this.rovCells[i].args : this.rovCells[i].view;
            if (this.rovCells[i].module == module && cellView == view) {
                this.rovCells[i].viewData = viewData;
            }
        }
        if (this.requests == 0) {
            for (var i = 0; i < this.rovCells.length; i++) {
                if (this.rovCells[i].isCustom) {
                    var value = this.getCustomCellValue(this.rovCells[i]);
                }
                else {
                    var value = this.getCellValue(this.rovCells[i].viewType,
                                     this.rovCells[i].primaryKeyColumnName, this.rovCells[i].primaryKeyColumnValue,
                                     this.rovCells[i].selectedColumnName, this.rovCells[i].viewData);
                                     this.rovCells[i].origVal = value.val;
                }
                if (this.rovCells[i].formula) {
                    if (this.rovCells[i].isCustom) {
                        var decls = this.parseCellFormula(this.rovCells[i].displayColumnName,
                                                          this.rovCells[i].formula);
                        var eStr = decls + this.rovCells[i].formula + ';';
                    }
                    else {
                        /* must start with an operator for now */
                        var eStr = String(this.rovCells[i].val);
                        eStr += String(this.rovCells[i].formula);
                    }
                    try {
                        var val = String(eval(eStr));
                        value.val = val;
                    }
                    catch (e) {
                        value.val = 'error';
                        value.status = 'Formula eval error';
                    }
                }
                if (this.rovCells[i].format) {
                    this.rovCells[i].val = this.formatVal(value.val, this.rovCells[i].format);
                    this.rovCells[i].format = null; /* only used for initial refresh, so table can get it */
                }
                else {
                    this.rovCells[i].val = value.val;
                }
                this.rovCells[i].status = value.status;
            }
            var tableData = this.formatTableData();
            this.viewIsShowing = this.$.tiRovTable.displayTable(tableData.data, this.viewName, 'CUSTOM', tableData.columns, this.dataRefresh);
        }
    },

   /*
    *  ======== getViewColumns ========
    */
    getViewColumns : function(module, view) {
        var viewObjs = this.viewList[module].viewTabs ? this.viewList[module].viewTabs : this.viewList[module];
        var viewColumns = null;
        for (var i = 0; i < viewObjs.length; i++) {
            if (viewObjs[i].name == view) {
                viewColumns = viewObjs[i].columns;
                break;
            }
        }
        return (viewColumns);
    },

   /*
    *  ======== getViews ========
    */
    getViews : function(module) {
        var views = [];
        var viewObjs = this.viewList[module].viewTabs ? this.viewList[module].viewTabs : this.viewList[module];
        if (viewObjs) {
            for (var i = 0; i < viewObjs.length; i++) {
                views.push(viewObjs[i].name);
            }
        }
        return (views);
    },

   /*
    *  ======== getViewsData ========
    */
    getViewsData : function () {
        return(this.$.tiRovTable.getViewsData());
    },

   /*
    *  ======== getViewType ========
    */
    getViewType : function(module, view) {
        var viewObjs = this.viewList[module].viewTabs ? this.viewList[module].viewTabs : this.viewList[module];
        var viewType = null;
        for (var i = 0; i < viewObjs.length; i++) {
            if (viewObjs[i].name == view) {
                viewType = viewObjs[i].type;
                break;
            }
        }
        return (viewType);
    },

   /*
    *  ======== isSameModuleView ========
    */
    isSameModuleView : function (cell1, cell2) {
       return(cell1.module == cell2.module && cell1.view == cell2.view &&
              cell1.args == cell2.args);
    },

   /*
    *  ======== nameCell ========
    */
    nameCell : function (cell) {
        var name;
        if (cell.assignedCellName) {
            name = cell.assignedCellName;
        }
        else if (cell.args) {
            name = cell.firstArg;
        }
        else {
            name = cell.selectedColumnName;
        }
        return (name);
    },

   /*
    *  ======== onCellPropertiesDialogClosed ========
    */
    onCellPropertiesDialogClosed : function (e) {
        if (e.target.id == 'cellPropertiesDialog') {
            this.set('primaryKeyMenuItems', []);
            this.set('primaryKeyMenuLabel', '');
            this.$.primaryKeyMenu._setSelectedItem(null);
        }
    },

   /*
    *  ======== onPrimaryKeySelected ========
    */
    onPrimaryKeySelected : function (e) {
        if (e.currentTarget.selectedItemLabel) {
            if (this.$.tableSettingsMenu.selected != undefined) {
                this.$.tableSettingsMenu.selected = -1;
            }
        }
    },

    /*
     *  ======== onRefresh ========
     *  Called when user clicks the 'Refresh' button on this view,
     *  or 'Refresh all' or 'Repeat refresh' buttons on the ROV toolbar
     */
    onRefresh : function (initialRefresh) {
        /*
         *  Request CPU load from an ROV view.
         *
         *  This is an asynchronous call; getViewCallback() will be called
         *  with the result in its viewData parameter.
         */
        var requests = [];
        for (var i = 0; i < this.rovCells.length; i++) {
            if (!this.rovCells[i].isCustom) {
                var view = this.rovCells[i].args ? this.rovCells[i].view + this.rovCells[i].args : this.rovCells[i].view;
                if (!requests[this.rovCells[i].module + '.' + view]) {
                    requests[this.rovCells[i].module + '.' + view] = true;
                    if (this.rovData.getView(this.rovCells[i].module, view, this)) {
                        ++this.requests;
                    }
                }
            }
        }
        this.dataRefresh = initialRefresh != true;
        this.viewRefresh = this.requests > 0;
    },

   /*
    *  ======== onSaveView ========
    *  Called when user clicks the 'Download' button on this view,
    *  or the 'Download all' button on the ROV toolbar
    */
    onSaveView: function () {
        /* return the graph's current data set */
        return (this.rows);
    },

   /*
    *  ======== ready ========
    */
    ready : function () {
        this.$.tiRovTable.setIsGlobal(false);
        this.$.tiRovTable.setNotifyObj(this);
    },

    /*
     *  ======== resizerClicked ========
     *  Called on a bottom corner on-mousedown event
     *
     *  See ti-rov-graph.html resizer div.
     */
    resizerClicked: function (e) {
        /*
         *  call polymerUI/src/rovUtils.js initRovResize(), passing the
         *  viewPaperCard element that is being resized. Also pass callback
         *  object in order to be notified via this.resized() when the element
         *  is done being is resized, so we can make any required size related
         *  changes to the graph itself
         */
        rovUtils.initRovResize(e, this.$.viewPaperCard);
    },

   /*
    *  ======== rovCustomViewDialogKeyPress ========
    */
    rovCustomViewDialogKeyPress : function (e) {
        var keyCode = e.keyCode || e.which;
        if (keyCode === 13) {
            var dlgId = e.currentTarget.id;
            this[dlgId + 'OkClicked'](e);
        }
    },

   /*
    *  ======== tableCellContextMenu ========
    */
    tableCellContextMenu : function (eData) {
        return;
        var cell = this.rovCells[eData.cellIndex];
        if (!cell.isCustom) {
            var dataProps = {module: cell.module,
                             view: cell.view,
                             selectedColumnName: cell.selectedColumnName,
                             selectedColumnValue: cell.selectedColumnValue,
                             primaryKeyColumnName: cell.primaryKeyColumnName,
                             primaryKeyColumnValue: cell.primaryKeyColumnValue,
                             event: eData.event,
                             args: cell.args,
                             viewArgs: cell.viewArgs,
                             argsId: cell.argsId,
                             viewType: cell.viewType,
                             formula: cell.formula
            };
            document.querySelector('ti-rov-panel').plotViewDataContextMenu(dataProps);
        }
    },

   /*
    *  ======== tableNameClicked ========
    */
    tableNameClicked : function (e) {
        var dialog = this.$.tableNameDialog;
        dialog.resetFit();
        var left = e.x;
        if ((left + 225) > document.documentElement.clientWidth) {
            left = document.documentElement.clientWidth - 225;
        }
        dialog.style.left = left + 'px';
        dialog.style.top = e.y + 'px';
        dialog.open();
        dialog.style.zIndex = String(document.querySelector('ti-rov-panel').getMaxZindex() + 1);
        this.$.tableNameInput.value = this.tableName;
    },

   /*
    *  ======== tableNameDialogOkClicked ========
    */
    tableNameDialogOkClicked : function (e) {
        if (this.$.tableNameInput.value != this.tableName) {
            this.tableName = this.$.tableNameInput.value;
            this.viewName = this.tableName;
            this.$.tiRovTable.viewNameChanged(this.viewName);
        }
        this.$.tableNameDialog.close();
    },

   /*
    *  ======== tableSettingsClicked ========
    */
    tableSettingsClicked : function (e) {
        /* Init cell props submenu */
        this.$.cellNamesMenu.selected = -1;
        this.$.cellPropertiesSubMenu.close();
        var cellNamesMenuItems = [];
        for (var i = 0; i < this.rovCells.length; i++) {
            var item = {};
            item.id = this.rovCells[i].primaryKeyColumnValue + ',' + this.rovCells[i].selectedColumnName;
            item.label = this.rovCells[i].displayColumnName;
            item.cellId = 'cell_' + i;
            item.isCustom = this.rovCells[i].isCustom == true;
            if (!item.isCustom) {
                var cell = this.rovCells[i];
                var titleStr = 'Module: ' + cell.module;
                if (cell.args) {
                    if (cell.view == 'Variable') {
                        titleStr += '\nVariable: ' + cell.firstArg;
                    }
                    else {
                        titleStr += '\nView: ' + cell.view;
                        var args = cell.viewArgs[cell.argsId].args;
                        for(var j = 0; j < args.length; j++) {
                            titleStr += '\n' + args[j].name + ': ' + args[j].value;
                        }
                    }
                }
                else {
                    titleStr += '\nView: ' + cell.view;
                }
                item.title = titleStr;
            }
            cellNamesMenuItems.push(item);
        }
        this.set('cellNamesMenuItems', cellNamesMenuItems);

        var dialog = this.$.tableSettingsMenuDialog;
        dialog.resetFit();
        this.$.tableSettingsMenu.selected = -1;
        var left = e.x;
        var width = 180; /* ballpark from styling in html */
        if ((left + 200) > document.documentElement.clientWidth) {
            left = document.documentElement.clientWidth - 200;
        }
        dialog.style.left = left + 'px';
        var height = 30 + 10;
        var top = e.y - this.$.closeButton.offsetHeight;
        if (top + height > document.querySelector('ti-rov-panel').viewContainer.clientHeight) {
          top = top - height;
          if (top < 0) {
              top = 0;
          }
        }
        dialog.style.top = top + 'px';
        dialog.style.minWidth = width + 'px';
        dialog.open();
        dialog.style.zIndex = String(document.querySelector('ti-rov-panel').getMaxZindex() + 1);
    },

   /*
    *  ======== tableSettingsMenuItemClicked ========
    */
    tableSettingsMenuItemClicked : function (e) {
        var selected = e.currentTarget.id;
        this.$.tableSettingsMenu.selected = -1;
        if (selected && selected.indexOf('Clicked') > 0) {
            this[selected](e); /* id of the item is the function name */
        }
    }

});
