(function (window, undefined) {
    var version = window["fu_cache_version"] || window.top["fu_cache_version"] || "0.1";
    var expire_days = window["fu_cache_expire"] || window.top["fu_cache_expire"] || 180;//180 day
    var cache_prefix_key = window["fu_cache_prefix_key"] || window.top["fu_cache_prefix_key"] || "fu_page_cache_";
    var localStorage = window.localStorage;

    var util = {
        setStorage: function (key, value, expire_days) {
            if (!localStorage) {
                return;
            }
            localStorage.setItem(key, arguments.length > 2 ?
                JSON.stringify({
                    _zexpires_time: (expire_days | 0) * 1440000 + Date.now(),
                    value: value
                }) : JSON.stringify(value));
        },
        getStorage: function (key) {
            if (!localStorage) {
                return undefined;
            }
            var value = localStorage.getItem(key);
            if (value) {
                value = JSON.parse(value);
                if (typeof value === "object" && value.hasOwnProperty("_zexpires_time")) {
                    return value._zexpires_time < Date.now() ? undefined : value.value;
                }
                return value;
            }
            return undefined;
        },
        clearStorage: function () {
            if (!localStorage) {
                return;
            }
            Object.keys(localStorage).forEach(function (key) {
                if (key.indexOf(cache_prefix_key) === 0) {
                    localStorage.removeItem(key);
                }
            });
        },
        queryAll: function (selector, root) {
            return Array.prototype.slice.call((root || document).querySelectorAll(selector));
        },
        removeEle: function (ele) {
            var parentNode = ele.parentNode;
            if (parentNode) {
                parentNode.removeChild(ele);
            }
        },
        setInner: function (innerEle, content) {
            innerEle.innerHTML = content;
            Array.prototype.slice.call(innerEle.querySelectorAll("script")).forEach(function (scriptItem) {
                util.evalScript(scriptItem);
            });
        },
        loadAndCache: function (url, key, completeCallBack, type) {
            var httpRequest = new XMLHttpRequest();
            httpRequest.onreadystatechange = function () {
                if (httpRequest.readyState === XMLHttpRequest.DONE && (httpRequest.status / 100 | 0) === 2) {
                    if (type === "img") {
                        var reader = new FileReader();
                        reader.onload = function () {
                            util.setStorage(cache_prefix_key + key, reader.result, expire_days);
                            completeCallBack(reader.result);
                        };
                        reader.readAsDataURL(httpRequest.response);
                    } else {
                        var responseText = httpRequest.responseText;
                        util.setStorage(cache_prefix_key + key, responseText, expire_days);
                        completeCallBack(responseText);
                    }
                }
            };
            if (type === "img") {
                if (window.navigator.userAgent.indexOf('MSIE ') > 0) {
                    httpRequest.onloadstart = function (ev) {
                        httpRequest.responseType = "blob";
                    }
                } else {
                    httpRequest.responseType = "blob";
                }
            }
            httpRequest.open("GET", url);
            httpRequest.send();
        },
        evalScript: function (scriptEle) {
            var head = document.getElementsByTagName("head")[0] || document.documentElement;
            var data = (scriptEle.text || scriptEle.textContent || scriptEle.innerHTML || "");
            var src = scriptEle.getAttribute("src");
            var script;
            if (data) {
                script = document.createElement("script");
                script.appendChild(document.createTextNode("(function (window,undefined){" + data + "})(window);"));
            } else if (src) {
                script = document.createElement("script");
                script.src = src;
            }
            if (script) {
                head.insertBefore(script, head.lastChild);
                util.removeEle(scriptEle);
            }
        },
        onReady: function (callBack) {
            if (util.isReady()) {
                setTimeout(callBack, 10);
            } else {
                document.addEventListener("DOMContentLoaded", function () {
                    if (util.isReady()) {
                        callBack();
                    }
                });
            }
        },
        isReady: function () {
            var readyState = document.readyState;
            return readyState === "complete" || readyState === "interactive";
        },
        getCacheKey: function (ele, path, with_prefix) {
            var key = ele.getAttribute("key") || path.split("/").reverse()[0] || path;
            return with_prefix === true ? cache_prefix_key + key : key;
        }
    };
    /********************************************load cached js&css********************************************/
    var loadCachedJSAndCSS = function (root) {
        ["js-src", "css-href"].forEach(function (attr) {
            util.queryAll("[" + attr + "]", root).forEach(function (item) {
                var src = item.getAttribute(attr);
                if (src) {
                    var cache = util.getStorage(util.getCacheKey(item, src, true));
                    if (cache) {
                        var js = document.createElement(attr === "js-src" ? "script" : "style");
                        js.innerHTML = cache;
                        item.parentNode.insertBefore(js, item.nextSibling);
                        util.removeEle(item);
                    } else {
                        if (attr === "js-src") {
                            document.write("<script src='" + src + "'></script>")
                        } else {
                            document.write("<link rel='stylesheet' href='" + src + "'>")
                        }
                    }
                }
            });
        });
    };
    /********************************************load and cache js&css********************************************/
    var loadAndCacheJSAndCSS = function (root) {
        ["js-src", "css-href"].forEach(function (attr) {
            util.queryAll("[" + attr + "]", root).forEach(function (item) {
                var src = item.getAttribute(attr);
                if (src) {
                    util.loadAndCache(src, util.getCacheKey(item, src), function () {
                        util.removeEle(item);
                    })
                }
            });
        });
    };
    /********************************************load and cache img********************************************/
    var loadAndCacheImg = function (root) {
        util.queryAll("[img-src]", root).forEach(function (item) {
            var src = item.getAttribute("img-src");
            if (src) {
                var cache = util.getStorage(util.getCacheKey(item, src, true));
                if (cache) {
                    item.setAttribute("src", cache);
                } else {
                    util.loadAndCache(src, util.getCacheKey(item, src), function (img) {
                        item.setAttribute("src", img);
                    }, "img");
                }
            }
        });
    };
    /********************************************load inner-url********************************************/
    var loadInnerPage = function (root) {
        var onCacheReady = window["onCacheReady"];
        var _onCacheReady = typeof onCacheReady === "function" ? function () {
            setTimeout(onCacheReady, 10);
        } : null;

        var arr = util.queryAll("[inner-url]", root);
        var count = arr.length;
        if (count === 0) {
            if (_onCacheReady) {
                _onCacheReady();
            }
        } else {
            var _setInner = function (item, content) {
                util.setInner(item, content);
                count--;
                if (count === 0) {
                    if (_onCacheReady) {
                        _onCacheReady();
                    }
                }
            };
            arr.forEach(function (innerEle) {
                var url = innerEle.getAttribute("inner-url");
                if (url) {
                    var cache = util.getStorage(util.getCacheKey(innerEle, url, true));
                    if (cache) {
                        _setInner(innerEle, cache);
                    } else {
                        util.loadAndCache(url, util.getCacheKey(innerEle, url), function (responseText) {
                            _setInner(innerEle, responseText);
                        });
                    }
                    // item.removeAttribute("key");
                    // item.removeAttribute("inner-url");
                }
            });
        }
    };

    /********************************************version********************************************/
    if (util.getStorage(cache_prefix_key + "version") !== version) {
        util.clearStorage();
        util.setStorage(cache_prefix_key + "version", version);
    }
    loadCachedJSAndCSS();
    util.onReady(function () {
        loadInnerPage();
        loadAndCacheImg();
        loadAndCacheJSAndCSS();
    });
})(window);

