var angular = require('angular');
require('../modules');
require('../services/AppConfig');
var Swipe = require('swipe');
var isHome, isListPage;

angular
  .module('commons.directives')
  .directive('sinoListTabs', sinoListTabs)
  .factory('sinoListTabsService', sinoListTabsService)
  .controller('SinoListTabsController', SinoListTabsController)
  .directive('sinoListPane', sinoListPane)
  .controller('sinoListPaneController', sinoListPaneController)
  .directive('sinoListPane2', sinoListPane2)
  .directive('sinoListPaneCacheItem', sinoListPaneCacheItem)
  .run(onStateChange);

/** @ngInject */
function onStateChange($rootScope, AppConfig) {
  $rootScope.$on('$stateChangeSuccess', function(
    event, toState, toParams, fromState, fromParams) {
    var prevState = fromState.name;
    isHome = prevState === AppConfig.home;
    isListPage = prevState === AppConfig.listPage;
  });
}

/** @ngInject */
function sinoListTabs() {
  return {
    restrict: 'E',
    templateUrl: 'views/commons/directives/sinoListTabs.tpl.html',
    transclude: true,
    scope: {
      name: '@'
    },
    controller: 'SinoListTabsController',
    controllerAs: 'tabsCtrl'
  };
}

function getSelectedIndexFromPrevState() {
  return isHome? 0 : isListPage ? 1 : -1;
}

/** @ngInject */
function SinoListTabsController(
  $scope, $element, $window, sinoListTabsService, $timeout) {
  var ctrl = this;
  var panes = ctrl.panes = [],
    selectedIndex  = getSelectedIndexFromPrevState();


  if (selectedIndex === -1) {
    selectedIndex = sinoListTabsService.get($scope.name);
  } else {
    sinoListTabsService.update($scope.name, selectedIndex);
  }

  ctrl.$scope = $scope;
  var cacheIndexs = [], // 缓存pane
    paneMap = {},
    element = $element[0];

  ctrl.swipe;
  ctrl.select = select;
  ctrl.addPane = addPane;
  ctrl.getSwipe = getSwipe;

  /** pane数据处理 */

  function addPane(pane) {
    if(!paneMap[pane.name]) {
      panes.push(pane);
      paneMap[pane.name] = pane;
    }
    if (panes.length - 1 === selectedIndex) {
      this.select(selectedIndex);
    }
  }

  function getPaneByName(paneName) {
    return paneMap[paneName];
  }

  /** 滚动位置记忆处理 */

  function getActivePanelScrollDelegate() {
    var activePane = panes[selectedIndex];
    return activePane.scrollDelegate;
  }

  function setScrollDelegate(paneName, scrollDelegate) {
    var pane = getPaneByName(paneName);
    if (pane) {
      pane.scrollDelegate = scrollDelegate;
    }
  }
  ctrl.setScrollDelegate = setScrollDelegate;

  function cacheActivePaneScrollPosition() {
    var scrollDelegate = getActivePanelScrollDelegate();
    if (scrollDelegate) {
      sinoListTabsService.cachePosition(
        $scope.name, selectedIndex, scrollDelegate.getScrollPosition());
    }
  }

  $scope.$parent.$on('$ionicView.beforeLeave', cacheActivePaneScrollPosition);

  /** swipe处理 */

  getSwipe();
  $window.addEventListener('transitionend', onTransitionend);
  $scope.$on('$destroy', function() {
    if (ctrl.swipe) {
      ctrl.swipe.kill();
      ctrl.swipe = null;
    }
    $window.removeEventListener('transitionend', onTransitionend);
  });

  function onTransitionend(event) {
    var target = event.target;
    if (isSinoListPane(target) && hasParent(target, element)) {
      $scope.$evalAsync(function() {
        var position = ctrl.swipe.getPos();
        if(position != selectedIndex) {
          select(position);
        }
      });
    }
  }

  function isSinoListPane(element) {
    return element && element.tagName.toLowerCase() === 'sino-list-pane';
  }

  function hasParent(element, parent) {
    var _parent = element;
    while (_parent != parent) {
      _parent = _parent.parentElement;
      if (_parent === document.body) {
        return false;
      }
    }
    return true;
  }

  function getSwipe() {
    if(ctrl.swipe) return ctrl.swipe;
    ctrl.swipe = Swipe($window.document.getElementsByClassName('tab-swipe')[0], {
      continuous: false,
      bouncing: true
    });
    return ctrl.swipe;
  }

  /** 选中处理 */

  function select(_index) {
    var pane = panes[_index];

    selectedIndex = _index;
    sinoListTabsService.update($scope.name, _index);//缓存一下
    updatePaneSelectedState(_index);

    ctrl.swipe.setup();
    ctrl.swipe.slide(_index);

    if ((!pane.inited) && pane.loadData) {
      pane.inited = true;
      var needScroll = pane.cacheArray.onceCache;
      pane.loadData().then(function() {
        if (needScroll) {
          applyCachedPos();
        }
      });
    }

    $scope.$broadcast('paneChange', _index, panes[_index]);
  }

  function applyCachedPos() {
    $timeout(function() {
        var scrollDelegate = getActivePanelScrollDelegate();
        var position = sinoListTabsService.getPosition($scope.name, selectedIndex);
        if (position) {
          scrollDelegate.scrollTo(position.left, position.top, false);
        }
      });
  }

  function updatePaneSelectedState(selectedIndex) {
    for (var i = 0, len = panes.length; i < len; i++) {
      panes[i].selected = i === selectedIndex;
    }
  }
}

/** @ngInject */
function sinoListTabsService() {
  var cache = {};
  var positionCache = {};
  return {
    get: function(name) {
      return cache[name] || 0;
    },
    update: function(name, position) {
      cache[name] = position;
    },
    cachePosition: function(name, selectedIndex, position) {
      positionCache[name + '_' + selectedIndex] = position;
    },
    getPosition: function(name, selectedIndex) {
      return positionCache[name + '_' + selectedIndex];
    }
  };
}

/** @ngInject */
function sinoListPane($timeout, $q) {
  function delay(promise, delayTime) {
    var delayPromise = $timeout(function() {}, delayTime);
    return $q.all([promise, delayPromise])
      .then(function(results) {
        return results[0];
      });
  }

  return {
    restrict: 'E',
    templateUrl: 'views/commons/directives/sinoListPane.tpl.html',
    transclude: true,
    require: '^sinoListTabs',
    scope: {
      title: '@',
      cacheArray: '='
    },
    controller: 'sinoListPaneController',
    controllerAs: 'listPaneCtrl',
    link: function(scope, element, attrs, sinoListTabsCtrl) {
      scope.state = 1;
      scope.sinoListTabsCtrl = sinoListTabsCtrl;
      scope.name = scope.name ||
        'sinoListPane_' + parseInt(1000 * Math.random()) + '_' + new Date().valueOf();
      scope.onRefresh = scope.loadData = function() {
        scope.state = isEmpty()? 1 : scope.state;
        scope.refreshing = true;

        var loadDataPromise = scope.cacheArray.onceCache?
          $q.when({}) : delay(scope.cacheArray.refresh(), 300);
        if (scope.cacheArray.onceCache) {
          scope.cacheArray.onceCache = false;
          scope.state = isEmpty()? 4 : 2;
          scope.refreshing = false;
        }

        return loadDataPromise
        .then(applyResult, function() {
          scope.state = 3;
        })
        ['finally'](function() {
          sinoListTabsCtrl.$scope.$broadcast('scroll.refreshComplete');//刷新事件加载完毕
          $timeout(function() {
            scope.refreshing = false;
          }, 1000);//等待下拉刷新完成。
        });
      };

      scope.loadMoreData = function() {
        return scope.cacheArray.loadMore(scope.cacheArray.number)
        .then(applyResult)
        ['finally'](function() {
          sinoListTabsCtrl.$scope.$broadcast('scroll.infiniteScrollComplete');
          sinoListTabsCtrl.$scope.$broadcast('scroll.resize');
        });
      };

      scope.moreDataCanBeLoaded = function() {
        var result = scope.cacheArray;
        return (!scope.refreshing) && scope.state == 2 && result && result.number >= 0 && result.number < result.totalPages;
      };

      var isEmpty = function() {
        var result = scope.cacheArray;
        return result == null || result.items == null ||
          result.items.length == 0;
      };

      function applyResult() {
        if (isEmpty()) {
          scope.state = 4;
        } else {
          scope.state = 2;
        }
      }

      sinoListTabsCtrl.addPane(scope);
    }
  };
}

/** @ngInject */
function sinoListPaneController($scope, $element, $attrs) {
  var ctrl = this;
  ctrl.$scope = $scope;
}

/** @ngInject */
function sinoListPaneCacheItem(){
  return {
    restrict: 'A',
    scope: {
      cacheArray: '=sinoListPaneCacheItem'
    },
    link: function(scope, element, attrs) {
      element.on('click', function() {
        scope.cacheArray.onceCache = true;
      });
    }
  };
}

/** @ngInject */
function sinoListPane2($timeout, $q) {
  function delay(promise, delayTime) {
    var delayPromise = $timeout(function() {}, delayTime);
    return $q.all([promise, delayPromise])
      .then(function(results) {
        return results[0];
      });
  }

  return {
    restrict: 'E',
    templateUrl: 'views/commons/directives/sinoListPane.tpl.html',
    transclude: true,
    require: '^sinoListTabs',
    scope: {
      title: '@',
      _moreDataCanBeLoaded: '&moreDataCanBeLoaded',
      _loadData: '&loadData',
      _loadMoreData: '&loadMoreData',
      emptyFn: '&emptyFn'
    },
    link: function(scope, element, attrs, sinoListTabsCtrl) {
      var result;
      scope.state = 1;
      scope.loadData = function() {
        scope.state = isEmpty()? 1 : scope.state;
        scope.refreshing = true;
        return delay(scope._loadData(), 300)
          .then(applyResult, function() {
            scope.state = 3;
          })
          ['finally'](function() {
            sinoListTabsCtrl.$scope.$broadcast('scroll.refreshComplete');
            $timeout(function() {
              scope.refreshing = false;
            }, 1000);//等待下拉刷新完成。
          });
      };

      scope.loadMoreData = function() {
        return scope._loadMoreData().then(applyResult)['finally'](function() {
          sinoListTabsCtrl.$scope.$broadcast('scroll.infiniteScrollComplete');
              sinoListTabsCtrl.$scope.$broadcast('scroll.resize');
        });
      };

      scope.moreDataCanBeLoaded = attrs.moreDataCanBeLoaded? scope._moreDataCanBeLoaded :
      function() {
        return (!scope.refreshing) && scope.state == 2 && result && result.number >= 0 && result.number < result.totalPages;
      };

      var isEmpty = attrs.emptyFn? scope.emptyFn : function() {
        return result == null || result.items == null ||
          result.items.length == 0;
      };

      function applyResult(list) {
        result = list;
        if (isEmpty()) {
          scope.state = 4;
        } else {
          scope.state = 2;
        }
        return result;
      }

      sinoListTabsCtrl.addPane(scope);
    }
  };
}
