// switch (window.location.hostname) {
//     case "127.0.0.1":
//     case "[::1]":
//     case "localhost":
//         break;
//     default:
//         window.console.log = function () { };
//         window.console.info = function () { };
//         window.console.warn = function () { };
//         window.console.error = function () { };
//         window.console.debug = function () { };
//         break;
// }

// 格式化 Date 对象为易读文本。
window.toLucid = function (date) {
    if (typeof date == "number" || typeof date == "string") date = new Date(date);
    if (date && date instanceof Date) {
        var year = date.getFullYear();
        var month = date.getMonth() + 1;
        var day = date.getDate();
        var hour = date.getHours();
        var minute = date.getMinutes();
        var second = date.getSeconds();
        var milli = date.getMilliseconds();
        year = (year < 10 ? "000" : (year < 100 ? "00" : (year < 1000 ? "0" : ""))) + String(year);
        month = (month < 10 ? "0" : "") + String(month);
        day = (day < 10 ? "0" : "") + String(day);
        hour = (hour < 10 ? "0" : "") + String(hour);
        minute = (minute < 10 ? "0" : "") + String(minute);
        second = (second < 10 ? "0" : "") + String(second);
        milli = (milli < 10 ? "00" : (milli < 100 ? "0" : "")) + String(milli);
        return year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second + "." + milli;
    };
    return "0000-00-00 00:00:00.000";
};

// 显示吐司提示。
// _html：要显示的内容。
// _duration：持续时间，单位毫秒，不指定时默认 2000 毫秒。
window.toast = function (_html, _duration) {
    if (document.getElementsByClassName) {
        var shown = document.getElementsByClassName('elivo.toast')
        for (var i = 0; i < shown.length; i++) {
            try {
                document.body.removeChild(shown[i])
            } catch (error) { }
        }
    }
    if (typeof _html !== 'string' || _html === '') return

    var box = document.createElement('span')
    var area = document.createElement('div')
    box.style.backdropFilter = 'blur(5px)'
    box.style.backgroundColor = '#3f3f3f'
    box.style.borderRadius = '5px'
    box.style.boxShadow = '0px 10px 40px rgba(0,0,0, 0.3)'
    box.style.color = 'white'
    box.style.display = 'inline-block'
    box.style.fontFamily = "consolas, 'microsoft yahei', 'pingfang sc', sans-serif"
    box.style.fontSize = '14px'
    box.style.lineHeight = '28px'
    box.style.paddingBottom = '10px'
    box.style.paddingLeft = '20px'
    box.style.paddingRight = '20px'
    box.style.paddingTop = '10px'
    box.style.textShadow = '0px 0px 10px rgba(0,0,0, 0.5)'
    box.innerHTML = _html
    area.className = 'elivo.toast'
    area.style.bottom = '20%'
    area.style.display = 'block'
    area.style.fontSize = '0px'
    area.style.left = '10%'
    area.style.opacity = '0'
    area.style.position = 'fixed'
    area.style.right = '10%'
    area.style.textAlign = 'center'
    area.style.transition = 'all 0.15s linear'
    area.style.zIndex = '200000000'
    area.appendChild(box)
    document.body.appendChild(area)
    setTimeout(function () {
        area.style.opacity = 1
        var delay = 150 + parseInt((typeof _duration === 'number') ? _duration : 2000)
        setTimeout(function () {
            area.style.opacity = 0
            setTimeout(function () {
                try {
                    document.body.removeChild(area)
                } catch (error) { }
            }, 300)
        }, delay)
    }, 1)
    return { area: area, box: box }
}

// 获取当前时钟的易读格式。
window.clock = function (date) {
    if (!date || !(date instanceof Date)) date = new Date()
    var year = date.getFullYear()
    var month = date.getMonth() + 1
    var day = date.getDate()
    var hour = date.getHours()
    var minute = date.getMinutes()
    var second = date.getSeconds()
    var milli = date.getMilliseconds()
    year = (year < 10 ? '000' : (year < 100 ? '00' : (year < 1000 ? '0' : ''))) + String(year)
    month = (month < 10 ? '0' : '') + String(month)
    day = (day < 10 ? '0' : '') + String(day)
    hour = (hour < 10 ? '0' : '') + String(hour)
    minute = (minute < 10 ? '0' : '') + String(minute)
    second = (second < 10 ? '0' : '') + String(second)
    milli = (milli < 10 ? '00' : (milli < 100 ? '0' : '')) + String(milli)
    return year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second + '.' + milli
}

// 闪烁颜色。
window.flickColor = function (color, duration) {
    var mask = document.getElementById('flickColorElement')
    if (mask && mask.parentElement) mask.parentElement.removeChild(mask)
    if (!duration) return
    mask = document.createElement('div')
    mask.id = 'flickColorElement'
    mask.style.position = 'fixed'
    mask.style.zIndex = '10000'
    mask.style.top = mask.style.right = mask.style.bottom = mask.style.left = '0px'
    mask.style.backgroundColor = color
    mask.style.opacity = '0.3'
    document.body.appendChild(mask)
    setTimeout(function () {
        mask.style.transition = 'opacity ' + (duration / 1000.0).toFixed(2) + 's linear'
        mask.style.opacity = '0'
    }, 200)
    if (duration > 0) {
        setTimeout(function () {
            if (mask && mask.parentElement) mask.parentElement.removeChild(mask)
        }, 200 + duration)
    }
    mask.style.pointerEvents = 'none'
}

// 闪烁绿屏。
window.flickGreen = function (ms) {
    if (!ms) ms = 800
    window.flickColor('limegreen', ms)
}

// 闪烁红屏。
window.flickRed = function (ms) {
    if (!ms) ms = 4000
    window.flickColor('crimson', ms)
}

// 修正数字，保留指定的小数位数。
window.trimNumber = function (number, digits) {
    var n = number
    if (typeof n === 'string') n = parseFloat(n)
    if (typeof n !== 'number') return n
    if (typeof digits !== 'number') digits = 4
    else if (digits < 1) return Math.round(n)
    var p = Math.pow(10, digits)
    n = Math.round(n * p) / p
    var t = n.toFixed(digits)
    n = parseFloat(t)
    return n
}

function ajaxGet(_url, _succeed, _failed, _timeout, _blob) {
    var _log_enabled = false;
    var same = true;
    if (_url.length > 2 && _url.substring(0, 2) == "//") same = false;
    if (_url.length > 5 && _url.substring(0, 5) == "http:") same = false;
    if (_url.length > 6 && _url.substring(0, 6) == "https:") same = false;
    var xhr = (window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
    xhr.open('GET', _url, true);
    if (typeof _timeout === 'number') xhr.timeout = _timeout;
    if (same) {
        var token = getAuthToken();
        if (token) {
            xhr.setRequestHeader('access-token', token);
            xhr.setRequestHeader('authorization', token);
        }
        var languageCodes = getLanguageCodes();
        if (languageCodes) {
            xhr.setRequestHeader('Language-Codes', languageCodes);
        }
    }
    if (_blob) xhr.responseType = 'arraybuffer';
    xhr.onreadystatechange = function () {
        if (xhr.readyState == 4) {
            if ((xhr.status == 200) || (xhr.status == 304)) {
                if (_blob) {
                    var blob = new Blob([xhr.response]);
                    if (typeof _succeed === 'function') _succeed(blob);
                    return;
                }
                var text = xhr.responseText;
                var response = null;
                try {
                    response = JSON.parse(text)
                } catch (ex) {
                    response = text
                }
                if (_log_enabled || typeof _succeed !== 'function') {
                }
                if (typeof _succeed === 'function') _succeed(response)
            } else {
                var json = { status: 'error', message: 'Invalid Status ' + String(xhr.status) }
                if (typeof _failed === 'function') _failed(json)
            }
        }
    }
    try {
        xhr.send()
    } catch (ex) {
        var json = { status: 'error', message: ex.message }
        if (typeof _failed === 'function') _failed(json)
    }
    return xhr
}

function ajaxPost(_url, _data, _succeed, _failed, _timeout, _blob) {
    var _log_enabled = false
    var data = null
    var isObject = false
    switch (typeof _data) {
        case 'undefined':
        case 'function':
        case 'symbol':
            break
        case 'string':
            data = _data
            break
        case 'boolean':
        case 'number':
        case 'bigint':
            data = String(_data)
            break
        case 'object':
            if (_data) data = JSON.stringify(_data)
            isObject = true
            break
    };
    var same = true;
    if (_url.length > 2 && _url.substring(0, 2) == "//") same = false;
    if (_url.length > 5 && _url.substring(0, 5) == "http:") same = false;
    if (_url.length > 6 && _url.substring(0, 6) == "https:") same = false;

    var xhr = (window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP')
    xhr.open('POST', _url, true)
    if (typeof _timeout === 'number') xhr.timeout = _timeout
    xhr.setRequestHeader('Content-Type', (isObject && same) ? 'application/json' : 'text/plain')
    if (same) {
        var token = getAuthToken();
        if (token) {
            xhr.setRequestHeader('access-token', token);
            xhr.setRequestHeader('authorization', token);
        }
        var languageCodes = getLanguageCodes();
        if (languageCodes) {
            xhr.setRequestHeader('Language-Codes', languageCodes);
        }
    }
    if (_blob) xhr.responseType = 'arraybuffer';
    xhr.onreadystatechange = function () {
        if (xhr.readyState == 4) {
            if ((xhr.status == 200) || (xhr.status == 304)) {
                if (_blob) {
                    var blob = new Blob([xhr.response]);
                    if (typeof _succeed === 'function') _succeed(blob);
                    return;
                }
                var text = xhr.responseText;
                var response = null;
                try {
                    response = JSON.parse(text)
                } catch (ex) {
                    response = text
                }
                if (_log_enabled || typeof _succeed !== 'function') {
                }
                if (typeof _succeed === 'function') _succeed(response)
            } else {
                var json = { status: 'error', message: 'Invalid Status ' + String(xhr.status) }
                if (typeof _failed === 'function') _failed(json)
            }
        }
    }
    try {
        xhr.send(data)
    } catch (ex) {
        var json = { status: 'error', message: ex.message }
        if (typeof _failed === 'function') _failed(json)
    }
    return xhr
};

// 使用 AJAX 上传文件。
window.ajaxUpload = function (url, succeed, failed, accept, before, after, progress, _blob) {
    if (typeof succeed != "function") succeed = function () { };
    if (typeof failed != "function") failed = function (msg) { };
    if (typeof before != "function") before = function (file) { };
    if (typeof after != "function") after = function (file) { };
    if (typeof progress != "function") progress = function (p) { };
    if (!url) return failed("未指定 URL。");

    var input = document.createElement("input");
    input.type = "file";
    if (accept && typeof accept == "string") input.accept = accept;
    input.click();
    input.onchange = function (evt) {
        if (evt.target.files.length < 1) return failed("没有选择文件。");

        if (typeof url == "function") url = url(evt.target.files[0]);
        if (typeof url != "string") return failed("未获取 URL。");

        var file = evt.target.files[0];
        if (typeof before == "function") {
            var value = before(file);
            if (typeof value == "boolean" && value == false) return;
            if (typeof value == "number" && value == 0) return;
        }

        var reader = new FileReader();
        reader.file = file;
        reader.onabort = function (e) { };
        reader.onerror = function (e) { };
        reader.onloadstart = function (e) { };
        reader.onprogress = function (e) { };
        reader.onload = function (e) { };
        reader.onloadend = function (e) {
            var xhr = new XMLHttpRequest();
            xhr.open("post", url);
            xhr.setRequestHeader("Content-Type", "application/octet-stream");
            var token = getAuthToken();
            if (token) {
                xhr.setRequestHeader('access-token', token);
                xhr.setRequestHeader('authorization', token);
            }
            var languageCodes = getLanguageCodes();
            if (languageCodes) {
                xhr.setRequestHeader('Language-Codes', languageCodes);
            }
            if (_blob) xhr.responseType = 'arraybuffer';
            xhr.onreadystatechange = function (e) {
                if (xhr.readyState == 4) {
                    after(file);
                    if (xhr.status == 200) {
                        if (_blob) {
                            var blob = new Blob([xhr.response]);
                            if (typeof _succeed === 'function') _succeed(blob);
                            return;
                        }
                        var response = xhr.responseText;
                        try { response = JSON.parse(response); } catch (err) { }
                        succeed(response);
                    } else failed("Status=" + String(xhr.status));
                }
            };
            xhr.onprogress = function (e) {
                if (e.lengthComputable) {
                    var p = { name: reader.file.name, total: e.total, loaded: e.loaded };
                    progress(p);
                }
            };
            xhr.send(reader.result);
        };
        reader.readAsArrayBuffer(file);
    };
};

// 对数组排序。
window.isArray = function (value) {
    if (typeof Array.isArray === 'function') {
        return Array.isArray(value)
    } else {
        return Object.prototype.toString.call(value) === '[object Array]'
    };
}

// 对数组排序。
window.sortArray = function (array, comparison, property) {
    function swap(array, i, j) {
        var temp = array[i]
        array[i] = array[j]
        array[j] = temp
    };
    function compare(a, b, p) {
        return (p ? a[p] : a) > (right = p ? b[p] : b)
    };
    if (!isArray(array)) return array
    switch (typeof comparison) {
        case 'function':
            break
        case 'number':
            if (comparison == 1) {
                comparison = function (a, b) {
                    return compare(a, b, property)
                }
            } else if (comparison == -1) {
                comparison = function (a, b) {
                    return compare(b, a, property)
                }
            };
            break
        case 'string':
            if (comparison == 'asc') {
                comparison = function (a, b) {
                    return compare(a, b, property)
                }
            } else if (comparison == 'desc') {
                comparison = function (a, b) {
                    return compare(b, a, property)
                }
            };
            break
    };
    if (!comparison || typeof comparison !== 'function') return array
    for (var i = 0; i < array.length - 1; i++) {
        for (var j = i + 1; j < array.length; j++) {
            var compared = comparison(array[i], array[j])
            if (compared) swap(array, i, j)
        };
    };
    return array
};

window.saveAs = function (content, name, bom) {
    if (!content) return;

    var blob;
    if (content instanceof Blob) {
        var blob = content;
        if (bom && /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
            blob = new Blob([String.fromCharCode(0xFEFF), blob], { type: blob.type });
        };
    } else {
        blob = new Blob([content], { type: 'application/octet-stream' });
    };

    var url = (window.URL || window.webkitURL).createObjectURL(blob);
    setTimeout(function () {
        if (typeof url == "string") (window.URL || window.webkitURL).revokeObjectURL(url);
        else file.remove();
    }, 10000);

    // IE 10+
    if (navigator.msSaveOrOpenBlob) return navigator.msSaveOrOpenBlob(blob, name);

    // emulate a tag
    var link = document.createElementNS("http://www.w3.org/1999/xhtml", "a");
    if ("download" in link) {
        link.href = url;
        link.download = name;
        var click = new MouseEvent("click");
        link.dispatchEvent(click);
        return;
    };

    // popup
    if (!window.open(url, "_blank")) window.location.href = url;

}

window.toFloat = function (number) {
    var input = number;
    var hasPercent = false;
    if (typeof input == "string") {
        input = input.replace(/,/gm, "").replace(/\ /gm, "");
        if (input.indexOf("%") > -1) {
            hasPercent = true;
            input = input.replace(/%/gm, "");
        }
    }
    var value = parseFloat(input);
    if (isNaN(value)) return 0.0;
    if (!isFinite(value)) return 0.0;
    if (hasPercent) value = value / 100.0;
    return value;
};

window.toInt = function (number) {
    if (typeof number == "number") {
        if (isNaN(number) || !isFinite(number)) number = 0;
        return number;
    }

    var n = parseInt(String(number));
    if (isNaN(n) || !isFinite(n)) n = 0;
    return n;
};


window.uuid = function (hyphenation) {
    var array = [];
    var hex = "0123456789abcdef";
    for (var i = 0; i < 36; i++) array[i] = hex.substr(Math.floor(Math.random() * 16), 1);
    array[14] = "4";
    array[19] = hex.substr((array[19] & 0x3) | 0x8, 1);
    array[8] = array[13] = array[18] = array[23] = "-";
    var result = array.join("");
    if (hyphenation !== true) result = result.replace(/-/gm, "");
    return result;
};

// 从指定字符串中获取参数。
window.urlQuery = function (selector, decode) {
    var combined = window.location.search;
    if (!combined) return "";
    switch (typeof selector) {
        case "string":
        case "number":
            break;
        default:
            return "";
    };
    var matched = combined.match(new RegExp("[\?\&#][^\?\&]+=[^\?\&]+", "g"));
    var array = [];
    if (matched) {
        for (var i = 0; i < matched.length; i++) {
            var split = matched[i].substring(1).split("=");
            array.push({ key: split[0], value: split[1] });
        };
    };
    var value = "";
    switch (typeof selector) {
        case "string":
            for (var i in array) {
                if (array[i].key == selector) {
                    value = array[i].value;
                    break;
                };
            };
            break;
        case "number":
            var i = parseInt(selector);
            if (i >= 0 && i < array.length) {
                value = array[i].value;
                break;
            };
            break;
    };
    if (decode) value = decodeURIComponent(value);
    return value;
};

// Auth
(function () {
    window.getAuthToken = function () {
        var token = sessionStorage.getItem("access-token");
        if (typeof token != "string") return "";
        if (!token) return "";
        var length = token.length;
        if (length >= 2 && token.substring(0, 1) == '"' && token.substring(length - 1) == '"') token = substring(1, length - 2);
        return token;
    };

    window.setAuthToken = function (token, username) {
        if (token) {
            sessionStorage.setItem("access-token", token);
            sessionStorage.setItem("auth-username", username);
        } else {
            sessionStorage.removeItem("access-token");
            sessionStorage.removeItem("auth-username");
            window.location.href = "/";
        }
    };

    function refreshAuthInfo() {
        if (getAuthToken()) {
            ajaxGet("/api/login/auth-info", (r) => {
                var info = r.data;
                if (info.menuPath) sessionStorage.setItem("auth-menu-path", JSON.stringify(info.menuPath));
                if (info.btnrole) sessionStorage.setItem("auth-btnrole", info.btnrole);
            });
        }
    }

    window.addEventListener("load", refreshAuthInfo);
})();

// IndexedDB
(function () {
    window.IDB = function (dbName, tableName, keyField) {
        var _dbName = dbName;
        var _tableName = tableName;
        var _keyField = "id";

        if (!dbName) throw "参数 dbName 无效。";
        if (!tableName) throw "参数 tableName 无效。";
        if (keyField) _keyField = keyField;

        window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
        window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction;
        window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange

        function onupgradeneeded(event) {
            var db = event.target.result;
            var objectStore;
            if (!db.objectStoreNames.contains(_tableName)) {
                objectStore = db.createObjectStore(_tableName, { keyPath: _keyField });
            }
        }

        function isArray(value) {
            if (typeof Array.isArray === "function") return Array.isArray(value);
            else return Object.prototype.toString.call(value) === "[object Array]";
        }

        function canAsync() {
            var userAgent = (userAgent || navigator.userAgent).toLowerCase();
            var isEdge = /\sedge\//.test(userAgent);
            var version = isEdge ? (userAgent.match(/(?:edge\/)([\d\.]*)/) || [])[1] : (userAgent.match(/.*(?:rv|chrome|webkit|opera|ie)[\/: ](.+?)([ \);]|$)/) || [])[1];
            var webkitVersion = (userAgent.match(/webkit\/(.+?) /) || [])[1];
            var webkit = (!isEdge && /webkit/.test(userAgent)) ? webkitVersion : "";
            var chrome = !isEdge && /chrome/.test(userAgent) ? version : "";
            var version = parseInt(chrome.split(".")[0]);
            if (isNaN(version) || !isFinite(version)) version = 0;
            return version >= 54 ? true : false;
        }

        function idbSet(record, callback) {
            if (!record) {
                console.error("idb", "invalid item", record);
                return;
            }

            var key = record[_keyField];
            if (typeof key != "number" && !key) {
                console.error("idb", "invalid " + String(_keyField), record);
                return;
            }

            var open = indexedDB.open(_dbName, 1);
            open.onerror = function (event) {
                console.error("idb.open", event);
            };
            open.onupgradeneeded = onupgradeneeded;
            open.onsuccess = function (event) {
                var db = event.target.result;
                var transaction = db.transaction(_tableName, "readwrite");
                var store = transaction.objectStore(_tableName);
                var getRequest = store.get(key);
                getRequest.onerror = function (event) {
                    console.error("idb.get", event);
                    transaction.abort();
                    db.close();
                };
                getRequest.onsuccess = function (event) {
                    var value = event.target.result;
                    if (value) {
                        var putRequest = store.put(record);
                        putRequest.onerror = function (event) {
                            console.log("idb.put.error", event);
                            transaction.abort();
                            db.close();
                        };
                        putRequest.onsuccess = function (event) {
                            transaction.commit();
                            db.close();
                            if (typeof callback == "function") callback();
                        };
                    } else {
                        var addRequest = store.add(record);
                        addRequest.onerror = function (event) {
                            console.log("idb.add.error", event);
                            transaction.abort();
                            db.close();
                        };
                        addRequest.onsuccess = function (event) {
                            transaction.commit();
                            db.close();
                            if (typeof callback == "function") callback();
                        };
                    }
                };
            };
        }

        function idbGet(key, callback) {
            var openRequest = indexedDB.open(_dbName, 1);
            openRequest.onerror = function (event) {
                console.error("idb.open", event);
            };
            openRequest.onupgradeneeded = onupgradeneeded;
            openRequest.onsuccess = function (event) {
                var db = event.target.result;
                var transaction = db.transaction(_tableName, "readonly");
                var store = transaction.objectStore(_tableName);
                var getRequest = store.get(key);
                getRequest.onerror = function (event) {
                    console.error("idb.get", event);
                    transaction.abort();
                    db.close();
                };
                getRequest.onsuccess = function (event) {
                    var value = event.target.result;
                    transaction.abort();
                    db.close();
                    if (typeof callback == "function") callback(value);
                };
            };
        }

        function idbAll(callback) {
            var openRequest = indexedDB.open(_dbName, 1);
            openRequest.onerror = function (event) {
                console.error("idb.open", event);
            };
            openRequest.onupgradeneeded = onupgradeneeded;
            openRequest.onsuccess = function (event) {
                var db = event.target.result;
                var array = [];
                var transaction = db.transaction(_tableName, "readonly");
                var store = transaction.objectStore(_tableName);
                var getAllRequest = store.getAll();
                getAllRequest.onsuccess = function (event) {
                    var result = event.target.result;
                    if (!result) result = [];
                    transaction.abort();
                    db.close();
                    if (typeof callback == "function") callback(array);
                };
            };
        }

        function idbDelete(key, callback) {
            if (typeof key != "number" && !key) {
                console.error("idb.delete", "invalid " + String(_keyField), key);
                return;
            }

            var open = indexedDB.open(_dbName, 1);
            open.onerror = function (event) {
                console.error("idb.open", event);
            };
            open.onupgradeneeded = onupgradeneeded;
            open.onsuccess = function (event) {
                var db = event.target.result;
                var transaction = db.transaction(_tableName, "readwrite");
                var store = transaction.objectStore(_tableName);
                var deleteRequest = store.delete(key);
                deleteRequest.onerror = function (event) {
                    console.error("idb.delete", event);
                    transaction.abort();
                    db.close();
                };
                deleteRequest.onsuccess = function (event) {
                    transaction.commit();
                    db.close();
                    if (typeof callback == "function") callback();
                };
            };
        }

        return { add: idbSet, all: idbAll, delete: idbDelete, get: idbGet, set: idbSet, };
    }
})();

// Lang
(function () {

    (function () {
        var localStorageLanguage = localStorage.getItem("language");
        if (!localStorageLanguage) {
            for (var i = 0; i < window.navigator.languages.length; i++) {
                switch (window.navigator.languages[i]) {
                    case "en-US":
                    case "en":
                        localStorage.setItem("language", "en");
                        return;
                    case "zh-CN":
                    case "zh":
                        localStorage.setItem("language", "zh");
                        return;
                }
            }
        }
    })();

    window.getLanguageCodes = function () {
        var value = localStorage.getItem("language");
        if (!value) return value;
        var length = value.length;
        if (length >= 2 && value.substring(0, 1) == '"' && value.substring(length - 1) == '"') value = substring(1, length - 2);
        return value;
    };

    window._strings = [];

    function loadStrings(callback, force) {
        if (!force && window._strings && window._strings.length) {
            if (typeof callback == "function") callback(_strings);
            return;
        }
        ajaxGet("/api/oneLanguage/listStrings", (r) => {
            if (r.data && r.data.length) {
                window._strings = r.data;
                if (typeof callback == "function") callback(window._strings);

                var idb = new IDB("lang", "strings");
                for (var i = 0; i < r.data.length; i++) {
                    if (r.data[i]) idb.set(r.data[i]);
                }
            }
        }, (e) => {
            setTimeout(() => {
                loadStrings(callback, force);
            }, 2000);
        });
    }

    function getStrings(id, chinese, args, skip) {
        var argsArray = [];
        if (typeof skip != "number") skip = 0;
        for (var i = skip; i < args.length; i++)argsArray.push(args[i]);
        args = argsArray;

        // ID 无效
        var array = [];
        if (id < 1) {
            array.push("invalid id");
            return array;
        }

        // 加载字典，获取字典条目
        var record = null;
        if (window._strings != null && window._strings.length > 0) {
            for (var i = 0; i < window._strings.length; i++) {
                if (window._strings[i].id == id) {
                    record = window._strings[i];
                    break;
                }
            }
        }

        // 无字典条目，且未指定中文
        if (!record) {
            if (!chinese || typeof chinese != "string") {
                array.push("untranslated");
                return array;
            }
        }

        // 准备
        var codes = [];
        var split = window.getLanguageCodes().split(",");
        for (var i = 0; i < split.length; i++) {
            var code = split[i].trim();
            if (code) codes.push(code);
        }
        if (!codes.length) codes.push("zh");

        // 获取翻译后的文本
        var values = [];
        if (record) {
            for (var i = 0; i < codes.length; i++) {
                var value = record[codes[i]];
                if (!value) value = "";
                values.push(value);
            }
        } else {
            values.push(chinese);
        }

        // 读取变量的值
        var vars = [];
        for (var i = 0; i < args.length; i++) {
            function getVar(arg, recurve) {
                if (arg == null) return "";
                switch (typeof arg) {
                    case "boolean":
                    case "number":
                        return String(arg);
                    case "string":
                        return arg ? arg : "";
                    case "function":
                        if (recurve > 2) return String(arg);
                        return getVar(arg(), recurve + 1);
                }
                return String(arg);
            }
            vars.push(getVar(args[i]));
        }

        // 将变量加入翻译后的文本
        if (vars.length) {
            for (var j = 0; j < values.length; j++) {
                var value = values[j];
                if (!value) continue;
                var i = 0;
                var e = 0;
                while (e < 10) {
                    var o = "{" + String(i) + "}";
                    var r = false;
                    while (value.indexOf(o) > -1) {
                        value = value.replace(o, i < vars.length ? vars[i] : "");
                        r = true;
                    }
                    e = r ? 0 : (e + 1);
                    i++;
                }
                values[j] = value;
            }
        }

        return values;
    }

    // 获取首选语言的文本。
    function first(id, vars) {
        var strs = getStrings(id, "", arguments, 1);
        return strs[0];
    }

    // 获取第二语言的文本。
    function second(id, vars) {
        var strs = getStrings(id, "", arguments, 1);
        return strs.length > 1 ? strs[1] : "";
    }

    function duo(id, vars) {
        var strs = getStrings(id, "", arguments, 1);
        var text = "<span";
        if (strs.length > 1) {
            text += " title=\"";
            text += strs[1].replace(/\"/gm, "\\\"");
            text += "\"";
        }
        text += ">";
        text += strs[0];
        text += "</span>";
        return text;
    }

    // 获取多语言的文本，每行一种。
    function line(id, vars) {
        var strs = getStrings(id, "", arguments, 1);
        return strs.join("\r\n");
    }
    // 获取多语言的文本， 使用()分隔
    function brackets(id, vars) {
        var strs = getStrings(id, "", arguments, 1);
        if (strs.length > 1) {
            // return strs[0] + '(' + strs[1] + ')';
            return strs.join('(') + ')'
        } else {
            return strs
        }
    }
    //分隔符
    function separator(id, vars) {
        var strs = getStrings(id, "", arguments, 1);
        if (strs.length > 1) {
            return strs.join('|')
        } else {
            return strs
        }
    }
    // 获取多语言的文本，使用 <br> 分隔。
    function br(id, vars) {
        var strs = getStrings(id, "", arguments, 1);
        return strs.join("<br>");
    }

    // 获取多语言的文本，使用 SPAN 标签包含每种语言。
    function span(id, vars) {
        var strs = getStrings(id, "", arguments, 1);
        return "<span>" + strs.join("</span><span>") + "</span>";
    }

    // 获取多语言的文本，使用 DIV 标签包含每种语言。
    function div(id, vars) {
        var strs = getStrings(id, "", arguments, 1);
        return "<div>" + strs.join("</div><div>") + "</div>";
    }

    // 获取首选语言的文本。
    function first2(id, chinese, vars) {
        var strs = getStrings(id, chinese, arguments, 2);
        return strs[0];
    }

    // 获取第二语言的文本。
    function second2(id, chinese, vars) {
        var strs = getStrings(id, chinese, arguments, 2);
        return strs.length > 1 ? strs[1] : "";
    }

    function duo2(id, chinese, vars) {
        var strs = getStrings(id, chinese, arguments, 2);
        var text = "<span";
        if (strs.length > 1) {
            text += " title=\"";
            text += strs[1].replace(/\"/gm, "\\\"");
            text += "\"";
        }
        text += ">";
        text += strs[0];
        text += "</span>";
        return text;
    }

    // 获取多语言的文本，每行一种。
    function line2(id, chinese, vars) {
        var strs = getStrings(id, chinese, arguments, 2);
        return strs.join("\r\n");
    }

    // 获取多语言的文本， 使用()分隔
    function brackets2(id, chinese, vars) {
        var strs = getStrings(id, chinese, arguments, 2);
        if (strs.length > 1) {
            // return strs[0] + '(' + strs[1] + ')';
            return strs.join('(') + ')'
        } else {
            return strs
        }
    }

    // 获取多语言的文本，使用 <br> 分隔。
    function br2(id, chinese, vars) {
        var strs = getStrings(id, chinese, arguments, 2);
        return strs.join("<br>");
    }

    // 获取多语言的文本，使用 SPAN 标签包含每种语言。
    function span2(id, chinese, vars) {
        var strs = getStrings(id, chinese, arguments, 2);
        return "<span>" + strs.join("</span><span>") + "</span>";
    }

    // 获取多语言的文本，使用 DIV 标签包含每种语言。
    function div2(id, chinese, vars) {
        var strs = getStrings(id, chinese, arguments, 2);
        return "<div>" + strs.join("</div><div>") + "</div>";
    }

    // 根据id，默认中文，获取 中文|English 样式文字
    function separator2(id, chinese, vars) {
        var strs = getStrings(id, chinese, arguments, 2);
        if (strs.length > 1) {
            return strs.join('|')
        } else {
            return strs
        }
    }



    window.lang = {
        importDictXlsx: function () {
            ajaxUpload("/api/oneLanguage/importDictXlsx", function (r) {
                console.log("importDictXlsx", "succeed", r);
            }, function (e) {
                console.log("importDictXlsx", "failed", e);
            });
        },

        loadStrings: loadStrings,
        strings: function () { return window._strings; },
        getLanguageCodes: getLanguageCodes,

        first: first,
        second: second,
        duo: duo,
        line: line,
        br: br,
        brackets: brackets,
        span: span,
        div: div,
        separator: separator,

        first2: first2,
        second2: second2,
        duo2: duo2,
        line2: line2,
        br2: br2,
        brackets2: brackets2,
        span2: span2,
        div2: div2,
        separator2: separator2
    };

    // 加载缓存的语言字典。
    new IDB("lang", "strings").all(records => {
        if (records && records.length) window._strings = records;
    });

})();

window.speak = function (text) {
    var rate = parseFloat(localStorage.getItem('readSpeed'));
    if (window.speechSynthesis && window.SpeechSynthesisUtterance) {
        if (!isNaN(rate)) {
            if (rate < 0.1) rate = 0.1;
            if (rate > 10) rate = 10;
        }

        var utterance = new SpeechSynthesisUtterance();
        utterance.text = text;
        utterance.lang = "zh-CN";
        if (rate) utterance.rate = rate;
        window.speechSynthesis.speak(utterance);
    } else if (typeof mesKeeper == "object") {
        if (isNaN(rate)) rate = 2;
        if (rate < -10) rate = -10;
        if (rate > 10) rate = 10;

        mesKeeper.post("system", "speak", { text: text, rate: rate })
    }
};

// program
(function () {
    window.sysvars = {};
    function loadProgram() {
        window.ajaxGet("/api/program", (r) => {
            if (r && r.sysvars) {
                window.sysvars = r.sysvars;
                window.profile = r.sysvars.program;
                return;
            }
            setTimeout(loadProgram, 2000);
        }, (e) => {
            setTimeout(loadProgram, 5000);
        });
    };
    loadProgram();

    window.getProfile = function (callback) {
        if (typeof callback != "function") return;
        if (window.sysvars) {
            callback(window.sysvars.profile);
            return;
        }
        setTimeout(() => window.getProfile(callback), 100);
    };
})();


(function () {
    var origingindex = "";

    function checkIndex() {
        ajaxGet("/index.html", (r) => {
            setTimeout(() => {
                checkIndex();
            }, 20000);
            if (!origingindex) {
                origingindex = r;
                return;
            }
            if (r !== origingindex) {
                var lan = localStorage.getItem("language");
                var llan = lan ? lan.split(",")[0] : "zh";
                if (llan === "zh") {
                    toast("页面存在新版本，刷新后生效。");
                } else {
                    toast("There is a new version on the page, which will take effect after refreshing.");
                }

            }
        })
    }

    window.addEventListener("load", () => {
        checkIndex();
    });
})();