var angular = require('angular');
require('../modules');
require('./localforage');
require('jsUtil');

  var i = 0;

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

  module.factory('CacheArray', function($q, localforage) {
    /**
     * CacheArray
     *
     * @param String itemKey 数组的本地缓存键值。
     *
     * @param number maxSize 缓存最大数组。
     */
    function CacheArray(itemKey, maxSize) {
      this.number = -1;
      this.totalPages = 10000;
      this.itemKey = itemKey;
      this.maxSize = maxSize;
      this.items = [];
      this._idItems = [];
      this.loadFromCache();
      this.id = i++;
      this._ready = false;
    }

    CacheArray.prototype = {
      /**
       * 从缓存中加载数据。
       *
       * @return {Promise}
       */
      loadFromCache: function() {
        var self = this;
        this.cachePromise = localforage.getItem(this.itemKey)
          .then(function(value) {
            self._idItems = value || [];
            return self.getByIds(self._idItems)
              .then(function(items) {
                if (self.refreshed) {
                  return self.items;
                }
                self.items = items;
                return items;
              });
          });

        this.cachePromise.then(function() {
          self._ready = true;
        }, function() {
          self._ready = true;
        });

        return this.cachePromise;
      },

      ready: function(fn) {
        if (fn) {
          this.cachePromise.then(fn);
        }
        return this.cachePromise;
      },

      /**
       * 通过一组id获取数据。需要配置的。
       *
       * @return {Promise}
       */
      getByIds: function() {

      },

      /**
       * 获取数据的id。
       *
       * @param  {Object} item 数据
       * @return {string} 返回数据对象
       */
      getItemId: function(item) {
        return item.id;
      },

      /**
       * 添加一组数据。
       * @param  {Promise} promise 获取一组数据的promise。
       * @param  {Boolean} successThenClear 获取数组成功后是否清空以前的缓存数组。
       * @return {Promise}
       */
      push: function(promise, successThenClear) {
        var self = this;

        function pushFn(items) {
          if (successThenClear) {
            self.clear();
          }

          self.joinArray(self.items, items);

          return self.syncCache();
        }

        if (!promise.then) {
          return pushFn(promise);
        } else {
          return promise.then(pushFn);
        }
      },
      /**
       * 从数组中过滤与指定item的id相同的元素数组。
       * @param  {Array} items
       * @param  {Object} myItem
       */
      filterItems: function(items, myItem) {
        var self = this;
        return jsUtil.filter(items, function(item) {
          return self.getItemId(item) === self.getItemId(myItem);
        });
      },
      /**
       * 合并数组，将newItems合并到selfItems中
       * @param  {Array} selfItems
       * @param  {Array} newItems
       */
      joinArray: function(selfItems, newItems) {
        var self = this;
        jsUtil.each(newItems, function(item) {
          if (self.filterItems(selfItems, item).length === 0) {
            selfItems.push(item);
          }
        });
        return selfItems;
      },
      /**
       * 同步缓存
       *
       * @return {Promise}
       */
      syncCache: function() {
        var items = this.items.slice(0, this.maxSize),
          ids = _.map(items, this.getItemId, this);

        this._idItems = ids;

        return $q.all(localforage.setItem(this.itemKey, ids));
      },

      /**
       * 在数组前插入一条数据
       *
       * @param  {Object} item 数据
       * @return {Promise}
       */
      insert: function(item) {
        var index = this.indexOf(item);
        if (index >= 0) {
          this.items.splice(index, 1);
        }
        this.items.unshift(item);
        return this.syncCache();
      },
      /**
       * 从数组中移除一条数据
       *
       * @param  {Object} item 数据
       * @return {Promise}
       */
      remove: function(item) {
        var index = this.indexOf(item);
        if (index >= 0) {
          this.items.splice(index, 1);
        }
        return this.syncCache();
      },

      /**
       * 获取元素在数组中的位置。
       *
       * @param  {Id|Object} item 元素
       * @return {Number} 返回元素所在的位置。
       */
      indexOf: function(item) {
        var id = _.isObject(item) ? this.getItemId(item) : item,
          self = this,
          result = -1;
        _.each(this.items, function(_item, index) {
          if (id === self.getItemId(_item)) {
            result = index;
          }
        });

        return result;
      },
      /**
       * （为方便测试，添加此方法。）
       */
      setItemIds: function(ids) {
        return $q.all(localforage.setItem(this.itemKey, ids));
      },

      /**
       * 清空数据。
       *
       * @return {Promise}
       */
      clear: function() {
        //this.reset();
        return $q.all(localforage.removeItem(this.itemKey));
      },

      reset: function() {
        this.number = -1;
        this.totalPages = 1000;
        this.items = [];
        this._idItems = [];
      },

      /**
       * 获取列表数据
       * @return {pageNo} 页码
       */
      queryList: function() {

      },
      /**
       * 刷新时同步更新列表缓存。
       */
      refresh: function() {
        var self = this;
        this.number = -1;
        this.number = -1;
        this.totalPages = 1000;
        var refreshPromise = this.queryList()
          .then(function(items) {
            self.refreshed = true;
            self.items = [];
            self._idItems = [];

            return items;
          });
        return this.push(refreshPromise, true).then(function() {
          self._ready = true;
          return self;
        });
      },
      /**
       * 加载更多时同步更新列表缓存。
       */
      loadMore: function() {
        if (!this._ready) {
          return this.refresh();
        }
        var self = this;
        this.number++;
        if (this.number < this.totalPages) {
          return this.push(this.queryList(this.number)).then(function() {
            return self;
          });
        } else {
          return $q.when(this);
        }
      }
    };

    return CacheArray;
  });
