var angular = require('angular');
var _ = require('jsUtil');
require('../modules');
require('./AppModulesAuthVisibleService');
require('./AppModules');
require('./configService');

angular
  .module('commons.services.appConfig')
  .factory('AppConfigCache', AppConfigCache)
  .factory('AppConfig', AppConfig)
  .factory('CoreAppConfig', CoreAppConfig)
  .provider('ConfigApp', ConfigApp);

function ApplicationConfig(config, $q) {
  this.$q = $q;
  this.keyGetterFnMap = {
    serverUrl: 'getServerUrl',
    server: 'getServerUrl',
    appId: 'getAppId',
    webSocketServerUrl: 'getWebSocketServerUrl',
    socketServer: 'getWebSocketServerUrl',
    socketServerUrl: 'getWebSocketServerUrl',
    serverId: 'getServerId'
  };

  this.waitValueUpdateToNoEmptyCallbacks = {};
  this.keyValueChangeListeners = {};

  this.update(config, true);
}

ApplicationConfig.prototype = {
  /**
   * 获取server url
   */
  getServerUrl: function() {
    var serverUrl = this.config.server;
    if (!serverUrl) {
      return serverUrl;
    }

    if (serverUrl.indexOf('http') === -1) {
      serverUrl = 'http://' + serverUrl;
    }

    if (!/:\d+$/.test(serverUrl)) {
      serverUrl += serverUrl.indexOf('https') >= 0? ':443' : ':80';
    }

    return serverUrl;
  },

  /**
   * 获取WebSocket服务器url
   */
  getWebSocketServerUrl: function() {
    var webSocketServerUrl = this.config.socketServer;
    var serverUrl = this.getServerUrl();
    if (!webSocketServerUrl && serverUrl) {
      webSocketServerUrl = serverUrl.replace(/^http\:/, 'ws:')
        .replace(/^https\:/, 'wss:')
        .replace(/:\d+$/, ':8887');
    }

    return webSocketServerUrl;
  },

  getAppId: function() {
    return this.config.appId || this.getServerId();
  },

  getServerId: function() {
    return this.config.id;
  },

  getKeyValue: function(key) {
    if (this.keyGetterFnMap[key]) {
      return this[this.keyGetterFnMap[key]].apply(this);
    }

    return this.config[key];
  },

  getKeyValueUntilNoEmpty: function(key, callback) {
    var deferred = this.$q.defer();
    var value = this.getKeyValue(key);
    if (value) {
      callback && callback(value);
      deferred.resolve(value);
    } else {
      this.addWaitValueUpdateToNoEmptyCallback(key, function(value) {
        callback && callback(value);
        deferred.resolve(value);
      });
    }
    return deferred.promise;
  },

  listenKeyValueChange: function(key, listener) {
    if (!listener) {
      console.warn('ApplicationConfig的配置变化事件的监听器不能为空，必须是函数。');
    }
    var listeners = this.keyValueChangeListeners[key] || [];

    for (var i = listeners.length; i--;) {
      if (listeners[i] === listener) {
        console.warn('不允许同一个监听器listener重复监听ApplicationConfig的配置变化。');
        return;
      }
    }
    listeners.push(listener);
    this.keyValueChangeListeners[key] = listeners;
  },

  update: function(config, noListeners) {
    var oldConfig = this.config;
    this.config = config || {};

    this.fireWaitValueUpdateToNoEmptyCallbacks();
    if (!noListeners) {
      this.fireKeyValueChangeListeners(oldConfig);
    }
  },

  fireKeyValueChangeListeners: function(oldConfig) {
    var oldApplicationConfig = new ApplicationConfig(oldConfig);
    for (var key in this.keyValueChangeListeners) {
      if (this.keyValueChangeListeners.hasOwnProperty(key)) {
        var oldValue = oldApplicationConfig.getKeyValue(key);
        var newValue = this.getKeyValue(key);
        if (oldValue !== newValue) {
          var listeners = this.keyValueChangeListeners[key];
          for (var i = listeners.length; i--;) {
            listeners[i](oldValue, newValue);
          }
        }
      }
    }
  },

  fireWaitValueUpdateToNoEmptyCallbacks: function() {
    for (var key in this.waitValueUpdateToNoEmptyCallbacks) {
      if (this.waitValueUpdateToNoEmptyCallbacks.hasOwnProperty(key)) {
        var value = this.getKeyValue(key);
        var callbacks = this.waitValueUpdateToNoEmptyCallbacks[key];
        if (value) {
          for (var i = callbacks.length; i--;) {
            callbacks[i](value);
          }
          this.waitValueUpdateToNoEmptyCallbacks = [];
        }
      }
    }
  },

  addWaitValueUpdateToNoEmptyCallback: function(key, callback) {
    var callbacks = this.waitValueUpdateToNoEmptyCallbacks[key] || [];
    callbacks.push(callback);
    this.waitValueUpdateToNoEmptyCallbacks[key] = callbacks;
  }
};

function AppConfigCache() {
  var config = loadAppConfigFromLocalStorage();
  function getObjectValueFromLocalStorage(key) {
    var value = localStorage[key];
    try {
      return JSON.parse(value);
    } catch (e) {
      console.error('JSON发序列化localStorage.' + key + '时出错，localStorage中存储的值为：' + value + '。', e);
    }
  }

  function saveObjectValueToLocalStorage(key, value) {
    localStorage[key] = JSON.stringify(value);
  }

  function loadAppConfigFromLocalStorage() {
    var currentAppConfig = getObjectValueFromLocalStorage('currentAppConfig');
    if (!currentAppConfig && localStorage.serverId) {
      currentAppConfig = {
        id: localStorage.serverId,
        server: localStorage.serverUrl,
        socketServer: localStorage.socketServer,
        appId: localStorage.appId
      };
    }

    return currentAppConfig;
  }

  return {
    get: function() {
      return config;
    },
    save: function(_config) {
      config = _config;
      saveObjectValueToLocalStorage('currentAppConfig', config);
    }
  };
}

function CoreAppConfig(AppConfigCache, $q, $rootScope, configService) {
  var applicationConfig = new ApplicationConfig(AppConfigCache.get(), $q);
  var service = {
    serverUrl: applicationConfig.getServerUrl(),
    applicationConfig: applicationConfig,
    updateConfigId: updateConfigId,
    updateConfig: updateConfig,
    getAppId: function() { return applicationConfig.getAppId(); }
  };

  applicationConfig.listenKeyValueChange('serverUrl', function(oldValue, newValue) {
    service.serverUrl = newValue;
    $rootScope.$broadcast('serverUrl.changed', newValue);
  });

  function updateConfigId(id) {
    return configService.get(id).then(function(config) {
      AppConfigCache.save(config);
      applicationConfig.update(config);
    });
  }

  function updateConfig(config) {
    AppConfigCache.save(config);
    applicationConfig.update(config);
    return $q.when(true);
  }

  if (applicationConfig.getServerId())
    updateConfigId(applicationConfig.getServerId());

  return service;
}

/** @ngInject */
function AppConfig(AppModules, AppModulesAuthVisibleService, $rootScope, ConfigApp, CoreAppConfig, LinkerService) {
  var appModules = new AppModules();
  var setItems = [];
  var setItemMap = {};
  var appConfigs = {};

  if (AppModulesAuthVisibleService.get) {
    appModules.applyAuthVisible(AppModulesAuthVisibleService.get());
  }

  var appConfig = {
    home: 'core-notice',
    listPage: 'core-find',
    modules: appModules.modules,
    addModule: addModuleConfig,
    getModuleByName: getModuleByName,
    getModuleConfigByFlowType: getModuleConfigByFlowType,
    updateModule: update,
    refreshModulesAuth: refreshModulesAuth,
    showInNotice: showInNotice,
    showInFind: showInFind,
    addSetItem: addSetItem,
    getSetItems: getSetItems,
    hasModule: hasModule,
    clearAuth: clearAuth,
    getAuthFlag: true,
    getModuleNames: getModuleNames,
    viewFileByPdf: false,
    isAddModulesList: isAddModules, // 测试
    getCustomResult: getCustomResult, //获取该单位的该模块的定制结果
    getConfigKey: getKey //为了测试
  };

  function getModuleNames() {
    var moduleNames = [];
    _.each(appModules.modules, function(module) {
      moduleNames.push(module.moduleName);
    });
    return moduleNames;
  }

  /**
   * 登录成功后对登录人缓存处理
   */
  $rootScope.$on('login', function() {
    appConfig.refreshModulesAuth();
    // 从新计算config.js中的配置
    refreshConfigModulesAuth();
  });

  $rootScope.$on('logout', function() {
    appConfig.clearAuth();
  });

  function addModuleConfig(moduleConfig) {
    appModules.addToAll(moduleConfig);
    if(isAddModules(moduleConfig)) {
      return appModules.add(moduleConfig);
    }
  }

  function isAddModules(moduleConfig) {
    var moduleVisible = getCustomResult('MODULE_VISIBLE');
    if(_.isObject(moduleVisible[moduleConfig.moduleName])) { // 类似于是信息发布，里面配置对个人可见
      var showToSomeOne = moduleVisible[moduleConfig.moduleName]['showToSomeOne'];
      var currentUserId = LinkerService.currentUserId;
      for(var i = 0, len = showToSomeOne.length; i < len; i++) {
        if(showToSomeOne[i] === currentUserId) {
          return true;
        }
      }
      return false;
    } else {
      return moduleVisible[moduleConfig.moduleName];
    }
  }

  function refreshModulesAuth() {
    var moduleIds = appModules.getModuleIds();
    return AppModulesAuthVisibleService.fetch(moduleIds, ConfigApp.appTypeName)
      .then(function(authority) {
        if (authority) {
          appModules.applyAuthVisible(authority);
        }
      });
  }

  /**
   * 从新计算config.js中的权限
   */
  function refreshConfigModulesAuth() {
    var moduleVisibleMap = getCustomResult('MODULE_VISIBLE');
    for(var key in moduleVisibleMap) {
      if(_.isObject(moduleVisibleMap[key]) && moduleVisibleMap[key].hasOwnProperty('showToSomeOne')) { // 针对个人的
        var showToSomeOne = moduleVisibleMap[key]['showToSomeOne'];
        var currentUserId = LinkerService.currentUserId;
        var isChanged = showToSomeOne.find(function(one) {
          return one === currentUserId;
        });
        if(isChanged) { // 要添加的
          var moduleConfig = appModules.getModuleConfig(key);
          if(!appModules.getByModuleName(key) && moduleConfig) {
            appModules.add(moduleConfig);
          }
        } else { // 要删除的
          if(appModules.getByModuleName(key)) {
            appModules.delete(key);
          }
        }
      } else { // 针对省份的
        if(moduleVisibleMap[key]) { // true 添加的
          if(!appModules.getByModuleName(key)) { 
            var moduleConfig = appModules.getModuleConfig(key);
            if(moduleConfig) {
              appModules.add(moduleConfig);
            }
          }
        } else { // 删除
          if(appModules.getByModuleName(key)) {
            appModules.delete(key);
          }
        }
      }
    }
  }

  function clearAuth() {
    AppModulesAuthVisibleService.clear();
  }

  function getModuleConfigByFlowType(typeId) {
    return appModules.getModuleByFlowType(typeId);
  }

  function getModuleByName(moduleName) {
    return appModules.getByModuleName(moduleName);
  }

  function hasModule(module) {
    if(module) {
      return !!appModules.getByModuleName(module.moduleName) || !!appModules.getByModuleName(module);
    } else {
      return false;
    }
  }

  function update(moduleName, moduleConfig) {
    appModules.update(moduleName, moduleConfig);
  }

  function showInNotice(moduleName) {
    var module = appModules.getByModuleName(moduleName);
    if(module) {
      return !module.hasOwnProperty('showInNotice') || module.showInNotice;
    }
  }

  function showInFind(moduleName) {
    var module = appModules.getByModuleName(moduleName);
    if(module) {
      return module.showInFind;
    }
  }

  /**
  * 添加设置页面选项
  *
  * @param {SetItem} 设置对象
  * SetItem {
  *   text: {String} 展示名称
  *   state: {String} 跳转页面
  *   order: {Integer} 排序个数
  * }
  */
  function addSetItem() {
    var _setItems = arguments;

    _.each(_setItems, function(setItem) {
      if (setItemMap[setItem.text]) {
        _.each(setItems, function(value, key) {
          if (value.text === setItem.text) {
            setItems.splice(key, 1);
          }
        });
      }
      setItems.push(setItem);
      setItemMap[setItem.text] = setItem;
    });
  }

  function getSetItems() {
    return setItems;
  }

  /**
   * 根据name和key返回配置的结果
   * 如果default中有配置则返回default中的值
   * 默认返回true,也就是说如果不定制则都显示，定制了则应该为false
   * @key {String} 要获取的配置的名称
   * @defaultValue {Bollean} 该配置如果没有配置时的返回值该是什么
   */
  function getCustomResult(key, defaultValue) {
    var appConfigs = ConfigApp.appConfigs;
    var serverId = CoreAppConfig.applicationConfig.getServerId();
    return getKey(key, appConfigs, serverId, defaultValue);
  }

  function getKey(key, appConfigs, serverId, defaultValue) {
    if(_.isEmpty(defaultValue)) {
      defaultValue = true;
    }

    var appConfigServerId = appConfigs[serverId];
    var appConfigDefault = _.clone(appConfigs['default']);
    
    if(appConfigServerId && appConfigServerId.hasOwnProperty(key)) {
      // 如果appConfigServerId[key]是一个object则替换默认中的某个值，不是全部替换
      if(_.isObject(appConfigServerId[key])) { 
        var _map = appConfigDefault[key];
        var newMap = appConfigServerId[key];
        for (var key in newMap) {
          _map[key] =  newMap[key];
        }
        return _map;
      } else { // 如果appConfigServerId[key]不是一个object则替换默认中的那个值
        return appConfigServerId[key];
      } 
    } else { // 具体配置中没有，则返回默认配置中的值
      if(appConfigDefault && appConfigDefault.hasOwnProperty(key)) {
        return appConfigDefault[key];
      }
    }
    // 没有配置则返回默认值
    return defaultValue;
  }
  
  return appConfig;
}

/** @ngInject */
function ConfigApp() {
  this.appTypeName = 'sjoa';
  this.allUersGetMethod;

  // 对应存储的每个APP中的config.js文件中的配置
  this.appConfigs = {}; 

  this.setConfig= function(name, configs) {
    this.appConfigs[name] = configs;
  }
  this.setAppTypeName = function(value) {
    this.appTypeName = value;
  };

  this.setAllUsersGetMethod = function(value) {
    this.allUersGetMethod = value;
  };

  this.$get = [function() {
    return this;
  }];
}
