

//here are all the functions defined that can be called by the wasm engine

function getlibrarymodel(modelname) {

    if (typeof (window.myguielement) !== "undefined") {
        modelname = decodeURI(window.myguielement.getText(modelname))

        var modelnameparts = modelname.split(".")

        var modelindex = -1
        if (modelnameparts.length == 2) {
            var modellinkparts = modelnameparts[1].split("_")
            var modelid = parseFloat(modellinkparts[0].substring(1))
            var modelnamef = modelnameparts[1].substring(modellinkparts[0].length + 1)
            modelindex = window.myguielement.state.availablemodels.findIndex(model => model.Name == modelnamef && model.Hostname == modelnameparts[0] && model.Id == modelid)
        } else {
            var modellinkparts = modelnameparts[0].split("_")
            var modelid = modellinkparts[0].substring(1)
            var modelnamef = modelnameparts[0].substring(modellinkparts[0].length + 1)
            modelindex = window.myguielement.state.availablemodels.findIndex(model => model.Name == modelnamef && model.Id == modelid)

        }
        if (modelindex != -1) {

            return JSON.stringify(window.myguielement.state.availablemodels[modelindex])
        } else {
            console.log("did not find model " + modelname)
            return
        }
    }

    return
}


function setdatasourceconfiguration(sourceName, columnName, configuration) {

    var success = "false"
    if (typeof (window.myguielement) !== "undefined" && window.myguielement.state.datasources != null) {
        //find the source
        var nameparts = sourceName.split(":")
        var sourceindex = window.myguielement.state.datasources.findIndex(source => source.name == nameparts[0] && source.cube == nameparts[1])

        if (sourceindex == -1) {
            success = "did not find source " + sourceName
            return
        }
        //make sure the columnName exists
        var headers = Object.keys(window.myguielement.state.datasources[sourceindex].data[0])

        //clean up headers
        headers.forEach((h, hi) => {
            var newheader = h.replace(/[.,]/g, '');
            if (newheader != h) {
                window.myguielement.state.datasources[sourceindex].data.forEach((r, ri) => {
                    r[newheader] = r[h]
                    delete r[h]
                })
                headers[hi] = h.replace(/[.,]/g, '');
            }
        })
        var columnindex = -1
        if (columnName == null) {
            columnindex = -1
        } else {
            columnindex = headers.findIndex(h => h == columnName)
        }
        if (columnindex == -1) {
            success = "did not find column " + columnName + " in source " + sourceName
            return
        }
        //make sure the configuration is valid
        if (configuration != "none" && configuration != "new var" && configuration != "new type") {
            //check if object is available in the model
            var object = window.myguielement.getfullvardata(configuration)
            if (object == null) {
                success = "configuration " + configuration + " does not point to an existing model object. Use 'none' to ignore this column, 'new var' to automatically create a new variable or 'new type' to automatically create a new type instead."
                return
            }
        }
        //modify the configuration
        window.myguielement.state.datasources[sourceindex].mapping[headers[columnindex]] = { value: configuration, label: configuration }
        success = "true"

    } else {
        return "gui or datasources not available"
    }
    return success
}


function importdatasource(sourceName) {
    var success = "false"

    if (typeof (window.myguielement) !== "undefined" && window.myguielement.state.datasources != null) {
        //find the source
        var nameparts = sourceName.split(":")
        var sourceindex = window.myguielement.state.datasources.findIndex(source => source.name == nameparts[0] && source.cube == nameparts[1])

        if (sourceindex == -1) {
            success = "did not find source " + sourceName
            return
        }

        //import the source
        var errors = window.myguielement.importData(sourceindex)
        if (errors == null || errors.length == 0) {
            success = "true"
        } else {
            success = "errors encountered while importing datasource " + sourceName + ":\n"
            errors.forEach((e) => {
                success += e + "\n"
            })
        }
        return success
    }

}

function getavailabledatasources() {

    if (typeof (window.myguielement) !== "undefined" && window.myguielement.state.datasources != null) {
        var Datasources = []
        window.myguielement.state.datasources.forEach(datasource => {
            var newsource = {}
            newsource.Name = datasource.name + ":" + datasource.cube

            newsource.Type = datasource.type
            newsource.Configuration = {}
            newsource.ConfigurationOptions = {}

            var headers = Object.keys(datasource.data[0])

            if (datasource.mapping == null) {
                datasource.mapping = {}
            }



            //clean up headers
            headers.forEach((h, hi) => {
                var newheader = h.replace(/[.,]/g, '');

                if (newheader != h) {

                    datasource.data.forEach((r, ri) => {
                        r[newheader] = r[h]
                        delete r[h]
                    })

                    headers[hi] = h.replace(/[.,]/g, '');
                }


            })





            headers.forEach(key => {

                newsource.ConfigurationOptions[key] = []


                window.myguielement.state.varnames.Dispnames.forEach((v, i) => {

                    if (window.myguielement.state.varnames.Type[i] == "var") {

                        //if it is a variable and the unit is a type, there are two options:
                        //1. use the variable as map to determine the import dimension /(e.g. mapping PLANST to Jobclusters)
                        //2. import data to the variable (i.e. import PLANST to the variable) -> this does not work for aggregating imports
                        var varobj = window.myguielement.getfullvardata(window.myguielement.state.varnames.List[i])
                        var vartype = varobj.Unit

                        var vartypeindex = window.myguielement.state.varnames.List.findIndex(l => l == vartype)

                        if (window.myguielement.state.varnames.Type[vartypeindex] == "type") {

                            newsource.ConfigurationOptions[key].push(window.myguielement.state.varnames.List[i])
                        } else {
                            newsource.ConfigurationOptions[key].push(window.myguielement.state.varnames.List[i])
                        }
                    } else {

                        if (window.myguielement.state.varnames.Type[i] == "type") {
                            newsource.ConfigurationOptions[key].push(window.myguielement.state.varnames.List[i])
                        }
                    }

                })
                newsource.ConfigurationOptions[key].push("none")
                newsource.ConfigurationOptions[key].push("new type")
                newsource.ConfigurationOptions[key].push("new var")

                if (typeof (datasource.mapping[key]) == "undefined") {

                    var headerindex = window.myguielement.state.varnames.Dispnames.findIndex((v, i) => v == key)
                    if (headerindex == -1) {
                        if (datasource.data.length == 0) {

                            datasource.mapping[key] = { value: "none", label: "None" }
                        } else {
                            if (isNumber(datasource.data[0][key])) {

                                datasource.mapping[key] = { value: "new var", label: "new var: " + key }
                            } else {

                                datasource.mapping[key] = { value: "new type", label: "new type: " + key }
                            }
                        }
                        datasource.mapping[key] = { value: "none", label: "None" }
                    } else {

                        datasource.mapping[key] = { value: window.myguielement.state.varnames.List[headerindex], label: window.myguielement.state.varnames.Dispnames[headerindex] }
                    }
                }
                newsource.Configuration[key] = datasource.mapping[key].value

            })


            Datasources.push(newsource)
        })

        return JSON.stringify(Datasources)
    } else {
        return JSON.stringify([])
    }

}
function isNumber(value) {
    return !isNaN(Number(value))
}
function getavailablelibraries() {

    if (typeof (window.myguielement) !== "undefined") {
        return JSON.stringify(window.myguielement.state.availablemodels.filter(model => model.IsLibrary == true))
    } else {
        return JSON.stringify([])
    }

}

function updateAiAgent(agent) {

    agent = JSON.parse(agent)

    if (typeof (window.myguielement) !== "undefined") {
        window.myguielement.state.aiAgents[agent.ID] = agent
        window.myguielement.setState({})
    }
}
function getchatcompletionwithtools(agent) {
    if (typeof (window.myguielement) !== "undefined") {


        if (window.myguielement.state.debugmode || typeof (window.myguielement.props.publicAccessToken) == "undefined") {

            window.myguielement.props.fetchInfo("/getChatCompletionWithToolsp", { agent: agent }, gotbackchatcompletionwithtools, window.myguielement.props.getAccessTokenSilently)

        } else {
            const getToken = () => new Promise(resolve => resolve(window.myguielement.props.publicAccessToken));
            window.myguielement.props.fetchInfo("/getChatCompletionWithTools", { agent: agent }, gotbackchatcompletionwithtools, getToken)

        }
    }
}

function gotbackchatcompletionwithtools(data) {

    wasm_returnchatcompletionwithtools(JSON.stringify(data))// eslint-disable-line
}

function redrawcurrentdiagram() {

    if (typeof (window.myguielement) !== "undefined") {
        window.myguielement.setState({
            currentdiagramloaded: false,
        })
    }
}

function triggerfrontendupdate(updatescenario = false) {
   
    if (typeof (window.myguielement) !== "undefined") {
        window.myguielement.saveCurrentDiagram()
        window.myguielement.updateModelState(updatescenario)
    } else {
        console.log("frontend update triggered but gui element not found")
    }
}

function setShownScenarios(scenarioNames) {
    if (typeof (window.myguielement) !== "undefined") {
        var scenarionamelist = JSON.parse(scenarioNames)
        window.myguielement.state.selectedscenarios = scenarionamelist.map((sc) => { return { value: sc, label: sc } })
        scenarionamelist.forEach(sc => {
            window.myguielement.state.scenariodata[sc] = []
            var newscenoutputs = JSON.parse(wasm_get_scenario_outputs(sc))// eslint-disable-line
            if (newscenoutputs.Variables != null && newscenoutputs.Variables.length > 0) {
                window.myguielement.state.scenariodata[sc] = newscenoutputs.Variables
            }
        })
        window.myguielement.updatescenariomenu()
        window.myguielement.setState({ fullvardataupdated: {} })
    }
}

function gotbacksimpletextprompt(data) {
   
    wasm_prompt_results(data.Content, data.Data)// eslint-disable-line
}

function getsimpletextprompt(prompttext, promptid) {
    //gets prompttext from wasm engine, fetches reply from backend engine and returns result
    if (typeof (window.myguielement) !== "undefined") {
        if (window.myguielement.state.debugmode || typeof (window.myguielement.props.publicAccessToken) == "undefined") {
            window.myguielement.props.fetchInfo("/getSimpleTextPromptp", { prompttext: prompttext, promptid: promptid }, gotbacksimpletextprompt, window.myguielement.props.getAccessTokenSilently)
        } else {
            const getToken = () => new Promise(resolve => resolve(window.myguielement.props.publicAccessToken));
            window.myguielement.props.fetchInfo("/getSimpleTextPrompt", { prompttext: prompttext, promptid: promptid }, gotbacksimpletextprompt, getToken)
        }
    }
}


function gotnewsessionreports(data) {
    //console.log("got new session reports")
    //console.log(data)
    if (typeof (window.myguielement) !== "undefined") {
        data.Reports.forEach((d, i) => {
            data.Reports[i].Group = window.myguielement.state.groupname
        })
        window.myguielement.setState({
            reports: data.Reports
        });
        window.myguielement.saveMiniGameStateToTemp(window.myguielement.state)
    }
}


function getsessionreportprompt(prompttext, promptid) {
    //gets prompttext from wasm engine, fetches reply from backend engine and stores result as session report for this session, scenario and variable
    if (typeof (window.myguielement) !== "undefined") {
        //find out if there is actually a running session
        if (window.myguielement.state.currentsession != null) {
            //check if creation of reports is activated for this group/session
            if (window.myguielement.state.currentsession.GenerateReports != null && typeof (window.myguielement.state.currentsession.GenerateReports[window.myguielement.state.groupname]) != "undefined" && window.myguielement.state.currentsession.GenerateReports[window.myguielement.state.groupname] == true) {
                const getToken = () => new Promise(resolve => resolve(window.myguielement.props.publicAccessToken));
                //clarify if a scenarioname must be provided
                var scenname = ""
                //if session is a minigame, then use roundname as scenarioname
                if (window.myguielement.state.currentsession.Type == "minigame") {
                    scenname = window.myguielement.getText("&&&DE&Runde &&&EN&Round ") + (window.myguielement.state.currentsession.MaxNumofTries - window.myguielement.state.remainingnumoftries + 1).toString()
                }

                if (window.myguielement.state.currentsession.Type != "minigame" || window.myguielement.state.currentsession.MaxNumofTries - window.myguielement.state.remainingnumoftries + 1 > 0) {
                    window.myguielement.props.fetchInfo("/getSessionReportPrompt", { prompttext: prompttext, sessionId: window.myguielement.state.currentsession.Id, timeStep: window.myguielement.state.currentsession.MaxNumofTries - window.myguielement.state.remainingnumoftries + 1, scenarioName: scenname, variableName: promptid }, gotnewsessionreports, getToken)
                } else {
                    console.log("not generating report for round 0")
                }
            } else {

                console.log("reports are not activated for the current group in this session")
                return
            }

        } else {
            console.log("cannot get session report prompt, no current session")
        }

    }
}

function savetempmodelfile(modelid, modelinfo) {
    //save model to local storage

    try {
        localStorage.setItem("tempmodelfile_" + modelid, modelinfo)
    } catch (e) {
        console.log("could not save model to local storage")
    }


}