<template>
<div class="root">
    <textarea class="text-input input-area" @input="onTextInput"
        v-model="input" :placeholder="translations.get('DirectInput_InputPlaceholder')" />

    <div class="text-container">
        <span v-if="errorState" class="material-icons mdi-m error-text">error</span>
        <span v-if="errorState" class="error-text">Something went wrong! Please try modifying your input text.</span>

        <span class="preserveWhitespace" v-html="formattedRestored" />
    </div>

    <div class="flex">
        <input type="checkbox" id="i-preserve-existing-macrons" v-model="preserveExistingMacrons" @input="startMacronisationWait" />
        <label for="i-preserve-existing-macrons">{{ translations.get('DirectInput_PreserveExistingMacrons') }}</label>
    </div>

    <div class="flex">
        <input type="checkbox" id="i-show-macronised-words" v-model="showMacronisedWords" :disabled="restored.length === 0" />
        <label for="i-show-macronised-words">{{ translations.get('DirectInput_ShowMacronisedWords') }}</label>
    </div>

    <div class="flex right-column">
        <input type="checkbox" id="i-show-macronised-words" v-model="normaliseLinebreaks" :disabled="restored.length === 0" />
        <label for="i-show-macronised-words">{{ translations.get('DirectInput_NormaliseLinebreaks') }}</label>
    </div>

    <button class="btn-primary right-column" :disabled="!canDownload" @click="downloadAsText">
        {{ translations.get('DirectInput_Download') }}
    </button>
</div>
</template>

<style scoped lang="scss">
.root {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1em;
}

.preserveWhitespace {
    white-space: pre-line;
}

.input-area {
    resize: vertical;
    min-height: 4em;
}

.flex {
    display: flex;
    align-items: center;
    gap: 0.5em;
}

.right-column {
    grid-column: 2;
}

.highlight {
    background-color: var(--highlighted-word-bg);
}

.error-text {
    color: rgb(185, 3, 3);
}
</style>

<script>
import { mapState } from "vuex";
import { saveAs } from "file-saver"
import { log } from "../js/Util"
import MacronRestorationModule from "../js/OcrService"

const macroniser = new MacronRestorationModule();

export default {
    name: "DirectInput",
    data() {
        return {
            preserveExistingMacrons: true,
            showMacronisedWords: false,
            macroniseWaitTimeout: null,
            waitingToMacronise: false,
            errorState: false,
            normaliseLinebreaks: false
        }
    },
    computed: {
        canDownload() {
            return this.restored.length > 0 && !this.waitingToMacronise;
        },
        input: {
            get() {
                return this.$store.state.directInput;
            },
            set(newValue) {
                this.$store.commit("setDirectInput", newValue);
                this.startMacronisationWait();
            }
        },
        restored: {
            get() {
                return this.$store.state.directOutput;
            },
            set(newValue) {
                this.$store.commit("setDirectOutput", newValue);
            }
        },
        formattedRestored() {
            let restored = "";

            for (const word of this.restored) {
                if (word.w) {
                    if (word[0] !== "-") {
                        restored += " ";
                    }

                    if (word.macronised && this.showMacronisedWords) {
                        restored += `<mark class="highlight">${word.w}</mark>`;
                    }
                    else {
                        restored += word.w;
                    }
                }

                if (word.linebreak) {
                    restored += this.normaliseLinebreak(word.linebreak);
                }
            }

            return restored;
        },
        ...mapState({
            translations: state => state.translations
        })
    },
    methods: {
        /**
         * Handles input on an element, and grows its height so that the text is always visible.
         * @param {InputEvent} event The input event.
         */
        onTextInput(event) {
            event.target.height = "auto";
            event.target.height = event.target.scrollHeight;
        },
        startMacronisationWait() {
            if (this.input === null || this.input === "") {
                return;
            }

            this.waitingToMacronise = true;

            if (this.macroniseWaitTimeout !== null) {
                clearTimeout(this.macroniseWaitTimeout);
            }

            this.macroniseWaitTimeout = setTimeout(this.updateMacronisedText, 1000);
        },
        async updateMacronisedText() {
            this.errorState = false;

            try {
                this.restored = await macroniser.directMacronisation(this.input, this.preserveExistingMacrons);
                this.waitingToMacronise = false;
            }
            catch (ex) {
                this.errorState = true;
                log(ex, "warn");
            }
        },
        downloadAsText() {
            const blob = new Blob([ this.restored ], { type: "text/plain;charset=utf-8" });
            saveAs(blob, "restored.txt");
        },
        /**
         * Normalises a linebreak.
         * @param {String} linebreak The linebreak sequence.
         */
        normaliseLinebreak(linebreak) {
            if (!this.normaliseLinebreaks) {
                return linebreak;
            }

            const rCount = linebreak.split("\r").length - 1;
            const nCount = linebreak.split("\n").length - 1;

            if (rCount > 1) {
                if (nCount > 0) {
                    return "\r\n\r\n";
                }

                return "\r\r";
            }
            else if (nCount > 1) {
                return "\n\n";
            }

            return linebreak;
        }
    }
}
</script>
