// web service proxy for menu
webservices.factory('httpCacheService', ['$http', '$q', 'apiConfig', 'CacheFactory', '$log', 'cacheService',
    function ($http, $q, apiConfig, CacheFactory, $log, cacheService) {
        'use strict';

        var deferred, promise;

        //Tell $http to use a cache created by CacheFactory for a specific request
        var getData = function (webApiUrl, isDbRequest) {

            deferred = $q.defer();
            promise = deferred.promise;
            var cacheName = constant.cache.cacheName;
            var start = new Date().getTime();
            var isFromCache = true;
            var cacheKey = constant.webapi.prefix + webApiUrl;
            var slashIndex = PWC.nIndexOf(webApiUrl, '/', 2);
            var questionMarkIndex = PWC.nIndexOf(webApiUrl, '?', 1);
            var routePrefix, dataCache;

            // Check to make sure the cache doesn't already exist
            //get method might be return error,so use the following way

            if (!CacheFactory.get(cacheName)) {
                CacheFactory(cacheName, {
                    storageMode: constant.cache.storageMode, // This cache will use `localStorage`.
                });
            }

            dataCache = CacheFactory.get(cacheName);

            if (slashIndex >= 0) {
                routePrefix = constant.webapi.prefix + webApiUrl.substring(0, slashIndex);
            } else if (questionMarkIndex >= 0) {
                routePrefix = constant.webapi.prefix + webApiUrl.substring(0, questionMarkIndex);
            } else {
                routePrefix = constant.webapi.prefix + webApiUrl;
                console.warn('need to verify the routePrefix in httpCache.svc.js');
            }

            // Now that control of inserting/removing from the cache is in our hands,
            // we can interact with the data in "dataCache" outside of this context,
            // e.g. Modify the data after it has been returned from the server and
            // save those modifications to the cache.
            this.finishedCache = false;
            if (dataCache.get(cacheKey) && !isDbRequest) {
                var data = dataCache.get(cacheKey);
                deferred.resolve(data.cacheResult);
                isFromCache = true;
                logTimeTakenInfo(cacheKey, start, isFromCache);

                promise = deferred.promise;
                this.finishedCache = true;
                return this;
            } else {
                var that = this;
                $http.get(webApiUrl, apiConfig.create()).success(function (data) {
                    cacheService.getCacheByKey(routePrefix).success(function (cache) {

                        var cacheResult = {};

                        isFromCache = false;
                        deferred.resolve(data);
                        logTimeTakenInfo(cacheKey, start, isFromCache);

                        //if could get the last modify time from cache, then align the same cache time
                        if (!cache && typeof (cache) != constant.common.undefined && cache != 0) {
                            cacheResult = { 'cacheResult': data, 'cacheTime': constant.cache.defaultCacheTime };

                        } else {
                            cacheResult = { 'cacheResult': data, 'cacheTime': cache.lastModifyTime };
                        }

                        promise = deferred.promise;
                        dataCache.put(cacheKey, cacheResult);
                        that.finishedCache = true;
                    });
                });
            }

            return this;
        };

        var promiseSuccess = function (fn) {
            promise.then(function (data) {
                fn(data);
            });
            return this;
        };

        var promiseError = function (fn) {
            promise.then(null, function (response) {
                fn(data);
            });
            return this;
        };

        var logTimeTakenInfo = function (cacheKey, start, isFromCache) {
            if (isFromCache) {
                $log.info('time taken from cache - ' + cacheKey + ': ' + (new Date().getTime() - start) + 'ms');
            } else {
                $log.info('time taken from server - ' + cacheKey + ': ' + (new Date().getTime() - start) + 'ms');
            }
        };


        // 加这个方法的原因是,getData 方法,在处理多个请求并发从后端取数据就会出现问题,可能是因为promise已经被替换成最新的了。
        var getCache = function (webApiUrl, isDbRequest, fn) {

            var cacheName = constant.cache.cacheName;
            var start = new Date().getTime();
            var isFromCache = true;
            var cacheKey = constant.webapi.prefix + webApiUrl;
            var slashIndex = PWC.nIndexOf(webApiUrl, '/', 2);
            var questionMarkIndex = PWC.nIndexOf(webApiUrl, '?', 1);
            var routePrefix, dataCache;

            // Check to make sure the cache doesn't already exist
            //get method might be return error,so use the following way

            if (!CacheFactory.get(cacheName)) {
                CacheFactory(cacheName, {
                    storageMode: constant.cache.storageMode, // This cache will use `localStorage`.
                });
            }

            dataCache = CacheFactory.get(cacheName);

            if (slashIndex >= 0) {
                routePrefix = constant.webapi.prefix + webApiUrl.substring(0, slashIndex);
            } else if (questionMarkIndex >= 0) {
                routePrefix = constant.webapi.prefix + webApiUrl.substring(0, questionMarkIndex);
            } else {
                routePrefix = constant.webapi.prefix + webApiUrl;
                console.warn('need to verify the routePrefix in httpCache.svc.js');
            }

            // Now that control of inserting/removing from the cache is in our hands,
            // we can interact with the data in "dataCache" outside of this context,
            // e.g. Modify the data after it has been returned from the server and
            // save those modifications to the cache.
            if (dataCache.get(cacheKey) && !isDbRequest) {
                var data = dataCache.get(cacheKey);

                isFromCache = true;
                logTimeTakenInfo(cacheKey, start, isFromCache);


                if (fn) {
                    fn(data.cacheResult);
                }
            } else {

                $http.get(webApiUrl, apiConfig.create()).success(function (data) {
                    cacheService.getCacheByKey(routePrefix).success(function (cache) {

                        var cacheResult = {};

                        isFromCache = false;


                        logTimeTakenInfo(cacheKey, start, isFromCache);

                        //if could get the last modify time from cache, then align the same cache time
                        if (!cache && typeof (cache) != constant.common.undefined && cache != 0) {
                            cacheResult = { 'cacheResult': data, 'cacheTime': constant.cache.defaultCacheTime };

                        } else {
                            cacheResult = { 'cacheResult': data, 'cacheTime': cache.lastModifyTime };
                        }

                        dataCache.put(cacheKey, cacheResult);
                        //promiseSuccess(thisObj.success);
                        if (fn) {
                            fn(data);
                        }
                    });
                });
            }
        };

        return {
            get: getData,
            success: promiseSuccess,
            error: promiseError,
            getCache: getCache
        };
    }]);