/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

var totp = new jsOTP.totp();

function parseOTP(jsontext, reload) {
    var keys = [];
    if (jsontext !== null && jsontext != "") {
        var keys = JSON.parse(jsontext || "[]");
        if (keys.length > 0) {
            //$("#nokeys").css("display", "none");
        }
        var tmpldata = [];
        for (var i = 0; i < keys.length; i++) {
            var code = totp.getOtp(keys[i]["secret"]);
            // Escape HTML characters
            var label = $('<div/>').html(keys[i]["label"]).html();
            var issuer = $('<div/>').text(keys[i]["issuer"]).html();
            tmpldata.push({
                code: code,
                secret: keys[i]["secret"],
                label: label,
                issuer: issuer,
                index: i
            });
        }
        router.navigate("/otp", {
            context: {
                otpcodes: tmpldata
            },
            reloadCurrent: (reload == true ? true : false)
        });
        setInterval(function () {
            refreshCountdown();
            refreshCodes();
        }, 1000);

        refreshCountdown();
    }
}

function setProgressBar(percent) {
    if (mainView.router.currentRoute.name == "otp") {
        app.progressbar.show(percent, app.theme === 'md' ? 'yellow' : 'blue');
    } else {
        app.progressbar.hide();
    }
}

function loadOTPPage(reload) {
    var ls_text = localStorage.getItem("otp");
    if (ls_text === null || ls_text == "") {
        // Recover from NativeStorage
        NativeStorage.getItem("otp", function (data) {
            localStorage.setItem("otp");
            parseOTP(data, reload);
        }, function (error) {
            parseOTP("[]", reload);
        });
    } else {
        parseOTP(ls_text, reload);
    }
}

function refreshCountdown() {
    var percent = ((30 - ((new Date).getSeconds() % 30)) / 30) * 100;
    setProgressBar(percent);
}

function refreshCodes() {
    $(".otpcard").each(function () {
        var code = totp.getOtp($(this).data("secret"));
        $(".otpcode", this).text(code);
    });
}

function deleteOTPCode(index) {
    var label = $(".otpcard[data-index=" + index + "] .otplabel").text();
    navigator.notification.confirm("Delete auth key?  This cannot be undone, so make sure you don't need this key to login anymore!", function (result) {
        if (result != 1) {
            return;
        }
        var keys = JSON.parse(localStorage.getItem("otp"));
        keys.splice(index, 1);
        localStorage.setItem("otp", JSON.stringify(keys));
        NativeStorage.setItem("otp", JSON.stringify(keys));
        loadOTPPage(true);
    }, "Delete " + label + "?");
}

function addOTPCode(key, label, issuer) {
    if (key == "") {
        navigator.notification.alert("Missing secret key.", null, "Error", 'Dismiss');
        return;
    }
    key = key.toUpperCase();
    /* Thanks to https://stackoverflow.com/a/27362880 for the regex */
    if (!key.match(/^(?:[A-Z2-7]{8})*(?:[A-Z2-7]{2}={6}|[A-Z2-7]{4}={4}|[A-Z2-7]{5}={3}|[A-Z2-7]{7}=)?$/)) {
        navigator.notification.alert("Secret key is not valid base32.", null, "Error", 'Dismiss');
        return;
    }
    if (label == "") {
        navigator.notification.alert("Missing label.", null, "Error", 'Dismiss');
        return;
    }
    var ls_text = localStorage.getItem("otp");
    var keys = [];
    if (ls_text != null && ls_text != "") {
        keys = JSON.parse(ls_text || "[]");
    }

    keys.push({"secret": key, "label": label, "issuer": issuer});
    localStorage.setItem("otp", JSON.stringify(keys));
    NativeStorage.setItem("otp", JSON.stringify(keys));

    app.toast.create({
        text: '2-factor key saved.',
        closeButton: true,
    }).open();
    loadOTPPage(true);
}

function scanOTPCode() {
    try {
        cordova.plugins.barcodeScanner.scan(
                function (result) {
                    if (!result.cancelled) {
                        try {
                            var url = decodeURI(result.text);
                        } catch (e) {
                            navigator.notification.alert("Could not decode OTP URI.", null, "Error", 'Dismiss');
                            return;
                        }
                        if (!url.startsWith("otpauth://")) {
                            navigator.notification.alert("Invalid OTP code.  Try again.", null, "Error", 'Dismiss');
                            return;
                        }
                        if (!url.startsWith("otpauth://totp/")) {
                            navigator.notification.alert("Unsupported key type.", null, "Error", 'Dismiss');
                            return;
                        }
                        var stripped = url.replace("otpauth://totp/", "");
                        var params = stripped.split("?")[1].split("&");
                        var label = stripped.split("?")[0];
                        var secret = "";
                        var issuer = "";
                        for (var i = 0; i < params.length; i++) {
                            var param = params[i].split("=");
                            if (param[0] == "secret") {
                                secret = param[1].toUpperCase();
                            } else if (param[0] == "issuer") {
                                issuer = param[1];
                            } else if (param[0] == "algorithm" && param[1].toLowerCase() != "sha1") {
                                navigator.notification.alert("Unsupported hash algorithm.", null, "Error", 'Dismiss');
                                return;
                            } else if (param[0] == "digits" && param[1] != "6") {
                                navigator.notification.alert("Unsupported digit count.", null, "Error", 'Dismiss');
                                return;
                            } else if (param[0] == "period" && param[1] != "30") {
                                navigator.notification.alert("Unsupported period.", null, "Error", 'Dismiss');
                                return;
                            }
                        }
                        try {
                            secret = decodeURIComponent(secret);
                            issuer = decodeURIComponent(issuer);
                            label = decodeURIComponent(label);
                        } catch (e) {
                            navigator.notification.alert("Could not decode OTP URI.", null, "Error", 'Dismiss');
                            return;
                        }
                        addOTPCode(secret, label, issuer);
                    }
                },
                function (error) {
                    navigator.notification.alert("Scanning failed: " + error, null, "Error", 'Dismiss');
                },
                {
                    "showFlipCameraButton": false,
                    "prompt": "Scan OTP QR code."
                }
        );
    } catch (ex) {
        navigator.notification.alert(ex.message, null, "Error", 'Dismiss');
    }
}

function addManualOTP() {
    var label = $("#addotp_sheetmodal #label").val();
    var secret = $("#addotp_sheetmodal #secret").val().replace(/\s+/g, '');
    app.sheet.close("#addotp_sheetmodal");
    addOTPCode(secret, label, "");
}