/** @scratch /panels/5

*
* include::panels/map.asciidoc[]
*/

/** @scratch /panels/map/0

*
* == Map
* Status: *Stable*
*
* The map panel translates 2 letter country or state codes into shaded regions on a map. Currently
* available maps are world, usa and europe.
*
*/

define([

'angular',
'app',
'lodash',
'jquery',
'config',
'./lib/jquery.jvectormap.min'

], function (angular, app, _, $) {

'use strict';

var module = angular.module('kibana.panels.map', []);
app.useModule(module);

module.controller('map', function($scope, $rootScope, querySrv, dashboard, filterSrv) {
  $scope.panelMeta = {
    editorTabs : [
      {title:'Queries', src:'app/partials/querySelect.html'}
    ],
    modals : [
      {
        description: "Inspect",
        icon: "icon-info-sign",
        partial: "app/partials/inspector.html",
        show: $scope.panel.spyable
      }
    ],
    status  : "Stable",
    description : "Displays a map of shaded regions using a field containing a 2 letter country "+
     ", or US state, code. Regions with more hit are shaded darker. Node that this does use the"+
     " Elasticsearch terms facet, so it is important that you set it to the correct field."
  };

  // Set and populate defaults
  var _d = {
    /** @scratch /panels/map/3
     *
     * === Parameters
     *
     * map:: Map to display. world, usa, europe
     */
    map     : "world",
    /** @scratch /panels/map/3
     * colors:: An array of colors to use to shade the map. If 2 colors are specified, shades
     * between them will be used. For example [`#A0E2E2', `#265656']
     */
    colors  : ['#A0E2E2', '#265656'],
    /** @scratch /panels/map/3
     * size:: Max number of regions to shade
     */
    size    : 100,
    /** @scratch /panels/map/3
     * exclude:: exclude this array of regions. For example [`US',`BR',`IN']
     */
    exclude : [],
    /** @scratch /panels/map/3
     * spyable:: Setting spyable to false disables the inspect icon.
     */
    spyable : true,
    /** @scratch /panels/map/5
     *
     * ==== Queries
     * queries object:: This object describes the queries to use on this panel.
     * queries.mode::: Of the queries available, which to use. Options: +all, pinned, unpinned, selected+
     * queries.ids::: In +selected+ mode, which query ids are selected.
     */
    queries     : {
      mode        : 'all',
      ids         : []
    }
  };
  _.defaults($scope.panel,_d);

  $scope.init = function() {
    $scope.$on('refresh',function(){$scope.get_data();});
    $scope.get_data();
  };

  $scope.get_data = function() {

    // Make sure we have everything for the request to complete
    if(dashboard.indices.length === 0) {
      return;
    }
    $scope.panelMeta.loading = true;

    var request,
      boolQuery,
      queries;

    $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries);
    request = $scope.ejs.Request().indices(dashboard.indices);
    queries = querySrv.getQueryObjs($scope.panel.queries.ids);

    boolQuery = $scope.ejs.BoolQuery();
    _.each(queries,function(q) {
      boolQuery = boolQuery.should(querySrv.toEjsObj(q));
    });

    // Then the insert into facet and make the request
    request = request
      .facet($scope.ejs.TermsFacet('map')
        .field($scope.panel.field)
        .size($scope.panel.size)
        .exclude($scope.panel.exclude)
        .facetFilter($scope.ejs.QueryFilter(
          $scope.ejs.FilteredQuery(
            boolQuery,
            filterSrv.getBoolFilter(filterSrv.ids())
            )))).size(0);

    $scope.populate_modal(request);

    var results = request.doSearch();

    // Populate scope when we have results
    results.then(function(results) {
      $scope.panelMeta.loading = false;
      $scope.hits = results.hits.total;
      $scope.data = {};
      _.each(results.facets.map.terms, function(v) {
        $scope.data[v.term.toUpperCase()] = v.count;
      });
      $scope.$emit('render');
    });
  };

  // I really don't like this function, too much dom manip. Break out into directive?
  $scope.populate_modal = function(request) {
    $scope.inspector = angular.toJson(JSON.parse(request.toString()),true);
  };

  $scope.build_search = function(field, value) {
    filterSrv.set({type:'field', field:field, query:value, mandate:"must"});
  };

});

module.directive('map', function() {
  return {
    restrict: 'A',
    link: function(scope, elem) {

      elem.html('<center><img src="img/load_big.gif"></center>');

      // Receive render events
      scope.$on('render',function(){
        slow();
      });

      elem.closest('.panel').resize(function () {
        elem.empty();
      });

      function render_panel() {
        elem.empty();
        elem.css({height:scope.panel.height||scope.row.height});
        $('.jvectormap-zoomin,.jvectormap-zoomout,.jvectormap-label').remove();
        require(['./panels/map/lib/map.'+scope.panel.map], function () {
          elem.vectorMap({
            map: scope.panel.map,
            regionStyle: {initial: {fill: '#8c8c8c'}},
            zoomOnScroll: false,
            backgroundColor: null,
            series: {
              regions: [{
                values: scope.data,
                scale: scope.panel.colors,
                normalizeFunction: 'polynomial'
              }]
            },
            onRegionLabelShow: function(event, label, code){
              elem.children('.map-legend').show();
              var count = _.isUndefined(scope.data[code]) ? 0 : scope.data[code];
              elem.children('.map-legend').text(label.text() + ": " + count);
            },
            onRegionOut: function() {
              elem.children('.map-legend').hide();
            },
            onRegionClick: function(event, code) {
              var count = _.isUndefined(scope.data[code]) ? 0 : scope.data[code];
              if (count !== 0) {
                scope.build_search(scope.panel.field,code);
              }
            }
          });
          elem.prepend('<span class="map-legend"></span>');

          elem.children('.map-legend').hide();
        });
      }

      var slow = _.debounce(render_panel, 200);
    }
  };
});

});