// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0
// API host/endpoint
var BaseUrl = window.location.protocol + "//" + window.location.host;
var htmlRegex = /<(.*)>.*?|<(.*)\/>/;
document.addEventListener('DOMContentLoaded', function(){
    var sidenavElems = document.querySelectorAll('.sidenav');
    var sidenavInstances = M.Sidenav.init(sidenavElems);

    var app = new Vue({
        el: '#app',
        delimiters: ['[[',']]'],
        data: {
            BaseUrl: BaseUrl,
            loading: true,
            error: "",
            langs: [],
            settings: {},
            sourceLang: "",
            targetLang: "",

            loadingTranslation: false,
            inputText: "",
            inputTextareaHeight: 250,
            savedTanslatedText: "",
            translatedText: "",
            output: "",
            charactersLimit: -1,

            copyTextLabel: "Copy text",

            suggestions: false,
            isSuggesting: false,

            supportedFilesFormat : [],
            translationType: "text",
            inputFile: false,
            loadingFileTranslation: false,
            translatedFileUrl: false,
            filesTranslation: true,
            frontendTimeout: 500
        },
        mounted: function() {
            const self = this;

            const settingsRequest = new XMLHttpRequest();
            settingsRequest.open("GET", BaseUrl + "/frontend/settings", true);

            const langsRequest = new XMLHttpRequest();
            langsRequest.open("GET", BaseUrl + "/languages", true);

            settingsRequest.onload = function() {
                if (this.status >= 200 && this.status < 400) {
                    self.settings = JSON.parse(this.response);
                    self.sourceLang = self.settings.language.source.code;
                    self.targetLang = self.settings.language.target.code;
                    self.charactersLimit = self.settings.charLimit;
                    self.suggestions = self.settings.suggestions;
                    self.supportedFilesFormat = self.settings.supportedFilesFormat;
                    self.filesTranslation = self.settings.filesTranslation;
                    self.frontendTimeout = self.settings.frontendTimeout;

                    if (langsRequest.response) {
                        handleLangsResponse(self, langsRequest);
                    } else {
                        langsRequest.onload = function() {
                            handleLangsResponse(self, this);
                        }
                    }
                } else {
                    self.error = "Cannot load /frontend/settings";
                    self.loading = false;
                }
            };

            settingsRequest.onerror = function() {
                self.error = "Error while calling /frontend/settings";
                self.loading = false;
            };

            langsRequest.onerror = function() {
                self.error = "Error while calling /languages";
                self.loading = false;
            };

            settingsRequest.send();
            langsRequest.send();
        },
        updated: function(){
            M.FormSelect.init(this.$refs.sourceLangDropdown);
            M.FormSelect.init(this.$refs.targetLangDropdown);

            if (this.$refs.inputTextarea){
                if (this.inputText === ""){
                    this.$refs.inputTextarea.style.height = this.inputTextareaHeight + "px";
                    this.$refs.translatedTextarea.style.height = this.inputTextareaHeight + "px";
                } else{
                    this.$refs.inputTextarea.style.height = this.$refs.translatedTextarea.style.height = "1px";
                    this.$refs.inputTextarea.style.height = Math.max(this.inputTextareaHeight, this.$refs.inputTextarea.scrollHeight + 32) + "px";
                    this.$refs.translatedTextarea.style.height = Math.max(this.inputTextareaHeight, this.$refs.translatedTextarea.scrollHeight + 32) + "px";
                }
            }

            if (this.charactersLimit !== -1 && this.inputText.length >= this.charactersLimit){
                this.inputText = this.inputText.substring(0, this.charactersLimit);
            }

            // Update "selected" attribute (to overcome a vue.js limitation)
            // but properly display checkmarks on supported browsers.
            // Also change the <select> width value depending on the <option> length
            if (this.$refs.sourceLangDropdown) {
                updateSelectedAttribute(this.$refs.sourceLangDropdown, this.sourceLang);
            }

            if (this.$refs.targetLangDropdown) {
                updateSelectedAttribute(this.$refs.targetLangDropdown, this.targetLang);
            }
        },
        computed: {
            requestCode: function(){
                return ['const res = await fetch("' + this.BaseUrl + '/translate", {',
                    '	method: "POST",',
                    '	body: JSON.stringify({',
                    '		q: ' + this.$options.filters.escape(this.inputText) + ',',
                    '		source: ' + this.$options.filters.escape(this.sourceLang) + ',',
                    '		target: ' + this.$options.filters.escape(this.targetLang) + ',',
                    '		format: "' + (this.isHtml ? "html" : "text") + '"',
                    '	}),',
                    '	headers: { "Content-Type": "application/json" }',
                    '});',
                    '',
                    'console.log(await res.json());'].join("\n");
            },
            supportedFilesFormatFormatted: function() {
                return this.supportedFilesFormat.join(', ');
            },
            isHtml: function(){
                return htmlRegex.test(this.inputText);
            },
            canSendSuggestion() {
                return this.translatedText.trim() !== "" && this.translatedText !== this.savedTanslatedText;
            }
        },
        filters: {
            escape: function(v){
                return JSON.stringify(v);
            },
            highlight: function(v){
                return Prism.highlight(v, Prism.languages.javascript, 'javascript');
            }
        },
        methods: {
            abortPreviousTransRequest: function(){
                if (this.transRequest){
                    this.transRequest.abort();
                    this.transRequest = null;
                }
            },
            swapLangs: function(e){
                this.closeSuggestTranslation(e)

                var t = this.sourceLang;
                this.sourceLang = this.targetLang;
                this.targetLang = t;
                this.inputText = this.translatedText;
                this.translatedText = "";
                this.handleInput();
            },
            dismissError: function(){
                this.error = '';
            },
            getQueryParam: function (key) {
                const params = new URLSearchParams(window.location.search);
                return params.get(key)
            },
            updateQueryParam: function (key, value) {
                let searchParams = new URLSearchParams(window.location.search)
                searchParams.set(key, value);
                let newRelativePathQuery = window.location.pathname + '?' + searchParams.toString();
                history.pushState(null, '', newRelativePathQuery);
            },
            handleInput: function(e){
                this.closeSuggestTranslation(e)

                this.updateQueryParam('source', this.sourceLang)
                this.updateQueryParam('target', this.targetLang)
                this.updateQueryParam('q', encodeURI(this.inputText))

                if (this.timeout) clearTimeout(this.timeout);
                this.timeout = null;

                if (this.inputText === ""){
                    this.translatedText = "";
                    this.output = "";
                    this.abortPreviousTransRequest();
                    this.loadingTranslation = false;
                    return;
                }

                var self = this;

                self.loadingTranslation = true;
                this.timeout = setTimeout(function(){
                    self.abortPreviousTransRequest();

                    var request = new XMLHttpRequest();
                    self.transRequest = request;

                    var data = new FormData();
                    data.append("q", self.inputText);
                    data.append("source", self.sourceLang);
                    data.append("target", self.targetLang);
                    data.append("format", self.isHtml ? "html" : "text");
                    data.append("api_key", localStorage.getItem("api_key") || "");

                    request.open('POST', BaseUrl + '/translate', true);

                    request.onload = function() {
                        try{
                            var res = JSON.parse(this.response);
                            // Success!
                            if (res.translatedText !== undefined){
                                self.translatedText = res.translatedText;
                                self.loadingTranslation = false;
                                self.output = JSON.stringify(res, null, 4);
                            } else{
                                throw new Error(res.error || "Unknown error");
                            }
                        } catch (e) {
                            self.error = e.message;
                            self.loadingTranslation = false;
                        }
                    };

                    request.onerror = function() {
                        self.error = "Error while calling /translate";
                        self.loadingTranslation = false;
                    };

                    request.send(data);
                }, self.frontendTimeout);
            },
            copyText: function(e){
                e.preventDefault();
                this.$refs.translatedTextarea.select();
                this.$refs.translatedTextarea.setSelectionRange(0, 9999999); /* For mobile devices */
                document.execCommand("copy");

                if (this.copyTextLabel === "Copy text"){
                    this.copyTextLabel = "Copied";
                    var self = this;
                    setTimeout(function(){
                        self.copyTextLabel = "Copy text";
                    }, 1500);
                }
            },
            suggestTranslation: function(e) {
                e.preventDefault();
                this.savedTanslatedText = this.translatedText

                this.isSuggesting = true;
            },
            closeSuggestTranslation: function(e) {
                this.translatedText = this.savedTanslatedText

                e.preventDefault();

                this.isSuggesting = false;
            },
            sendSuggestion: function(e) {
                e.preventDefault();

                var self = this;

                var request = new XMLHttpRequest();
                self.transRequest = request;

                var data = new FormData();
                data.append("q", self.inputText);
                data.append("s", self.translatedText);
                data.append("source", self.sourceLang);
                data.append("target", self.targetLang);
                data.append("api_key", localStorage.getItem("api_key") || "");

                request.open('POST', BaseUrl + '/suggest', true);
                request.onload = function() {
                    try{
                        var res = JSON.parse(this.response);
                        if (res.success){
                            M.toast({html: 'Thanks for your correction.'})
                            self.closeSuggestTranslation(e)
                        }else{
                            throw new Error(res.error || "Unknown error");
                        }
                    }catch(e){
                        self.error = e.message;
                        self.closeSuggestTranslation(e)
                    }
                };

                request.onerror = function() {
                    self.error = "Error while calling /suggest";
                    self.loadingTranslation = false;
                };

                request.send(data);
            },
            deleteText: function(e){
                e.preventDefault();
                this.inputText = this.translatedText = this.output = "";
                this.$refs.inputTextarea.focus();
            },
            switchType: function(type) {
                this.translationType = type;
            },
            handleInputFile: function(e) {
                this.inputFile = e.target.files[0];
            },
            removeFile: function(e) {
              e.preventDefault()
              this.inputFile = false;
              this.translatedFileUrl = false;
              this.loadingFileTranslation = false;
            },
            translateFile: function(e) {
                e.preventDefault();

                let self = this;
                let translateFileRequest = new XMLHttpRequest();

                translateFileRequest.open("POST", BaseUrl + "/translate_file", true);

                let data = new FormData();
                data.append("file", this.inputFile);
                data.append("source", this.sourceLang);
                data.append("target", this.targetLang);
                data.append("api_key", localStorage.getItem("api_key") || "");

                this.loadingFileTranslation = true

                translateFileRequest.onload = function()  {
                    if (translateFileRequest.readyState === 4 && translateFileRequest.status === 200) {
                        try{
                            self.loadingFileTranslation = false;

                            let res = JSON.parse(this.response);
                            if (res.translatedFileUrl){
                                self.translatedFileUrl = res.translatedFileUrl;

                                let link = document.createElement("a");
                                link.target = "_blank";
                                link.href = self.translatedFileUrl;
                                link.click();
                            }else{
                                throw new Error(res.error || "Unknown error");
                            }

                        }catch(e){
                            self.error = e.message;
                            self.loadingFileTranslation = false;
                            self.inputFile = false;
                        }
                    }else{
                        let res = JSON.parse(this.response);
                        self.error = res.error || "Unknown error";
                        self.loadingFileTranslation = false;
                        self.inputFile = false;
                    }
                }

                translateFileRequest.onerror = function() {
                    self.error = "Error while calling /translate_file";
                    self.loadingFileTranslation = false;
                    self.inputFile = false;
                };

                translateFileRequest.send(data);
            }
        }
    });
});

/**
 * @param {object} self
 * @param {XMLHttpRequest} response
 */
function handleLangsResponse(self, response) {
    if (response.status >= 200 && response.status < 400) {
        self.langs = JSON.parse(response.response);

        if (self.langs.length === 0){
            self.loading = false;
            self.error = "No languages available. Did you install the models correctly?"
            return;
        }

        self.langs.push({ name: "Auto Detect (Experimental)", code: "auto" })

        const sourceLanguage = self.langs.find(l => l.code === self.getQueryParam("source"))
        const targetLanguage = self.langs.find(l => l.code === self.getQueryParam("target"))

        if (sourceLanguage) {
            self.sourceLang = sourceLanguage.code
        }

        if (targetLanguage) {
            self.targetLang = targetLanguage.code
        }

        const defaultText = self.getQueryParam("q")

        if (defaultText) {
            self.inputText = decodeURI(defaultText)
        }
    } else {
        self.error = "Cannot load /languages";
    }

    self.loading = false;
}

/**
 * @param {object} langDropdown
 * @param {string} lang
 */
function updateSelectedAttribute(langDropdown, lang) {
    for (const child of langDropdown.children) {
        if (child.value === lang){
            child.setAttribute('selected', '');
            langDropdown.style.width = getTextWidth(child.text) + 24 + 'px';
        } else{
            child.removeAttribute('selected');
        }
    }
}

function getTextWidth(text) {
    var canvas = getTextWidth.canvas || (getTextWidth.canvas = document.createElement("canvas"));
    var ctx = canvas.getContext("2d");
    ctx.font = 'bold 16px sans-serif';
    var textWidth = Math.ceil(ctx.measureText(text).width);
    return textWidth;
}

function setApiKey(){
    var prevKey = localStorage.getItem("api_key") || "";
    var newKey = "";
    newKey = window.prompt("Type in your API Key. If you need an API key, contact the server operator.", prevKey);
    if (newKey === null) newKey = "";

    localStorage.setItem("api_key", newKey);
}

// @license-end