
import { EditorState, StateEffect } from '@codemirror/state';

import { lineNumbers, highlightActiveLineGutter, highlightSpecialChars, 
    drawSelection, rectangularSelection, crosshairCursor, highlightActiveLine, 
    keymap, dropCursor,EditorView} from '@codemirror/view';

import { openSearchPanel, highlightSelectionMatches, searchKeymap } from '@codemirror/search';

import { openLintPanel, lintGutter, lintKeymap, linter} from "@codemirror/lint"

import { indentWithTab, history, defaultKeymap, historyKeymap } from '@codemirror/commands';

import { foldGutter, indentOnInput, indentUnit, bracketMatching, foldKeymap, 
    syntaxHighlighting, defaultHighlightStyle , StreamLanguage } from '@codemirror/language';

import { closeBrackets, autocompletion, closeBracketsKeymap, completionKeymap } from '@codemirror/autocomplete';

import { LSPClient, LSPPlugin, languageServerSupport, languageServerExtensions,
    formatDocument,formatKeymap } from "@codemirror/lsp-client";

import { xQuery } from "@codemirror/legacy-modes/mode/xquery"



// Language
import { xml } from "@codemirror/lang-xml";

// return promise with socket map or reject if no connect
function simpleWebSocketTransport(uri) {
    let handlers = [];
    return new Promise(function (resolve, reject) {
        let sock = new WebSocket(uri);

        sock.onmessage = e => { for (let h of handlers) h(e.data.toString()); };
        sock.onerror = e => reject(e);
        sock.onopen = () => resolve({
            socket: sock,
            send: (message) => sock.send(message),
            subscribe: (handler) => handlers.push(handler),
            unsubscribe: (handler) => handlers = handlers.filter(h => h != handler)
        });
    }
    );
};

const baseExts = [
    lineNumbers(),
    highlightActiveLineGutter(),
    highlightSpecialChars(),
    history(),
    foldGutter(),
    lintGutter(),
    drawSelection(),
    dropCursor(),
    EditorState.allowMultipleSelections.of(true),
    EditorView.lineWrapping,
    indentOnInput(),
    syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
    bracketMatching(),
    closeBrackets(),
    autocompletion(),
    rectangularSelection(),
    crosshairCursor(),
    highlightActiveLine(),
    highlightSelectionMatches(),
    keymap.of([
        ...closeBracketsKeymap,
        ...defaultKeymap,
        ...searchKeymap,
        ...historyKeymap,
        ...foldKeymap,
        ...completionKeymap,
        ...lintKeymap
    ]),
    StreamLanguage.define(xQuery)
];



// map cmd->{keybings,fn}
function listCommands(view) {
    const commands = new Map();
    const keymaps = view.state.facet(keymap);
    for (let km of keymaps) {
        for (let binding of km) {
            if (binding.run && binding.run.name) {
                commands.set(binding.run.name, { key: binding.key, fn: binding.run });
            }
        }
    }
    return commands;
};

export { baseExts, EditorView, EditorState, StateEffect, LSPPlugin, LSPClient, 
     openSearchPanel, openLintPanel, languageServerSupport, languageServerExtensions,
     simpleWebSocketTransport, linter,  formatDocument,keymap,formatKeymap, listCommands };