define([
  'angular',
  'lodash',
  'jquery',
],
function (angular, _, $) {
  'use strict';

  var module = angular.module('grafana.services');

  module.factory('dashboardViewStateSrv', function($location, $timeout) {

    // represents the transient view state
    // like fullscreen panel & edit
    function DashboardViewState($scope) {
      var self = this;
      self.state = {};
      self.panelScopes = [];
      self.$scope = $scope;

      $scope.exitFullscreen = function() {
        if (self.state.fullscreen) {
          self.update({ fullscreen: false });
        }
      };

      $scope.onAppEvent('$routeUpdate', function() {
        var urlState = self.getQueryStringState();
        if (self.needsSync(urlState)) {
          self.update(urlState, true);
        }
      });

      this.update(this.getQueryStringState(), true);
      this.expandRowForPanel();
    }

    DashboardViewState.prototype.expandRowForPanel = function() {
      if (!this.state.panelId) { return; }

      var panelInfo = this.$scope.dashboard.getPanelInfoById(this.state.panelId);
      if (panelInfo) {
        panelInfo.row.collapse = false;
      }
    };

    DashboardViewState.prototype.needsSync = function(urlState) {
      return _.isEqual(this.state, urlState) === false;
    };

    DashboardViewState.prototype.getQueryStringState = function() {
      var state = $location.search();
      state.panelId = parseInt(state.panelId) || null;
      state.fullscreen = state.fullscreen ? true : null;
      state.edit =  (state.edit === "true" || state.edit === true) || null;
      state.editview = state.editview || null;
      return state;
    };

    DashboardViewState.prototype.serializeToUrl = function() {
      var urlState = _.clone(this.state);
      urlState.fullscreen = this.state.fullscreen ? true : null;
      urlState.edit = this.state.edit ? true : null;
      return urlState;
    };

    DashboardViewState.prototype.update = function(state, skipUrlSync) {
      _.extend(this.state, state);
      this.fullscreen = this.state.fullscreen;

      if (!this.state.fullscreen) {
        this.state.panelId = null;
        this.state.fullscreen = null;
        this.state.edit = null;
      }

      if (!skipUrlSync) {
        $location.search(this.serializeToUrl());
      }

      this.syncState();
    };

    DashboardViewState.prototype.syncState = function() {
      if (this.panelScopes.length === 0) { return; }

      if (this.fullscreen) {
        if (this.fullscreenPanel) {
          this.leaveFullscreen(false);
        }
        var panelScope = this.getPanelScope(this.state.panelId);
        // panel could be about to be created/added and scope does
        // not exist yet
        if (!panelScope) {
          return;
        }
        this.enterFullscreen(panelScope);
        return;
      }

      if (this.fullscreenPanel) {
        this.leaveFullscreen(true);
      }
    };

    DashboardViewState.prototype.getPanelScope = function(id) {
      return _.find(this.panelScopes, function(panelScope) {
        return panelScope.panel.id === id;
      });
    };

    DashboardViewState.prototype.leaveFullscreen = function(render) {
      var self = this;

      self.fullscreenPanel.editMode = false;
      self.fullscreenPanel.fullscreen = false;
      delete self.fullscreenPanel.height;

      this.$scope.appEvent('panel-fullscreen-exit', {panelId: this.fullscreenPanel.panel.id});

      if (!render) { return false;}

      $timeout(function() {
        if (self.oldTimeRange !== self.fullscreenPanel.range) {
          self.$scope.broadcastRefresh();
        }
        else {
          self.fullscreenPanel.$broadcast('render');
        }
        delete self.fullscreenPanel;
      });
    };

    DashboardViewState.prototype.enterFullscreen = function(panelScope) {
      var docHeight = $(window).height();
      var editHeight = Math.floor(docHeight * 0.3);
      var fullscreenHeight = Math.floor(docHeight * 0.7);

      panelScope.editMode = this.state.edit && this.$scope.dashboardMeta.canEdit;
      panelScope.height = panelScope.editMode ? editHeight : fullscreenHeight;

      this.oldTimeRange = panelScope.range;
      this.fullscreenPanel = panelScope;

      $(window).scrollTop(0);

      panelScope.fullscreen = true;
      this.$scope.appEvent('panel-fullscreen-enter', {panelId: panelScope.panel.id});

      $timeout(function() {
        panelScope.$broadcast('render');
      });
    };

    DashboardViewState.prototype.registerPanel = function(panelScope) {
      var self = this;
      self.panelScopes.push(panelScope);

      if (self.state.panelId === panelScope.panel.id) {
        self.enterFullscreen(panelScope);
      }

      panelScope.$on('$destroy', function() {
        self.panelScopes = _.without(self.panelScopes, panelScope);
      });
    };

    return {
      create: function($scope) {
        return new DashboardViewState($scope);
      }
    };

  });
});
