
const view = new lsp.EditorView({
    extensions: lsp.baseExts,
    parent: document.getElementById("editor")
});
let doc = "xquery version '3.1';\n(:~ comment:)\nmodule namespace pdfbox='ns';\n";
var client; // https://codemirror.net/docs/ref/#lsp-client

var workspace = {
    "file:///some/file.xqm": null
};

function $(id) { return document.getElementById(id) };

// Load saved content from localStorage when the page loads
window.addEventListener('load', () => {
   
    const savedText = localStorage.getItem('code');
    if (savedText) doc = savedText;
    let svr = localStorage.getItem('lsp');
    if (!svr) {
        let x = new URL(window.location.href);
        x.protocol = "ws";
        x.pathname = "ws/lsp"
        svr = x.href;
    }
    $("iServer").value = svr;
    formFromStore('fSettings');
    view.setState(lsp.EditorState.create({ doc: doc, extensions: lsp.baseExts }));
    lsp.updateCompartment(objectFromForm('fSettings'))
    connect();
});

// Save content to localStorage when the page is about to unload
window.addEventListener('beforeunload', () => {
    const doc = view.state.doc.toString();
    localStorage.setItem('code', doc);
    localStorage.setItem('lsp', $("iServer").value);
});

$("connect").onclick = e => { e.preventDefault(); connect() };

$("symTrigger").onclick = e => { e.preventDefault(); };
$("symOptions").onclick = e => { e.preventDefault(); };
$("bnNew").onclick = e => {
    let name = prompt("New file name?", "untitled.xq");
    if (name === null) return;
    docSwitch("", name);
};

$("search").onclick = e => lsp.openSearchPanel(view);

$("fullscreen").onclick = e => $("editor").requestFullscreen();

$("bnWordAt").onclick = e => {
    let pos = view.state.selection.main.head;
    let w = view.state.wordAt(pos);
    alert("wordAt " + JSON.stringify(w));
};

$("symbols2").onclick = e => {
    client.sync();
    client.request("textDocument/documentSymbol", { "textDocument": { "uri": $("iFile").value } })
        .then(r => {
            console.log("symbols", r)
            $("symPanel").open = true;
            $("symList").setData(r);
        });
};

$("cmdList").onclick = e => {
    let cmds = lsp.listCommands(view);
    let result = "";
    [...cmds.keys()].sort().forEach(key => {
        result += `<li>${key} ${cmds.get(key).key}</li>`
    });
    $("popHelpInfo").innerHTML = `<ul>${result}</ul>`
    $("popCmds").showPopover()
};

$("symList").addEventListener("itemSelected", e => {
    const plugin = lsp.LSPPlugin.get(view)
    if (!plugin) return;
    const sel = e.detail.range // or selectionRange;
    console.log("SYM selection range", sel);
    const an = plugin.fromPosition(sel.start)
    const hd = plugin.fromPosition(sel.end)
    view.dispatch({ selection: { anchor: an, head: hd }, scrollIntoView: true });
});

$("lint").onclick = async e => {
    console.log("word", view.state.wordAt(1));
    lsp.openLintPanel(view);
};

$("sync").onclick = e => { client.sync(); console.log("XXXsync"); };
// state a state
$("bnSave").onclick = e => { workspace[iFile] = view.state; };
$("bnLoad").onclick = e => { const v = workspace[iFile]; if (v) view.setState(v) };


// select local file
$("bnRead").onclick = e => { $("fileElem").click(); };
$("fileElem").onchange = e => {
    let file = e.target.files[0]
    let fr = new FileReader();
    fr.onload = () => docSwitch(fr.result, file.name);
    fr.readAsText(file);
};

$("format").onclick = e => { console.log("FMT", lsp.formatDocument(view)); };

$("popUrl").onsubmit = e => {
    e.preventDefault();
    const f = objectFromForm("popUrl");
    fetch(f.url)
        .then(response => response.text())
        .then(t => {
            docSwitch(t, f.url)
            $("popWeb").open = false;
        })
        .catch(error => {
            alert("CORS?: " + error)
        });
};
$("bnDebug").onclick = e => { debugger; };


$("tConnect").addEventListener('quiet-change', e => {
    e.preventDefault();
    $("popConnect").showPopover()
});
$("msgIcon").onclick = e => {
    e.preventDefault();
    alert("NOT YET")
};


function updateSettings(event) {
    event.preventDefault();

    console.log("COPTS", lsp.curOpts);
    const opts = {
        lineWrap: $("lineWrap").checked,
        highlightWhitespace: $("highlightWhitespace").checked,
        minimap: $("minimap").checked
    }
    console.log(opts)
    lsp.updateCompartment(opts);
    $('popSettings').hidePopover();
    formToStore("fSettings");
};

$("fSettings").addEventListener("submit", updateSettings);

function connect() {
    const server = $("iServer").value;
    const file = $("iFile").value;
    lsp.simpleWebSocketTransport(server)
        .then(transport => {
            transport.socket.onclose = (event) => $("tConnect").checked = false;
            transport.socket.oneror = (event) => $("msg").innerText = "sock error!";
            transport.subscribe(incoming);
            client = new lsp.LSPClient({ extensions: lsp.languageServerExtensions() });
            client.connect(transport);
            $("popConnect").hidePopover();
            $("tConnect").checked = true;
             $("tipConnect").innerText=server;
            const extLsp = client.plugin(file, "xquery");

            view.dispatch({
                effects: lsp.StateEffect.appendConfig.of(
                    [lsp.linter(null, { autoPanel: true }), ...extLsp,
                    lsp.keymap.of([...lsp.formatKeymap])])
            })
        })
        .catch(e => {
            console.log(e);
            $("tConnect").checked = false;
            alert("connection failed: " + server)
        });

};

// change active doc
function docSwitch(text,urlNew) {
    const urlOld=$("iFile").value;
    client.workspace.closeFile(urlOld);
    view.dispatch({
        changes: {
            from: 0,
            to: view.state.doc.length,
            insert: text
        }
    })
    client.workspace.openFile(urlNew,"xquery",view)
    $("iFile").value = urlNew;
};


function incoming(msg) {
    const rpc = JSON.parse(msg);
    log(rpc);
};


function log(rpc) {
    console.log("<-", rpc)
    const when = (new Date()).toISOString();
    const msg = { name: rpc.method ?? rpc.id, detail: when.substring(1 + when.indexOf("T")), kind: 23 /* event */ };
    //name,details,kind
    $("msgList").setData([msg], true)
    $("relative-time__live").date=new Date();
};

function formFromStore(name) {
    let v = localStorage.getItem(name)
    if (!!v) formDeserialize($(name), v);
};

function formToStore(name) {
    localStorage.setItem(name, formSerialize($(name)));
};

function objectFromForm(name) {
    const data = new FormData($(name));
    //https://stackabuse.com/convert-form-data-to-javascript-object/
    return Object.fromEntries(data.entries());
}
function formSerialize(form) {
    const data = new FormData(form);
    //https://stackoverflow.com/a/44033425/1869660
    return new URLSearchParams(data).toString();
}

function formDeserialize(form, data) {
    const entries = (new URLSearchParams(data)).entries();
    for (const [key, val] of entries) {
        //http://javascript-coder.com/javascript-form/javascript-form-value.phtml
        const input = form.elements[key];
        switch (input.type) {
            case 'checkbox': input.checked = !!val; break;
            default: input.value = val; break;
        }
    }
}