define('pgadmin.dashboard', [
    'sources/url_for', 'sources/gettext', 'require', 'jquery', 'underscore',
    'sources/pgadmin', 'backbone', 'backgrid', 'flotr2',
    'pgadmin.alertifyjs', 'backgrid.filter',
    'pgadmin.browser', 'bootstrap', 'wcdocker'
    ],
function(url_for, gettext, r, $, _, pgAdmin, Backbone, Backgrid, Flotr,
  alertify) {

  var wcDocker = window.wcDocker,
  pgBrowser = pgAdmin.Browser;

  /* Return back, this has been called more than once */
  if (pgAdmin.Dashboard)
    return;

  var dashboardVisible = true,
    cancel_query_url = '',
    terminate_session_url = '',
    is_super_user = false,
    current_user, maintenance_database,
    is_server_dashboard = false,
    is_database_dashboard = false;

  // Custom BackGrid cell, Responsible for cancelling active sessions
  var cancelQueryCell = Backgrid.Extension.DeleteCell.extend({
        render: function () {
          this.$el.empty();
          this.$el.html(
            "<i class='fa fa-stop' data-toggle='tooltip' " +
            "title='" + gettext('Cancel the active query') +
            "'></i>"
          );
          this.delegateEvents();
          return this;
        },
        deleteRow: function(e) {
          var self = this;
          e.preventDefault();

          var canDeleteRow = Backgrid.callByNeed(
            self.column.get('canDeleteRow'), self.column, self.model
          );
          // If we are not allowed to cancel the query, return from here
          if(!canDeleteRow)
            return;

          // This will refresh the grid
          var refresh_grid = function() {
            if(is_server_dashboard) {
              $('#btn_server_activity_refresh').click();
            } else if(is_database_dashboard) {
              $('#btn_database_activity_refresh').click();
            }
          };

          var title = gettext('Cancel Active Query?'),
            txtConfirm = gettext('Are you sure you wish to cancel the active query?');

          alertify.confirm(
            title,
            txtConfirm,
            function(evt) {
              $.ajax({
                url: cancel_query_url + self.model.get('pid'),
                type:'DELETE',
                success: function(res) {
                  if (res == gettext('Success')) {
                    alertify.success(gettext('Active query cancelled successfully.'));
                    refresh_grid();
                  } else {
                    alertify.error(gettext('An error occurred whilst cancelling the active query.'));
                  }
                },
                error: function(xhr, status, error) {
                  try {
                    var err = $.parseJSON(xhr.responseText);
                    if (err.success == 0) {
                      alertify.error(err.errormsg);
                    }
                  } catch (e) {}
                }
              });
            },
            function(evt) {
              return true;
            }
          );
        }
  });

  var terminateSessionCell = Backgrid.Extension.DeleteCell.extend({
        render: function () {
          this.$el.empty();
          this.$el.html(
            "<i class='fa fa-times-circle' data-toggle='tooltip' " +
            "title='" + gettext('Terminate the session') +
            "'></i>"
          );
          this.delegateEvents();
          return this;
        },
        deleteRow: function(e) {
          var self = this;
          e.preventDefault();

          var canDeleteRow = Backgrid.callByNeed(
            self.column.get('canDeleteRow'), self.column, self.model
          );
          // If we are not allowed to cancel the query, return from here
          if(!canDeleteRow)
            return;

          // This will refresh the grid
          var refresh_grid = function() {
            if(is_server_dashboard) {
              $('#btn_server_activity_refresh').click();
            } else if(is_database_dashboard) {
              $('#btn_database_activity_refresh').click();
            }
          };

          var title = gettext('Terminate Session?'),
            txtConfirm = gettext('Are you sure you wish to terminate the session?');

          alertify.confirm(
            title,
            txtConfirm,
            function(evt) {
              $.ajax({
                url: terminate_session_url + self.model.get('pid'),
                type:'DELETE',
                success: function(res) {
                  if (res == gettext('Success')) {
                    alertify.success(gettext('Session terminateed successfully.'));
                    refresh_grid();
                  } else {
                    alertify.error(gettext('An error occurred whilst terminateing the active query.'));
                  }
                },
                error: function(xhr, status, error) {
                  try {
                    var err = $.parseJSON(xhr.responseText);
                    if (err.success == 0) {
                      alertify.error(err.errormsg);
                    }
                  } catch (e) {}
                }
              });
            },
            function(evt) {
              return true;
            }
          );
        }
  });

  // Subnode Cell, which will display subnode control
  var SessionDetailsCell = Backgrid.Extension.ObjectCell.extend({
   enterEditMode: function () {
      // Notify that we are about to enter in edit mode for current cell.
      this.model.trigger("enteringEditMode", [this]);

      Backgrid.Cell.prototype.enterEditMode.apply(this, arguments);
      /* Make sure - we listen to the click event */
      this.delegateEvents();
      var editable = Backgrid.callByNeed(this.column.editable(), this.column, this.model);

      if (editable) {
        this.$el.html(
          "<i class='fa fa-caret-down subnode-edit-in-process'></i>"
          );
        this.model.trigger(
          "pg-sub-node:opened", this.model, this
          );
      }
    },
    render: function(){
        this.$el.empty();
        this.$el.html(
          "<i class='fa fa-caret-right' data-toggle='tooltip' " +
          "title='" + gettext('View the active session details') +
          "'></i>"
        );
        this.delegateEvents();
        if (this.grabFocus)
          this.$el.focus();
        return this;
    }
  });

  // Subnode Model
  var ActiveQueryDetailsModel = Backbone.Model.extend({
    defaults: {
      version: null /* Postgres version */
    },
    schema: [{
      id: 'backend_type', label: gettext('Backend type'),
      type: 'text', editable: true, disabled: true,
      group: gettext('Details'),
      visible: function(m) {
        return this.version >= 100000;
      }
    },{
      id: 'query_start', label: gettext('Query started at'),
      type: 'text', editable: false, disabled: true,
      group: gettext('Details')
    },{
      id: 'state_change', label: gettext('Last state changed at'),
      type: 'text', editable: true, disabled: true,
      group: gettext('Details')
    },{
      id: 'query', label: gettext('SQL'),
      type: 'text', editable: true, disabled: true,
      control: Backform.SqlFieldControl,
      group: gettext('Details')
    }]
  });

  pgAdmin.Dashboard = {
        init: function() {
            if (this.initialized)
                return;

            this.initialized = true;

            // Bind the Dashboard object with the 'object_selected' function
            var selected = this.object_selected.bind(this);
            var disconnected = this.object_disconnected.bind(this);

            // Listen for selection of any of object
            pgBrowser.Events.on('pgadmin-browser:tree:selected', selected);

            // Listen for server disconnected event
            pgBrowser.Events.on('pgadmin:server:disconnect', disconnected);

            // Load the default welcome dashboard
            var url = url_for('dashboard.index');

            var dashboardPanel = pgBrowser.panels['dashboard'].panel;
            if (dashboardPanel) {
                var div = dashboardPanel.layout().scene().find('.pg-panel-content');

                if (div) {
                    $.ajax({
                        url: url,
                        type: "GET",
                        dataType: "html",
                        success: function (data) {
                            $(div).html(data);
                        },
                        error: function (xhr, status) {
                            $(div).html(
                                '<div class="alert alert-danger pg-panel-message" role="alert">' + gettext('An error occurred whilst loading the dashboard.') + '</div>'
                            );
                        }
                    });

                    // Cache the current IDs for next time
                    $(dashboardPanel).data('sid', -1)
                    $(dashboardPanel).data('did', -1)
                }
            }
        },

        // Handle Server Disconnect
        object_disconnected: function(obj) {
            this.object_selected(obj.item, obj.data, pgBrowser.Nodes[obj.data._type]);
        },

        // Handle treeview clicks
        object_selected: function(item, itemData, node) {
            if (itemData && itemData._type && dashboardVisible) {
                var treeHierarchy = node.getTreeNodeHierarchy(item),
                    url = url_for('dashboard.index'),
                    sid = -1, did = -1, b = pgAdmin.Browser,
                    m = b && b.Nodes[itemData._type];

                cancel_query_url = url_for('dashboard.index') + 'cancel_query/';
                terminate_session_url = url_for('dashboard.index') + 'terminate_session/';

                // Check if user is super user
                var server = treeHierarchy['server'];
                maintenance_database = (server && server.db) || null;

                if(server && server.user && server.user.is_superuser) {
                  is_super_user = true;
                } else {
                  is_super_user = false;
                  // Set current user
                  current_user = (server && server.user) ? server.user.name : null;
                }

                if (m && m.dashboard) {
                    if (_.isFunction(m.dashboard)) {
                        url = m.dashboard.apply(
                            item, itemData, node, treeHierarchy
                        );
                    } else {
                        url = m.dashboard;
                    }
                } else {
                    if ('database' in treeHierarchy) {
                        sid = treeHierarchy.server._id;
                        did = treeHierarchy.database._id;
                        is_server_dashboard = false;
                        is_database_dashboard = true;
                        url += sid + '/' + did;
                        cancel_query_url += sid + '/' + did + '/';
                        terminate_session_url += sid + '/' + did + '/';
                    } else if ('server' in treeHierarchy) {
                        sid = treeHierarchy.server._id;
                        is_server_dashboard = true;
                        is_database_dashboard = false;
                        url += sid;
                        cancel_query_url += sid + '/';
                        terminate_session_url += sid + '/';
                    }
                }

                var dashboardPanel = pgBrowser.panels['dashboard'].panel;
                if (dashboardPanel) {
                    var div = dashboardPanel.layout().scene().find(
                            '.pg-panel-content'
                        );

                    if (div) {
                        if (itemData.connected || _.isUndefined(itemData.connected)) {
                            // Avoid unnecessary reloads
                            if (url != $(dashboardPanel).data('dashboard_url') ||
                               (url == $(dashboardPanel).data('dashboard_url') && $(dashboardPanel).data('server_status') == false )) {
                                // Clear out everything so any existing timers die off
                                $(div).empty();

                                $.ajax({
                                    url: url,
                                    type: "GET",
                                    dataType: "html",
                                    success: function (data) {
                                        $(div).html(data);
                                    },
                                    error: function (xhr, status) {
                                        $(div).html(
                                            '<div class="alert alert-danger pg-panel-message" role="alert">' + gettext('An error occurred whilst loading the dashboard.') + '</div>'
                                        );
                                    }
                                });
                                $(dashboardPanel).data('server_status', true);
                            }

                        }
                        else {
                            $(div).empty();
                            $(div).html(
                                '<div class="alert alert-info pg-panel-message" role="alert">' + gettext('Please connect to the selected server to view the dashboard.') + '</div>'
                            );
                            $(dashboardPanel).data('server_status', false);
                        }
                        // Cache the current IDs for next time
                        $(dashboardPanel).data('dashboard_url', url);

                    }
                }
            }
        },

        // Render a chart
        render_chart: function(container, data, dataset, sid, did, url, options, counter, refresh) {

            // Data format:
            // [
            //     { data: [[0, y0], [1, y1]...], label: 'Label 1', [options] },
            //     { data: [[0, y0], [1, y1]...], label: 'Label 2', [options] },
            //     { data: [[0, y0], [1, y1]...], label: 'Label 3', [options] }
            // ]

            if (!dashboardVisible)
              return;

            var y = 0;
            if (dataset.length == 0) {
                if (counter == true)
                {
                    // Have we stashed initial values?
                    if (_.isUndefined($(container).data('counter_previous_vals'))) {
                        $(container).data('counter_previous_vals', data[0])
                    } else {
                        // Create the initial data structure
                        for (var x in data[0]) {
                            dataset.push({ 'data': [[0, data[0][x] - $(container).data('counter_previous_vals')[x]]], 'label': x });
                        }
                    }
                } else {
                    // Create the initial data structure
                    for (var x in data[0]) {
                        dataset.push({ 'data': [[0, data[0][x]]], 'label': x });
                    }
                }
            } else {
                for (var x in data[0]) {
                    // Push new values onto the existing data structure
                    // If this is a counter stat, we need to subtract the previous value
                    if (counter == false) {
                        dataset[y]['data'].unshift([0, data[0][x]]);
                    } else {
                        // Store the current value, minus the previous one we stashed.
                        // It's possible the tab has been reloaded, in which case out previous values are gone
                        if (_.isUndefined($(container).data('counter_previous_vals')))
                            return

                        dataset[y]['data'].unshift([0, data[0][x] - $(container).data('counter_previous_vals')[x]]);
                    }

                    // Reset the time index to get a proper scrolling display
                    for (var z = 0; z < dataset[y]['data'].length; z++) {
                        dataset[y]['data'][z][0] = z;
                    }

                    y++;
                }
                $(container).data('counter_previous_vals', data[0])
            }

             // Remove uneeded elements
            for (x = 0; x < dataset.length; x++) {
                // Remove old data points
                if (dataset[x]['data'].length > 101) {
                    dataset[x]['data'].pop();
                }
            }

            // Draw Graph, if the container still exists and has a size
            var dashboardPanel = pgBrowser.panels['dashboard'].panel;
            var div = dashboardPanel.layout().scene().find('.pg-panel-content');
            if ($(div).find(container).length) { // Exists?
                if (container.clientHeight > 0 && container.clientWidth > 0) { // Not hidden?
                    Flotr.draw(container, dataset, options);
                }
            } else {
                return;
            }

            // Animate
            var setTimeoutFunc = function () {
                var path = url + sid;
                if (did != -1) {
                    path += '/' + did;
                }
                $.ajax({
                    url: path,
                    type: "GET",
                    dataType: "html",
                    success: function (resp) {
                        $(container).removeClass('graph-error')
                        data = JSON.parse(resp);
                        pgAdmin.Dashboard.render_chart(container, data, dataset, sid, did, url, options, counter, refresh);
                    },
                    error: function (xhr, status, msg) {
                        var err = $.parseJSON(xhr.responseText),
                            msg = err.errormsg,
                            cls;
                        // If we get a 428, it means the server isn't connected
                        if (xhr.status == 428) {
                            if (_.isUndefined(msg) || _.isNull(msg)) {
                              msg = gettext('Please connect to the selected server to view the graph.');
                            }
                            cls = 'info';
                        } else {
                            msg = gettext('An error occurred whilst rendering the graph.');
                            cls = 'danger';
                        }

                        $(container).addClass('graph-error');
                        $(container).html(
                            '<div class="alert alert-' + cls + ' pg-panel-message" role="alert">' + msg + '</div>'
                        );

                        // Try again...
                        if (container.clientHeight > 0 && container.clientWidth > 0) {
                            setTimeout(setTimeoutFunc, refresh * 1000);
                        }
                    },
                });
            };

            setTimeout(setTimeoutFunc, refresh * 1000);
        },

        // Handler function to support the "Add Server" link
        add_new_server: function() {
            if (pgBrowser && pgBrowser.tree) {
                var i = pgBrowser.tree.selected().length != 0 ?
                          pgBrowser.tree.selected() :
                          pgBrowser.tree.first(null, false),
                     serverModule = r('pgadmin.node.server'),
                     itemData = pgBrowser.tree.itemData(i);

                while (itemData && itemData._type != "server_group") {
                    i = pgBrowser.tree.next(i);
                    itemData = pgBrowser.tree.itemData(i);
                }

                if (!itemData) {
                    return;
                }

                if (serverModule) {
                    serverModule.callbacks.show_obj_properties.apply(
                        serverModule, [{action: 'create'}, i]
                    );
                }
            }
        },

        // Render a grid
        render_grid: function(container, sid, did, url, columns) {
            var Datum = Backbone.Model.extend({});

            var path = url + sid;
            if (did != -1) {
                path += '/' + did;
            }

            var Data = Backbone.Collection.extend({
              model: Datum,
              url: path,
              mode: "client"
            });

            var data = new Data();

            // Set up the grid
            var grid = new Backgrid.Grid({
              columns: columns,
              collection: data,
              className: "backgrid table-bordered presentation table backgrid-striped"
            });

            // Render the grid
            $(container).append(grid.render().el)

            // Initialize a client-side filter to filter on the client
            // mode pageable collection's cache.
            var filter = new Backgrid.Extension.ClientSideFilter({
              collection: data
            });

            // Render the filter
            $('#' + container.id + '_filter').before(filter.render().el);

            // Add some space to the filter and move it to the right
            $(filter.el).css({float: "right", margin: "5px", "margin-right": "2px", "margin-top": "3px"});

            // Stash objects for future use
            $(container).data('data', data);
            $(container).data('grid', grid);
            $(container).data('filter', filter);
        },

        // Render the data in a grid
        render_grid_data: function(container) {
            var data = $(container).data('data'),
                grid = $(container).data('grid'),
                filter = $(container).data('filter');

            if(_.isUndefined(data)){
              return null;
            }

            data.fetch({
                reset: true,
                success: function() {
                    // If we're showing an error, remove it, and replace the grid & filter
                    if ($(container).hasClass('grid-error')) {
                        $(container).removeClass('grid-error');
                        $(container).html(grid.render().el)
                        $(filter.el).show();
                    }

                    // Re-apply search criteria
                    filter.search();
                },
                error: function(model, xhr, options) {
                     var err = $.parseJSON(xhr.responseText),
                         msg = err.errormsg,
                         cls;
                    // If we get a 428, it means the server isn't connected
                    if (xhr.status == 428) {
                        if (_.isUndefined(msg) || _.isNull(msg)) {
                            msg = gettext('Please connect to the selected server to view the table.');
                        }
                        cls = 'info';
                    } else {
                        msg = gettext('An error occurred whilst rendering the table.');
                        cls = 'danger';
                    }

                    // Replace the content with the error, if not already present. Always update the message
                    if (!$(container).hasClass('grid-error')) {
                        $(filter.el).hide();
                        $(container).addClass('grid-error');
                    }

                    $(container).html(
                        '<div class="alert alert-' + cls + ' pg-panel-message" role="alert">' + msg + '</div>'
                    );

                    // Try again
                    setTimeout(function() {
                        pgAdmin.Dashboard.render_grid_data(container, data);
                    }, 5000)
                }
            });
        },

        // Rock n' roll on the server dashboard
        init_server_dashboard: function(sid, version, session_stats_refresh, tps_stats_refresh, ti_stats_refresh, to_stats_refresh, bio_stats_refresh) {
            var div_sessions = $('.dashboard-container').find('#graph-sessions')[0];
            var div_tps = $('.dashboard-container').find('#graph-tps')[0];
            var div_ti = $('.dashboard-container').find('#graph-ti')[0];
            var div_to = $('.dashboard-container').find('#graph-to')[0];
            var div_bio = $('.dashboard-container').find('#graph-bio')[0];
            var div_server_activity = $('.dashboard-container').find('#server_activity');
            var div_server_locks = $('.dashboard-container').find('#server_locks');
            var div_server_prepared = $('.dashboard-container').find('#server_prepared');
            var div_server_config = $('.dashboard-container').find('#server_config');
            var dataset_sessions = [];
            var data_sessions = [];
            var dataset_tps = [];
            var data_tps = [];
            var dataset_ti = [];
            var data_ti = [];
            var dataset_to = [];
            var data_to = [];
            var dataset_bio = [];
            var data_bio = [];

            // Fake DB ID
            var did = -1;

            var options_line = {
                  parseFloat: false,
                  xaxis: {
                      min: 100,
                      max: 0,
                      autoscale: 0
                  },
                  yaxis : {
                      autoscale: 1
                  },
                  legend : {
                      position : 'nw',
                      backgroundColor : '#D2E8FF'
                  }
            }

            var server_activity_columns = [{
                name: "pid",
                label: gettext('PID'),
                editable: false,
                cell: "string"
            }, {
                name: "datname",
                label: gettext('Database'),
                editable: false,
                cell: "string"
            }, {
                name: "usename",
                label: gettext('User'),
                editable: false,
                cell: "string"
            }, {
                name: "application_name",
                label: gettext('Application'),
                editable: false,
                cell: "string"
            }, {
                name: "client_addr",
                label: gettext('Client'),
                editable: false,
                cell: "string"
            }, {
                name: "backend_start",
                label: gettext('Backend start'),
                editable: false,
                cell: "string"
            }, {
                name: "state",
                label: gettext('State'),
                editable: false,
                cell: "string"
            }];

            if (version < 90600) {
                server_activity_columns = server_activity_columns.concat(
                [{
                    name: "waiting",
                    label: gettext('Waiting?'),
                    editable: false,
                    cell: "string"
                }]);
            } else {
                server_activity_columns = server_activity_columns.concat(
                [{
                    name: "wait_event",
                    label: gettext('Wait Event'),
                    editable: false,
                    cell: "string"
                },{
                    name: "blocking_pids",
                    label: gettext('Blocking PIDs'),
                    editable: false,
                    cell: "string"
                }]);
            }

            var newActiveQueryDetailsModel = new ActiveQueryDetailsModel();

            var subNodeFieldsModel = Backform.generateViewSchema(
              null, newActiveQueryDetailsModel, 'create', null, null, true
            );

            // Add version to each field
            _.each(subNodeFieldsModel[0].fields, function(obj) {
              obj['version'] = version;
            });

            // Add cancel active query button
            server_activity_columns.unshift({
              name: "pg-backform-expand", label: "",
              cell: SessionDetailsCell,
              cell_priority: -1,
              postgres_version: version,
              schema: subNodeFieldsModel
            });

            // Add cancel active query button
            server_activity_columns.unshift({
              name: "pg-backform-delete", label: "",
              cell: cancelQueryCell,
              editable: false, cell_priority: -1,
              canDeleteRow: pgAdmin.Dashboard.can_cancel_active_query,
              postgres_version: version
            });

            server_activity_columns.unshift({
              name: "pg-backform-delete", label: "",
              cell: terminateSessionCell,
              editable: false, cell_priority: -1,
              canDeleteRow: pgAdmin.Dashboard.can_terminate_session,
              postgres_version: version
            });

            var server_locks_columns = [{
                name: "pid",
                label: gettext('PID'),
                editable: false,
                cell: "string"
            }, {
                name: "datname",
                label: gettext('Database'),
                editable: false,
                cell: "string"
            }, {
                name: "locktype",
                label: gettext('Lock type'),
                editable: false,
                cell: "string"
            }, {
                name: "relation",
                label: gettext('Target relation'),
                editable: false,
                cell: "string"
            }, {
                name: "page",
                label: gettext('Page'),
                editable: false,
                cell: "string"
            }, {
                name: "tuple",
                label: gettext('Tuple'),
                editable: false,
                cell: "string"
            }, {
                name: "virtualxid",
                label: gettext('vXID (target)'),
                editable: false,
                cell: "string"
            }, {
                name: "transactionid",
                label: gettext('XID (target)'),
                editable: false,
                cell: "string"
            },{
                name: "classid",
                label: gettext('Class'),
                editable: false,
                cell: "string"
            },{
                name: "objid",
                label: gettext('Object ID'),
                editable: false,
                cell: "string"
            },{
                name: "virtualtransaction",
                label: gettext('vXID (owner)'),
                editable: false,
                cell: "string"
            },{
                name: "mode",
                label: gettext('Mode'),
                editable: false,
                cell: "string"
            },{
                name: "granted",
                label: gettext('Granted?'),
                editable: false,
                cell: "string"
            }];

            var server_prepared_columns = [{
                name: "git",
                label: gettext('Name'),
                editable: false,
                cell: "string"
            }, {
                name: "database",
                label: gettext('Database'),
                editable: false,
                cell: "string"
            }, {
                name: "Owner",
                label: gettext('Owner'),
                editable: false,
                cell: "string"
            }, {
                name: "transaction",
                label: gettext('XID'),
                editable: false,
                cell: "string"
            }, {
                name: "prepared",
                label: gettext('Prepared at'),
                editable: false,
                cell: "string"
            }];

            var server_config_columns = [{
                name: "name",
                label: gettext('Name'),
                editable: false,
                cell: "string"
            }, {
                name: "category",
                label: gettext('Category'),
                editable: false,
                cell: "string"
            }, {
                name: "setting",
                label: gettext('Setting'),
                editable: false,
                cell: "string"
            }, {
                name: "unit",
                label: gettext('Unit'),
                editable: false,
                cell: "string"
            }, {
                name: "short_desc",
                label: gettext('Description'),
                editable: false,
                cell: "string"
            }];

            // Render the graphs
            pgAdmin.Dashboard.render_chart(
              div_sessions, data_sessions, dataset_sessions, sid, did,
              url_for('dashboard.session_stats'), options_line, false,
              session_stats_refresh
            );
            pgAdmin.Dashboard.render_chart(
              div_tps, data_tps, dataset_tps, sid, did,
              url_for('dashboard.tps_stats'), options_line, true,
              tps_stats_refresh
            );
            pgAdmin.Dashboard.render_chart(
              div_ti, data_ti, dataset_ti, sid, did,
              url_for('dashboard.ti_stats'), options_line, true,
              ti_stats_refresh
            );
            pgAdmin.Dashboard.render_chart(
              div_to, data_to, dataset_to, sid, did,
              url_for('dashboard.to_stats'), options_line, true,
              to_stats_refresh
            );
            pgAdmin.Dashboard.render_chart(
              div_bio, data_bio, dataset_bio, sid, did,
              url_for('dashboard.bio_stats'), options_line, true,
              bio_stats_refresh
            );

            // To align subnode controls properly
            $(div_server_activity).addClass('pg-el-container');
            $(div_server_activity).attr('el', 'sm');

            // Render the tabs, but only get data for the activity tab for now
            pgAdmin.Dashboard.render_grid(
              div_server_activity, sid, did,
              url_for('dashboard.activity'), server_activity_columns
            );
            pgAdmin.Dashboard.render_grid(
              div_server_locks, sid, did, url_for('dashboard.locks'),
              server_locks_columns
            );
            pgAdmin.Dashboard.render_grid(
              div_server_prepared, sid, did, url_for('dashboard.prepared'),
              server_prepared_columns
            );
            pgAdmin.Dashboard.render_grid(
              div_server_config, sid, did, url_for('dashboard.config'),
              server_config_columns
            );

            pgAdmin.Dashboard.render_grid_data(div_server_activity);

            // (Re)render the appropriate tab
            $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
                switch ($(e.target).attr('aria-controls')) {
                    case "tab_server_activity":
                        pgAdmin.Dashboard.render_grid_data(div_server_activity);
                        break;

                    case "tab_server_locks":
                        pgAdmin.Dashboard.render_grid_data(div_server_locks);
                        break;

                    case "tab_server_prepared":
                        pgAdmin.Dashboard.render_grid_data(div_server_prepared);
                        break;

                    case "tab_server_config":
                        pgAdmin.Dashboard.render_grid_data(div_server_config);
                        break;
                }
            });

            // Handle button clicks
            $("button").click(function(e){
                switch(this.id) {
                    case "btn_server_activity_refresh":
                        pgAdmin.Dashboard.render_grid_data(div_server_activity);
                        break;

                    case "btn_server_locks_refresh":
                        pgAdmin.Dashboard.render_grid_data(div_server_locks);
                        break;

                    case "btn_server_prepared_refresh":
                        pgAdmin.Dashboard.render_grid_data(div_server_prepared);
                        break;

                    case "btn_server_config_refresh":
                        pgAdmin.Dashboard.render_grid_data(div_server_config);
                        break;
                }
            });

        },

        // Rock n' roll on the database dashboard
        init_database_dashboard: function(sid, did, version, session_stats_refresh, tps_stats_refresh, ti_stats_refresh, to_stats_refresh, bio_stats_refresh) {
            var div_sessions = document.getElementById('graph-sessions');
            var div_tps = document.getElementById('graph-tps');
            var div_ti = document.getElementById('graph-ti');
            var div_to = document.getElementById('graph-to');
            var div_bio = document.getElementById('graph-bio');
            var div_database_activity = document.getElementById('database_activity');
            var div_database_locks = document.getElementById('database_locks');
            var div_database_prepared = document.getElementById('database_prepared');
            var dataset_sessions = [];
            var data_sessions = [];
            var dataset_tps = [];
            var data_tps = [];
            var dataset_ti = [];
            var data_ti = [];
            var dataset_to = [];
            var data_to = [];
            var dataset_bio = [];
            var data_bio = [];

            var options_line = {
                  parseFloat: false,
                  xaxis: {
                      min: 100,
                      max: 0,
                      autoscale: 0
                  },
                  yaxis : {
                      autoscale: 1
                  },
                  legend : {
                      position : 'nw',
                      backgroundColor : '#D2E8FF'
                  }
            }

            var database_activity_columns = [{
                name: "pid",
                label: gettext('PID'),
                editable: false,
                cell: "string"
            }, {
                name: "usename",
                label: gettext('User'),
                editable: false,
                cell: "string"
            }, {
                name: "application_name",
                label: gettext('Application'),
                editable: false,
                cell: "string"
            }, {
                name: "client_addr",
                label: gettext('Client'),
                editable: false,
                cell: "string"
            }, {
                name: "backend_start",
                label: gettext('Backend start'),
                editable: false,
                cell: "string"
            }, {
                name: "state",
                label: gettext('State'),
                editable: false,
                cell: "string"
            }];

            if (version < 90600) {
                database_activity_columns = database_activity_columns.concat(
                [{
                    name: "waiting",
                    label: gettext('Waiting?'),
                    editable: false,
                    cell: "string"
                }]);
            } else {
                database_activity_columns = database_activity_columns.concat(
                [{
                    name: "wait_event",
                    label: gettext('Wait Event'),
                    editable: false,
                    cell: "string"
                },{
                    name: "blocking_pids",
                    label: gettext('Blocking PIDs'),
                    editable: false,
                    cell: "string"
                }]);
            }

            var newActiveQueryDetailsModel = new ActiveQueryDetailsModel();

            var subNodeFieldsModel = Backform.generateViewSchema(
              null, newActiveQueryDetailsModel, 'create', null, null, true
            );

            // Add version to each field
            _.each(subNodeFieldsModel[0].fields, function(obj) {
              obj['version'] = version;
            });


            // Add cancel active query button
            database_activity_columns.unshift({
              name: "pg-backform-expand", label: "",
              cell: SessionDetailsCell,
              cell_priority: -1,
              postgres_version: version,
              schema: subNodeFieldsModel
            });

            database_activity_columns.unshift({
              name: "pg-backform-delete", label: "",
              cell: cancelQueryCell,
              editable: false, cell_priority: -1,
              canDeleteRow: pgAdmin.Dashboard.can_cancel_active_query,
              postgres_version: version
            });
            database_activity_columns.unshift({
              name: "pg-backform-delete", label: "",
              cell: terminateSessionCell,
              editable: false, cell_priority: -1,
              canDeleteRow: pgAdmin.Dashboard.can_terminate_session,
              postgres_version: version
            });

            var database_locks_columns = [{
                name: "pid",
                label: gettext('PID'),
                editable: false,
                cell: "string"
            }, {
                name: "locktype",
                label: gettext('Lock type'),
                editable: false,
                cell: "string"
            }, {
                name: "relation",
                label: gettext('Target relation'),
                editable: false,
                cell: "string"
            }, {
                name: "page",
                label: gettext('Page'),
                editable: false,
                cell: "string"
            }, {
                name: "tuple",
                label: gettext('Tuple'),
                editable: false,
                cell: "string"
            }, {
                name: "virtualxid",
                label: gettext('vXID (target)'),
                editable: false,
                cell: "string"
            }, {
                name: "transactionid",
                label: gettext('XID (target)'),
                editable: false,
                cell: "string"
            },{
                name: "classid",
                label: gettext('Class'),
                editable: false,
                cell: "string"
            },{
                name: "objid",
                label: gettext('Object ID'),
                editable: false,
                cell: "string"
            },{
                name: "virtualtransaction",
                label: gettext('vXID (owner)'),
                editable: false,
                cell: "string"
            },{
                name: "mode",
                label: gettext('Mode'),
                editable: false,
                cell: "string"
            },{
                name: "granted",
                label: gettext('Granted?'),
                editable: false,
                cell: "string"
            }];

            var database_prepared_columns = [{
                name: "git",
                label: gettext('Name'),
                editable: false,
                cell: "string"
            }, {
                name: "Owner",
                label: gettext('Owner'),
                editable: false,
                cell: "string"
            }, {
                name: "transaction",
                label: gettext('XID'),
                editable: false,
                cell: "string"
            }, {
                name: "prepared",
                label: gettext('Prepared at'),
                editable: false,
                cell: "string"
            }];

            // Render the graphs
            pgAdmin.Dashboard.render_chart(
              div_sessions, data_sessions, dataset_sessions, sid, did,
              url_for('dashboard.session_stats'), options_line, false,
              session_stats_refresh
            );
            pgAdmin.Dashboard.render_chart(
              div_tps, data_tps, dataset_tps, sid, did,
              url_for('dashboard.tps_stats'), options_line, true,
              tps_stats_refresh
            );
            pgAdmin.Dashboard.render_chart(
              div_ti, data_ti, dataset_ti, sid, did,
              url_for('dashboard.ti_stats'), options_line, true,
              ti_stats_refresh
            );
            pgAdmin.Dashboard.render_chart(
              div_to, data_to, dataset_to, sid, did,
              url_for('dashboard.to_stats'), options_line, true,
              to_stats_refresh
            );
            pgAdmin.Dashboard.render_chart(
              div_bio, data_bio, dataset_bio, sid, did,
              url_for('dashboard.bio_stats'), options_line, true,
              bio_stats_refresh
            );

            // To align subnode controls properly
            $(div_database_activity).addClass('pg-el-container');
            $(div_database_activity).attr('el', 'sm');

            // Render the tabs, but only get data for the activity tab for now
            pgAdmin.Dashboard.render_grid(
              div_database_activity, sid, did, url_for('dashboard.activity'),
              database_activity_columns
            );
            pgAdmin.Dashboard.render_grid(
              div_database_locks, sid, did, url_for('dashboard.locks'),
              database_locks_columns
            );
            pgAdmin.Dashboard.render_grid(
              div_database_prepared, sid, did, url_for('dashboard.prepared'),
              database_prepared_columns
            );

            pgAdmin.Dashboard.render_grid_data(div_database_activity);

            // (Re)render the appropriate tab
            $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
                switch ($(e.target).attr('aria-controls')) {
                    case "tab_database_activity":
                        pgAdmin.Dashboard.render_grid_data(div_database_activity);
                        break;

                    case "tab_database_locks":
                        pgAdmin.Dashboard.render_grid_data(div_database_locks);
                        break;

                    case "tab_database_prepared":
                        pgAdmin.Dashboard.render_grid_data(div_database_prepared);
                        break;
                }
            });

            // Handle button clicks
            $("button").click(function(e){
                switch(this.id) {
                    case "btn_database_activity_refresh":
                        pgAdmin.Dashboard.render_grid_data(div_database_activity);
                        break;

                    case "btn_database_locks_refresh":
                        pgAdmin.Dashboard.render_grid_data(div_database_locks);
                        break;

                    case "btn_database_prepared_refresh":
                        pgAdmin.Dashboard.render_grid_data(div_database_prepared);
                        break;
                }
            });

        },
        toggleVisibility: function(flag) {
          dashboardVisible = flag;
        },
        can_cancel_active_query: function(m) {
          // We will validate if user is allowed to cancel the active query
          // If there is only one active session means it probably our main
          // connection session
          var active_sessions = m.collection.where({'state': 'active'}),
            pg_version = this.get('postgres_version') || null;

          // With PG10, We have background process showing on dashboard
          // We will not allow user to cancel them as they will fail with error
          // anyway, so better usability we will throw our on notification

          // Background processes do not have database field populated
          if (pg_version && pg_version >= 100000 && !m.get('datname')) {
            alertify.info(
              gettext('You cannot cancel background worker processes.')
            );
            return false;
          // If it is the last active connection on maintenance db then error out
          } else if (maintenance_database == m.get('datname') &&
              m.get('state') == 'active' && active_sessions.length == 1) {
            alertify.error(
              gettext('You are not allowed to cancel the main active session.')
            );
            return false;
          } else if(m.get('state') == 'idle') {
            // If this session is already idle then do nothing
            alertify.info(
              gettext('The session is already in idle state.')
            );
            return false;
          } else if(is_super_user) {
            // Super user can do anything
            return true;
          } else if (current_user && current_user == m.get('usename')) {
            // Non-super user can cancel only their active queries
            return true;
          } else {
            // Do not allow to cancel someone else session to non-super user
            alertify.error(
              gettext('Superuser privileges are required to cancel another users query.')
            );
            return false;
          }
        },
        can_terminate_session: function(m) {
          // We will validate if user is allowed to cancel the active query
          // If there is only one active session means it probably our main
          // connection session
          var active_sessions = m.collection.where({'state': 'active'}),
            pg_version = this.get('postgres_version') || null;

          // With PG10, We have background process showing on dashboard
          // We will not allow user to cancel them as they will fail with error
          // anyway, so better usability we will throw our on notification

          // Background processes do not have database field populated
          if (pg_version && pg_version >= 100000 && !m.get('datname')) {
            alertify.info(
              gettext('You cannot terminate background worker processes.')
            );
            return false;
          // If it is the last active connection on maintenance db then error out
          } else if (maintenance_database == m.get('datname') &&
              m.get('state') == 'active' && active_sessions.length == 1) {
            alertify.error(
              gettext('You are not allowed to terminate the main active session.')
            );
            return false;
          } else if(is_super_user) {
            // Super user can do anything
            return true;
          } else if (current_user && current_user == m.get('usename')) {
            // Non-super user can terminate only their active queries
            return true;
          } else {
            // Do not allow to cancel someone else session to non-super user
            alertify.error(
              gettext('Superuser privileges are required to terminate another users query.')
            );
            return false;
          }
        },
  };

  return pgAdmin.Dashboard;
});
