var angular = require('angular'),
  _ = require('jsUtil');

require('./RemoteDataService');
require('../../linker/services/LinkerService');
require('../../flow/services/WorkflowService');
require('../../flow/services/NotionService');
require('../../../commons/services/CacheArray');
var combineGetDataRequest = require('./combineGetDataRequest');

var module = angular.module('flowmodulebase.services');
/**
 *
 * @example
 *
 * var config = {
 *     name: 'chuout',
         idPropertyName: 'outId',
         subflagPropertyName: 'subflag',
         flowType: 'chuout',
         tempNotions: ['mynotion'],
         controllers: ['controller1', 'controller2'],
         tableNames: ['tableName1', 'tableName2']
 * };
 * var DataService = BaseDataServiceFactory.generate(config);
 *
 * DateService.get('recordId').then(function(content) {
 *   console.log('业务数据', content.chuout);
 *   console.log('业务数据', content.record);
 *   console.log('流程信息', content.workflow);
 *   console.log('码表数据', content.options);
 *   console.log('临时意见', content.ideas);
 *  console.log('控制信息', content.controllers);
 *   console.log('当前用户', content.loginUser);
 * });
 */
module.factory('BaseDataServiceFactory', function(
  WorkflowService, RemoteDataService, LinkerService,
  NotionService, $q, CacheArray, $http) {
  function BaseDataServiceFactory(config) {
    this.config = config;
    this.config.baseUrl = config.baseUrl || config.name;
    this.config.subflagPropertyName = this.config.subflagPropertyName || 'subflag';
    this.remoteDataService = new RemoteDataService(this.config.baseUrl, this.config.idPropertyName);

    this.initArrayCache();
  }

  BaseDataServiceFactory.generate = function(config) {
    return new BaseDataServiceFactory(config);
  };

  function toObject(keys, values) {
    var result = {};
    _.forEach(keys, function(key, index) {
      result[key] = values[index];
    });
    return result;
  }

  BaseDataServiceFactory.prototype = {
    /**
     * 获取数据
     *
     * @param  {String} recordId 业务数据id
     * @return {Promise}         未来对象。
     */
    get: function(recordId) {
      var self = this;

      if (!recordId) {
        return LinkerService.getCurrentUser().then(function(user) {
          return self.generateDefaultValue(user);
        });
      }

      if (window.cordova) {
        return this.get2(recordId);
      }

      var recordPromise = this.getData(recordId),
        workflowPromise = _.isUndefined(recordId)? $q.when({}) :
        recordPromise.then(function(record) {
          return record[self.config.subflagPropertyName];
        }).then(function(subflag) {
          return self.getWorkflowInfo(recordId, subflag);
        }),
        tempNotionPromise = this.getTempNotions(recordId),
        loginUserPromise = LinkerService.getCurrentUser(),
        controllersPromise = this.getControllers(),
        notionListPromise = _.isUndefined(recordId)? $q.when({}) :
        recordPromise.then(function(record) {
          return self.getNotionList(self.config.flowType, record[self.config.idPropertyName]);
        }),
        stopTimePromise = _.isUndefined(recordId)? $q.when() :
        recordPromise.then(function(record) {
          return self.getStopTime(record[self.config.needGradePropertyName]);
        });

      return $q.all([recordPromise, workflowPromise, tempNotionPromise, loginUserPromise,
        controllersPromise, notionListPromise, stopTimePromise])
      .then(function(values) {
        var result = {};
        result[self.config.name] = values[0];
        result.record = values[0];
        result.workflow = values[1];
        result.loginUser = values[3];
        result.ideas = values[2].ideas;
        result.tempNotion = values[2].tempNotion;
        result.tempNotions = values[2];
        result.controllers = values[4];
        result.notionList = values[5];
        result.stopTime = values[6];
        return result;
      });
    },

    get2: function(recordId, subflag) {
      var promise = combineGetDataRequest(recordId, subflag || this.getSubflagFromAnyList(recordId) || '1', LinkerService.currentUserId,
        this, WorkflowService, NotionService, $http, $q);
      var self = this;
      var recordPromise = promise.recordPromise,
        workflowPromise = promise.workflowPromise,
        tempNotionPromise = promise.tempNotionsPromise,
        loginUserPromise = LinkerService.getCurrentUser(),
        controllersPromise = this.getControllers(),
        notionListPromise = promise.notionListPromise.then(this.handleNotionList),
        stopTimePromise = _.isUndefined(recordId)? $q.when() :
        recordPromise.then(function(record) {
          return self.getStopTime(record[self.config.needGradePropertyName]);
        });

        return $q.all([recordPromise, workflowPromise, tempNotionPromise, loginUserPromise,
        controllersPromise, notionListPromise, stopTimePromise])
          .then(function(values) {
            var result = {};
            result[self.config.name] = values[0];
            result.record = values[0];
            result.workflow = values[1];
            result.loginUser = values[3];
            result.ideas = values[2].ideas;
            result.tempNotion = values[2].tempNotion;
            result.tempNotions = values[2];
            result.controllers = values[4];
            result.notionList = values[5];
            result.stopTime = values[6];
            self.updateWorkflowInfoToList(recordId, result.workflow);
            return result;
          });
    },

    getItemId: function(item) {
      var self = this;
      return item[self.config.idPropertyName];
    },

    initArrayCache: function() {
      var self = this;
      var getByIds = function() {return $q.when([]);},
        getItemId = function(item) {
          return self.getItemId(item);
        };

      var todos = new CacheArray(this.config.name + '.todos', 50);
      todos.queryList = function(pageNo) {
        return self.getTodos(pageNo).then(function(content) {
          todos.number = content.number;
          todos.totalPages = content.totalPages;
          return content.content;
        });
      };
      todos.getItemId = getItemId;
      todos.getByIds = getByIds;
      self.todos = todos;

      var relatedList = new CacheArray(this.config.name + '.relatedList', 100);
      relatedList.queryList = function(pageNo) {
        return self.getRelatedList(pageNo, this.params).then(function(content) {
          relatedList.number = content.number;
          relatedList.totalPages = content.totalPages;
          return content.content;
        });
      };
      relatedList.getItemId = getItemId;
      relatedList.getByIds = getByIds;
      self.relatedList = relatedList;

      var drafts = new CacheArray(this.config.name + '.drafts', 100);
      drafts.queryList = function(pageNo) {
        return self.getDrafts(pageNo).then(function(content) {
          drafts.number = content.number;
          drafts.totalPages = content.totalPages;
          return content.content;
        });
      };
      drafts.getItemId = getItemId;
      drafts.getByIds = getByIds;
      self.drafts = drafts;
    },

    /**
     * 获取待办
     *
     * @param  {Number} pageNo 页码
     * @return {Promise}       返回未来对象。
     */
    getTodos: function(pageNo) {
      var remoteDataService = this.remoteDataService;
      return remoteDataService.getTodos(LinkerService.currentUserId, pageNo || 0);
    },

    /**
     * 获取草稿列表。
     *
     * @param  {Number} pageNo 页码
     * @return {Promise}       返回未来对象。
     */
    getDrafts: function(pageNo) {
      var remoteDataService = this.remoteDataService;
      return remoteDataService.getDrafts(LinkerService.currentUserId, pageNo || 0);
    },

    getRelatedList: function(pageNo, params) {
      var remoteDataService = this.remoteDataService;
      return remoteDataService.getRelatedList(LinkerService.currentUserId, pageNo || 0, params);
    },

    create: function(record) {
      return this.remoteDataService.create(record);
    },

    update: function(record) {
      return this.remoteDataService.update(record);
    },

    remove: function(recordId) {
      return this.remoteDataService.remove(recordId);
    },

    save: function(record) {
      var self = this;
      return this.remoteDataService.save(record).then(function(data) {
        self.updateRecordDataToList(record);
        return data;
      });
    },

    /**
     * 获取业务数据。
     *
     * @param  {String} recordId 业务数据编号。
     * @return {Promise}
     */
    getData: function(recordId) {
      if (recordId) {
        return this.remoteDataService.get(recordId);
      } else {
        var self = this;
        return LinkerService.getCurrentUser().then(function(user) {
          return self.generateDefaultValue(user);
        });
      }
    },

    generateDefaultValue: function(/*loginUser*/) {
      var defaultRecord = {};
      defaultRecord[this.config.subflagPropertyName] = '0';
      return defaultRecord;
    },

    /**
     * 获取流程信息
     *
     * @param  {String} id      数据主键
     * @param  {String} subflag 流程状态
     *
     * @return {Promise}        未来对象。
     */
    getWorkflowInfo: function(id, subflag) {
      var self = this;
      return WorkflowService.getWorkFlowInfo(
          LinkerService.currentUserId, self.config.flowType, id, subflag || '0')
          .then(function(workflowInfo){
            self.updateWorkflowInfoToList(id, workflowInfo);
            return workflowInfo;
          });
    },

    /**
     * 获取开发设置。
     *
     * @return {Promise} 返回未来对象。
     */
    getControllers: function() {
      var controllers = this.config.controllers;
      if (_.isEmpty(controllers)) {
        return $q.when({});
      } else {
        return $http.get('/systoggle/getToggles?toggleKeys=' + controllers.join(','), {
          timeout: 15000
        })
        .then(function(response) {
          return response.data;
        });
      }
    },

    /**
     * 获取临时意见。
     *
     * @param  {String} recordId 业务数据编号
     * @return {Promise}
     */
    getTempNotions: function(recordId) {
      var tempNotions = this.config.tempNotions,
        hasNotion = !_.isEmpty(tempNotions),
        hasOnlyNotion = hasNotion && tempNotions.length === 1,
        flowType = this.config.flowType,
        self = this;

      if (!hasNotion) {
        return $q.all({});
      } else {
        var promises = _.map(tempNotions, function(ideaName) {
          return NotionService.getTempNotion(ideaName, recordId, LinkerService.currentUserId, flowType);
        });
        return $q.all(promises).then(function(ideas) {
          var result = toObject(tempNotions, ideas);
          result.ideas = ideas;

          if (hasOnlyNotion) {
            result.tempNotion = ideas[0];
          }
          return result;
        });
      }
    },

    getSubflagFromAnyList: function(recordId) {
      var todo = this.getRecordFromList(this.todos.items, recordId),
        related = this.getRecordFromList(this.relatedList.items, recordId);
      if (todo) {
        return todo[this.config.subflagPropertyName];
      } else if (related) {
        return related[this.config.subflagPropertyName];
      }
    },

    updateRecordDataToList: function(record) {
      var todo = this.getRecordFromList(this.todos.items, record[this.config.idPropertyName]),
        related = this.getRecordFromList(this.relatedList.items, record[this.config.idPropertyName]);
      if (todo) {
        _.apply(todo, record);
      }
      if (related) {
        _.apply(related, record);
      }
    },

    updateSubflag: function(recordId, subflag) {
      var todo = this.getRecordFromList(this.todos.items, recordId),
        related = this.getRecordFromList(this.relatedList.items, recordId);

      if (todo) {
        todo[this.config.subflagPropertyName] = subflag;
      }

      if (related) {
        related[this.config.subflagPropertyName] = subflag;
      }
    },

    updateWorkflowInfoToList: function(recordId, workflowInfo) {
      var todo = this.getRecordFromList(this.todos.items, recordId),
        related = this.getRecordFromList(this.relatedList.items, recordId);
      if (todo) {
        todo.workflow = workflowInfo;
      }
      if (related) {
        related.workflow = workflowInfo;
      }
    },

    refreshWorkFlowInfo: function(recordId, subflag, flowType, bean) {
      var workflowInfoPromise = this.getWorkflowInfo(recordId, subflag);
      var notionListPromise = this.getNotionList(flowType, recordId);
      var tempNotionPromise = this.getTempNotions(recordId);

      this.updateSubflag(recordId, subflag);

      return $q.all([workflowInfoPromise, notionListPromise, tempNotionPromise])
      .then(function(datas) {
        if (bean) {
          bean.workflow = datas[0];
          bean.notionList = datas[1];
          bean.tempNotions = datas[2];
        }

        return datas;
      });
    },

    handleNotionList: function(items) {
      var NotionList = {};
      _.each(items, function(item) {
        if (!_.isArray(NotionList[item.ideaFieldTitle])) {
          NotionList[item.ideaFieldTitle] = [];

        }
        NotionList[item.ideaFieldTitle].push(item);
      });
      return NotionList;
    },

    getNotionList: function(flowType, recordId) {
      return NotionService.queryNotion(flowType, recordId).then(this.handleNotionList);
    },

    /**
    * 获取紧急停止时间
    */
    getStopTime: function(needGrade) {
      if (needGrade) {
        var url = '/common/config/stopTime/' + needGrade;
        return $http.get(url, {
          timeout: 15000
        }).then(function(response) {
          return response.data.stopTime;
        });
      } else {
        return $q.when();
      }
    },

    getRecordFromList: function(list, recordId) {
      var record,
        idPropertyName = this.config.idPropertyName;
      for (var i = 0, len = list.length; i < len; i++) {
        record = list[i];
        if (record[idPropertyName] === recordId) {
          return record;
        }
      }
    }



  };

  return BaseDataServiceFactory;
});
