<script setup lang="ts">
import { onMounted, ref } from 'vue';
import { type TabData } from '../common/TabData'
import CodeEditor from '@/components/common/CodeEditorComponent.vue';

const props = defineProps(
    {
        tool: {type: String, required: true},
        xml: {type: [String, Array<TabData>], required: true},
        query: {type: String, required: true},
        activeTabId: {type: Number, required: false}
    }
)

const emit = defineEmits(["update", "update:engine"]);

const result = ref('');

let enginesForCurrentTool = ref(["saxon", "xalan", "libxml"]);

const allVersionsOfXpath = ["2.0", "3.0", "3.1"];
const allVersions = ["1.0", "2.0", "3.0", "3.1"];
let versionsForCurrentEngine = ref([""]);

const engine = ref('');
const version = ref('');

const errorOccurred = ref(false);
const successOccurred = ref(false);

interface XmlFile {
    fileName: string;
    fileData: string;
}

onMounted(() => {
    changeAvailableEngines();
    changeAvailableVersions();
})

function changeAvailableEngines() {
    if (props.tool == "xsd") {
        enginesForCurrentTool.value = ["xalan", "libxml"]
    }
    else if (props.tool == "xquery") {
        enginesForCurrentTool.value = ["saxon"]
    }

    selectDefaultEngine();
}

function changeAvailableVersions() {
    if (props.tool == "xquery")
        versionsForCurrentEngine.value = ["3.1"];
    else if (props.tool == "xslt")
        changeAvailableVersionsOfXSLT();
    else if (props.tool == "xsd")
        versionsForCurrentEngine.value = ["N/A"];

    else if (props.tool == "xpath")
        changeAvailableVersionsOfXPath();

    selectDefaultVersion();
}

function changeAvailableVersionsOfXSLT() {
    if(engine.value == "saxon")
        versionsForCurrentEngine.value = ["3.0"];
    else
        versionsForCurrentEngine.value = ["1.0"];
}

function changeAvailableVersionsOfXPath() {
    if(engine.value == "xalan" || engine.value == "libxml")
        versionsForCurrentEngine.value = ["1.0"];
    else if (engine.value == "saxon")
        versionsForCurrentEngine.value = allVersionsOfXpath;
}

function selectDefaultEngine() {
    engine.value = enginesForCurrentTool.value[0];
}

function selectDefaultVersion() {
    const lastVersion = versionsForCurrentEngine.value.length - 1;
    version.value = versionsForCurrentEngine.value[lastVersion];
    emitVersionChange();
}

function process() {
    let request:Request = prepareRequest();
    fetchRequest(request).then((data) => {
        updateOutputField(data);
    })
}

function updateOutputField(data: any) {
    result.value = data.result
    errorOccurred.value = data.status != "OK"
    successOccurred.value = data.status == "OK"
}

function prepareRequest():Request {
    let request = new Request(prepareURL(), {
        body: selectRequestBodyType(),
        method: "POST"
    });
    return request
    
}

function prepareURL(): string {
    const engineEndpoint = engine.value == "libxml" ? "libxml" : "java";

    let tool = props.tool;
    if (Array.isArray(props.xml) && props.xml.length > 1 && engine.value == "saxon")
        tool = "multiple/xslt";

    return document.location.protocol + "//" + document.location.hostname + "/" + engineEndpoint + "/" + tool;
}

function selectRequestBodyType() : string {
    if (Array.isArray(props.xml) && (engine.value == "xalan" || engine.value == "libxml"))
      return prepareRequestBodySingleXml(props.xml.at(props.activeTabId!)!.data)
    else if (Array.isArray(props.xml) && props.xml.length > 1)
      return prepareRequestBodyMultiXml();
    else if (Array.isArray(props.xml))
      return prepareRequestBodySingleXml(props.xml.at(0)!.data);
    else
      return prepareRequestBodySingleXml(props.xml!);
}

function prepareRequestBodySingleXml(data: string):string {
    let requestBody = JSON.stringify({
        "data": data,
        "processorData": props.query,
        "processor": engine.value,
        "version": version.value
    });
    return requestBody;
}

function prepareRequestBodyMultiXml():string {
    if (!Array.isArray(props.xml))
        return "";

    let xmlFilesArray = convertDataArray(props.xml);

    let requestBody = JSON.stringify({
        "data": xmlFilesArray,
        "processorData": props.query,
        "processor": engine.value,
        "version": version.value
    });
    return requestBody;
}


function convertDataArray(data: Array<TabData>) {
    let result = new Array<XmlFile>;
    data.forEach(element => {
        let fileName = element.name;
        if (!fileName.endsWith(".xml")) {
            fileName += ".xml";
        }

        result.push({
            fileName: fileName,
            fileData: element.data,
        });
    });

    return result;
}

async function fetchRequest(request: Request):Promise<JSON> {
    let responseBody = await fetch(request)
    .then(response => response.json())
    .then((body) => body)
    return responseBody
}



function clear() {
    result.value = ""
    errorOccurred.value = false
    successOccurred.value = false
}

function emitVersionChange() {
    emit("update", version.value);
}

function emitEngineChange() {
  emit("update:engine", engine.value);
}

function isVersionSelectionAvailable() {
    return !(versionsForCurrentEngine.value.length == 1 && versionsForCurrentEngine.value.at(0) == "N/A");
}

function highlightField() {
    if (errorOccurred.value)
        return "text-field-error";

    if (successOccurred.value)
        return "text-field-success";

    return "";
}

function handleChange() {
  changeAvailableVersions();
  emitEngineChange();
}

</script>

<template>
    <div class="flex flex-col flex-none w-full 2xl:w-1/2 h-1/3 2xl:h-full items-center pb-2 xl:pr-2">
        <div class="flex place-content-between w-full items-center pb-2">
            <span class="dark:text-white">Result:</span>
            <div class="flex space-x-2 overflow-x-auto">
                <select v-model="engine" name="engine" @change="handleChange()" class="px-3 rounded-lg border border-slate-400 bg-white dark:text-slate-100 dark:bg-gray-600">
                    <option v-for="engine in enginesForCurrentTool" :value="engine">{{ engine }}</option>
                </select>
                <select v-model="version" v-if="isVersionSelectionAvailable()" name="version" @change="emitVersionChange()" class="px-3 rounded-lg border border-slate-400 bg-white dark:text-slate-100 dark:bg-gray-600">
                    <option v-for="version in versionsForCurrentEngine" :value="version">{{ version }}</option>
                </select>
                <button class="tool-button" @click="clear">Clear</button>    
                <button class="tool-button" @click="process">Process</button>
            </div>
        </div>
        <div class="overflow-auto h-full w-full rounded-2xl" :class="highlightField()">
            <CodeEditor :code="result" :config="{disabled:false,language:tool}"></CodeEditor>
        </div>
        
    </div>
</template>
