Registry.require("promise helper i18n xmlhttprequest uri permission convert".split(" "),
function() {
    var f = {
        DEFAULT: "default",
        OFF: "off",
        NATIVE: "native",
        CHROME: "chrome",
        NOT_ENABLED: "not_enabled",
        NOT_WHITELISTED: "not_whitelisted",
        NOT_PERMITTED: "not_permitted",
        NOT_SUPPORTED: "not_supported",
        NOT_SUCCEEDED: "not_succeeded"
    },
    h = Registry.log,
    u = rea.FEATURES,
    l = Registry.get("promise"),
    q = Registry.get("helper"),
    k = Registry.get("permission"),
    v = Registry.get("i18n"),
    C = Registry.get("xmlhttprequest"),
    D = Registry.get("uri"),
    E = Registry.get("convert"),
    F = C.run,
    m = f.OFF,
    w = [],
    p = null,
    x = !1,
    n = {},
    y = !1,
    z = function() {
        var a = l();
        Registry.vendor(["vendor/saveas/filesaver"],
        function() {
            z = l.Pledge;
            a.resolve()
        });
        return a.promise()
    },
    r = function() {
        return null !== p ? l.Pledge(p) : !rea.permissions.supported && rea.downloads.supported ? (p = !0, l.Pledge(p)) : k.has(k.permDownloads).then(function(a) {
            p = a;
            h.debug("downs: permission to use rea.downloads ->", a);
            return r()
        })
    },
    G = function(a, b) {
        if (this[a]) this[a]("function" == typeof b ? b() : b)
    },
    t = function(a, b) {
        this[a] && (G.apply(this, arguments), this[a] = null)
    },
    H = 0,
    I = function(a, b, c) {
        p && !y && rea.downloads.supported && (rea.downloads.onChanged.addListener(A), y = !0);
        var e = {
            filename: b.name
        },
        d;
        u.RUNTIME.FIREFOX && 52 > u.RUNTIME.BROWSER_VERSION ? d = ["url"] : (d = ["url", "method", "saveAs", "headers"], e.body = b.data);
        d.forEach(function(a) {
            e[a] = b[a]
        });
        var g = n[a] = {
            callbacks: c,
            url: b.url,
            name: b.name
        };
        rea.downloads.download(e,
        function(a) {
            g.id = a;
            var c = function(c) {
                rea.downloads.cancel(a,
                function() {
                    b();
                    c && c()
                })
            },
            b = function() {
                rea.downloads.search({
                    id: a
                },
                function(c) {
                    var b; (b = c[0]) ? A(b) : h.warn("downs: unable to query download ID", a)
                })
            }; ! 0 === g.cancel ? c() : (g.cancel = c, g.interval = window.setInterval(b, 1E3))
        })
    },
    J = function(a, b, c) {
        void 0 === c && (c = {});
        var e = function() {
            return t.apply(c, arguments)
        };
        b.responseType = "blob";
        b.method = b.method || "GET";
        var d = F(b, {
            onload: function(a) {
                if (4 != a.readyState || 200 != a.status && 0 != a.status || a.error) e("onerror", {});
                else {
                    var c = null; (a.responseHeaders ? a.responseHeaders.split("\n") : []).forEach(function(a) {
                        var b = a.split(":");
                        a = b.shift() || "";
                        b = b.join(":") || "";
                        "content-type" == a.trim().toLowerCase() && (c = b.trim())
                    });
                    a = new Blob([a.response], {
                        type: b.overrideMimeType || c || "binary/octet-stream"
                    });
                    saveAs(a, b.name);
                    e("onload", {})
                }
            },
            ondone: function() {
                e("ondone", {});
                delete n[a]
            },
            onerror: c.onerror,
            ontimeout: c.ontimeout,
            onprogress: c.onprogress
        });
        n[a] = {
            cancel: d ? d.abort: function() {}
        }
    },
    A = function(a) {
        var b, c;
        Object.keys(n).every(function(d) {
            var e;
            return (e = n[d]) && e.id == a.id ? (c = d, b = e, !1) : !0
        });
        if (b) {
            var e = b.callbacks,
            d = function() {
                return t.apply(e, arguments)
            },
            g = function() {
                b.interval && (window.clearInterval(b.interval), b.interval = null);
                delete n[c]
            };
            a.error || a.state && "interrupted" == a.state.current ? (h.warn("downs: download of", b.name, "(" + b.url + ")", "failed", a.error), d("onerror", {
                error: f.NOT_SUCCEEDED,
                details: a.error
            }), g()) : a.endTime || a.state && "complete" == a.state.current ? (h.debug("downs: download of", b.name, "(" + b.url + ")", "finished"), d("onload", {}), d("ondone", {}), g()) : void 0 === a.totalBytes && void 0 === a.bytesReceived || d("onprogress", {
                loaded: a.bytesReceived,
                total: a.totalBytes,
                estimatedEndTime: a.estimatedEndTime
            })
        }
    },
    B = function(a) {
        var b = !1;
        q.each(w,
        function(c, e) {
            if (c && c.length) try {
                var d;
                if ("/" === c[0]) c = c.replace(/^\//g, "").replace(/\/$/g, ""),
                "$" !== c[c.length - 1] && (h.debug("downs: patching $ into", c), c += "$"),
                d = new RegExp(c, "i");
                else if ("." === c[0]) {
                    var g = [q.escapeForRegExp(c), "$"].join("");
                    d = new RegExp(g, "i")
                } else h.warn("downs: invalid file extension:", '"' + c + '"', 'starts neither with "." nor with "/"');
                if (d && -1 !== a.search(d)) return h.debug("downs:", c, "matched @", a),
                b = !0
            } catch(f) {
                h.warn("downs: can't process", c, f)
            }
        });
        return b
    };
    Registry.register("downloads", "5770", {
        start: function(a, b) {
            var c = this,
            e = H++,
            d = [e].concat(Array.prototype.slice.call(arguments)),
            g = function() {
                return t.apply(b, arguments)
            };
            h.debug("downs: start", a);
            if (!a.internal) {
                if (m == f.OFF) {
                    h.warn("downs: feature is not enabled");
                    g("onerror", {
                        error: f.NOT_ENABLED
                    });
                    return
                }
                if (!a.name || !B(a.name)) {
                    h.warn("downs:", a.name, "is not whitelisted");
                    g("onerror", {
                        error: f.NOT_WHITELISTED
                    });
                    return
                }
                if (!rea.downloads.supported && m == f.CHROME) {
                    h.warn("downs: this download mode is not supported");
                    g("onerror", {
                        error: f.NOT_SUPPORTED
                    });
                    return
                }
            } (function() {
                return ! rea.downloads.supported || m != f.CHROME && m != f.DEFAULT ? l.Breach() : r().then(function(a) {
                    if (a) I.apply(c, d);
                    else if (m == f.CHROME) h.warn("downs: download permission is missing"),
                    g("onerror", {
                        error: f.NOT_PERMITTED
                    });
                    else return l.Breach()
                })
            })().fail(function() {
                var b = D.parse(a.url);
                a.name = a.name || "File.download";
                z().done(function() {
                    "data:" == b.protocol ? saveAs(E.dataURItoBlob(a.url), a.name) : J.apply(c, d)
                })
            });
            return e
        },
        cancel: function(a) {
            if (a = n[a]) return a.cancel ? "function" === typeof a.cancel && a.cancel() : a.cancel = !0,
            !0
        },
        set_mode: function(a) {
            m = a;
            m == f.CHROME && r().done(function(a) {
                a || k.has(k.permDownloads).then(function(a) {
                    var b = l();
                    x || a ? b.resolve({
                        permission: a,
                        asked: !1
                    }) : k.ask(k.permDownloads, v.getMessage("Browser_API_Downloads"), v.getMessage("Click_here_to_allow_TM_to_start_downloads")).done(function(a) {
                        b.resolve({
                            permission: a,
                            asked: !0
                        })
                    });
                    x = !0;
                    return b.promise()
                }).done(function(a) {
                    a.permission && a.asked && rea.page.reload()
                })
            })
        },
        set_whitelist: function(a) {
            "Array" === q.toType(a) && (w = a)
        },
        is_whitelisted: B,
        remove_permission: function() {
            return k.remove(k.permDownloads)
        },
        staticVars: f
    })
});