define([

'angular',
'lodash',
'config'

], function (angular, _, config) {

'use strict';

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

module.service('fields', function(dashboard, $rootScope, $http, esVersion, alertSrv, ejsResource) {

  // Save a reference to this
  var self = this;

  var ejs = ejsResource(config.elasticsearch);

  this.list = ['_type'];
  this.indices = [];

  // Stop tracking the full mapping, too expensive, instead we only remember the index names
  // we've already seen.
  //
  $rootScope.$watch(function(){return dashboard.indices;},function(n) {
    if(!_.isUndefined(n) && n.length && dashboard.current.index.warm_fields) {
      // Only get the mapping for indices we don't know it for
      var indices = _.difference(n,_.keys(self.indices));
      // Only get the mapping if there are new indices
      if(indices.length > 0) {
        self.map(indices).then(function(result) {
          self.indices = _.union(self.indices,_.keys(result));
          self.list = mapFields(result);
        });
      }
    }
  });

  var mapFields = function (m) {
    var fields = [];
    _.each(m, function(types) {
      _.each(types, function(type) {
        fields = _.difference(_.union(fields,_.keys(type)),
          ['_parent','_routing','_size','_ttl','_all','_uid','_version','_boost','_source']);
      });
    });
    return fields;
  };

  this.map = function(indices) {
    var request = ejs.client.get('/' + indices.join(',') + "/_mapping",
      undefined, undefined, function(data, status) {
        if(status === 0) {
          alertSrv.set('Error',"Could not contact Elasticsearch at "+ejs.config.server+
            ". Please ensure that Elasticsearch is reachable from your system." ,'error');
        } else {
          alertSrv.set('Error',"No index found at "+ejs.config.server+"/" +
            indices.join(',')+"/_mapping. Please create at least one index."  +
            "If you're using a proxy ensure it is configured correctly.",'error');
        }
      });

    // Flatten the mapping of each index into dot notated keys.
    return request.then(function(p) {
      var mapping = {};
      return esVersion.gte('1.0.0.RC1').then(function(version) {
        _.each(p, function(indexMap,index) {
          mapping[index] = {};
          _.each((version ? indexMap.mappings : indexMap), function (typeMap,type) {
            mapping[index][type] = flatten(typeMap);
          });
        });
        return mapping;
      });
    });
  };

  // This should understand both the 1.0 format and the 0.90 format for mappings. Ugly.
  var flatten = function(obj,prefix) {
    var propName = (prefix) ? prefix :  '',
      dot = (prefix) ? '.':'',
      ret = {};
    for(var attr in obj){
      if(attr === 'dynamic_templates' || attr === '_default_') {
        continue;
      }
      // For now only support multi field on the top level
      // and if there is a default field set.
      if(obj[attr]['type'] === 'multi_field') {
        ret[attr] = obj[attr]['fields'][attr] || obj[attr];
        var keys = _.without(_.keys(obj[attr]['fields']),attr);
        for(var key in keys) {
          ret[attr+'.'+keys[key]] = obj[attr]['fields'][keys[key]];
        }
      } else if (attr === 'properties' || attr ==='fields') {
        _.extend(ret,flatten(obj[attr], propName));
      } else if(typeof obj[attr] === 'object' &&
        (!_.isUndefined(obj[attr].type) || !_.isUndefined(obj[attr].properties))){
        _.extend(ret,flatten(obj[attr], propName + dot + attr));
      } else {
        if(propName !== '') {
          ret[propName] = obj;
        }
      }
    }
    return ret;
  };

});

});