"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
/* --------------------------------------------------------------------------------------------
 * Copyright (c) Microsoft Corporation. All rights reserved.
 * Licensed under the MIT License. See License.txt in the project root for license information.
 * ------------------------------------------------------------------------------------------ */
const vscode_languageserver_1 = require("vscode-languageserver");
const vscode_languageserver_textdocument_1 = require("vscode-languageserver-textdocument");
const node_1 = require("vscode-languageserver/node");
const flinkdb_schema_json_1 = __importDefault(require("./assets/flinkdb.schema.json"));
const constants_1 = require("./constants");
const lsp_server_1 = require("./lsp-server");
const protocol_translation_1 = require("./protocol-translation");
// Create a connection for the server, using Node's IPC as transport.
// Also include all preview / proposed LSP features.
const connection = (0, node_1.createConnection)(node_1.ProposedFeatures.all);
// Create a simple text document manager.
const documents = new node_1.TextDocuments(vscode_languageserver_textdocument_1.TextDocument);
const lspServer = new lsp_server_1.LSPServer();
const isLanguageIdSupported = (document) => constants_1.SUPPORT_LANGUAGE_IDs.includes(document.languageId);
let hasConfigurationCapability = false;
let hasWorkspaceFolderCapability = false;
let hasDiagnosticRelatedInformationCapability = false;
let hasCodeActionLiteralsCapability = false;
connection.onInitialize((params) => {
    const capabilities = params.capabilities;
    // Does the client support the `workspace/configuration` request?
    // If not, we fall back using global settings.
    hasConfigurationCapability = !!(capabilities.workspace && !!capabilities.workspace.configuration);
    hasWorkspaceFolderCapability = !!(capabilities.workspace && !!capabilities.workspace.workspaceFolders);
    hasDiagnosticRelatedInformationCapability = !!(capabilities.textDocument &&
        capabilities.textDocument.publishDiagnostics &&
        capabilities.textDocument.publishDiagnostics.relatedInformation);
    hasCodeActionLiteralsCapability = !!capabilities.textDocument?.codeAction?.codeActionLiteralSupport;
    const result = {
        capabilities: {
            textDocumentSync: node_1.TextDocumentSyncKind.Incremental,
            executeCommandProvider: {
                commands: [constants_1.ServerCommands.EXTRACT_SQL_STRUCTURE]
            },
            documentFormattingProvider: true,
            referencesProvider: true,
            hoverProvider: true,
            foldingRangeProvider: true,
            renameProvider: true,
            codeActionProvider: true,
            // Tell the client that this server supports code completion.
            completionProvider: {
                triggerCharacters: '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''),
                resolveProvider: true
            }
        }
    };
    if (hasWorkspaceFolderCapability) {
        result.capabilities.workspace = {
            workspaceFolders: {
                supported: true
            }
        };
    }
    if (hasCodeActionLiteralsCapability) {
        result.capabilities.codeActionProvider = {
            codeActionKinds: [vscode_languageserver_1.CodeActionKind.QuickFix]
        };
    }
    return result;
});
connection.onInitialized(() => {
    if (hasConfigurationCapability) {
        // Register for all configuration changes.
        connection.client.register(node_1.DidChangeConfigurationNotification.type, undefined).then();
    }
    if (hasWorkspaceFolderCapability) {
        connection.workspace.onDidChangeWorkspaceFolders(() => {
            connection.console.log('Workspace folder change event received.');
        });
    }
});
// The global settings, used when the `workspace/configuration` request is not supported by the client.
// Please note that this is not the case when using this server with the client provided in this example
// but could happen with other clients.
const defaultSettings = { maxNumberOfProblems: 1000 };
let globalSettings = defaultSettings;
// Cache the settings of all open documents
const documentSettings = new Map();
connection.onDidChangeConfiguration(change => {
    if (hasConfigurationCapability) {
        // Reset all cached document settings
        documentSettings.clear();
    }
    else {
        globalSettings = (change.settings.languageServerExample || defaultSettings);
    }
    // Revalidate all open text documents
    documents.all().filter(isLanguageIdSupported).forEach(validateTextDocument);
});
function getDocumentSettings(resource) {
    if (!hasConfigurationCapability) {
        return Promise.resolve(globalSettings);
    }
    let result = documentSettings.get(resource);
    if (!result) {
        result = connection.workspace.getConfiguration({
            scopeUri: resource,
            section: 'languageServerExample'
        });
        documentSettings.set(resource, result);
    }
    return result;
}
documents.onDidOpen(e => {
    lspServer.warehouse.setParsingValue(e.document);
});
// Only keep settings for open documents
documents.onDidClose(e => {
    lspServer.warehouse.removeParsingValue(e.document.uri);
    documentSettings.delete(e.document.uri);
});
// The content of a text document has changed. This event is emitted
// when the text document first opened or when its content has changed.
documents.onDidChangeContent(change => {
    lspServer.warehouse.setParsingValue(change.document);
    validateTextDocument(change.document);
});
function validateTextDocument(textDocument) {
    const diagnostics = lspServer.doValidation(textDocument);
    // Send the computed diagnostics to VSCode.
    connection.sendDiagnostics({ uri: textDocument.uri, diagnostics }).then();
}
connection.onDidChangeWatchedFiles(() => {
    // Monitored files have change in VSCode
    connection.console.log('We received an file change event');
});
// This handler provides the initial list of the completion items.
connection.onCompletion((params) => {
    const { textDocument, position } = params;
    const document = documents.get(textDocument.uri);
    if (!document) {
        console.error('TextDocument not found.');
        return [];
    }
    return lspServer.doCompletion(document, position).completionItems;
});
connection.onCompletionResolve((item) => {
    if (!item.detail) {
        item.detail = 'Flink Sql keyword';
    }
    return item;
});
connection.onCodeAction((params) => {
    const actions = [];
    const diagnostics = params.context.diagnostics;
    if (!diagnostics.length) {
        return [];
    }
    const document = documents.get(params.textDocument.uri);
    if (!document) {
        console.error('TextDocument not found.');
        return [];
    }
    const kinds = params.context.only;
    if (kinds?.includes(vscode_languageserver_1.CodeActionKind.QuickFix)) {
        diagnostics.forEach(diagnostic => {
            const quickFixes = diagnostic.data?.suggestions
                .filter((s) => s !== 'EOF')
                .map((newText) => ({
                title: `Cannot find name '${document.getText(diagnostic.range)}'. Do you mean '${newText}'?`,
                kind: vscode_languageserver_1.CodeActionKind.QuickFix,
                diagnostics: [diagnostic],
                edit: {
                    changes: {
                        [params.textDocument.uri]: [
                            {
                                newText,
                                range: diagnostic.range
                            }
                        ]
                    }
                }
            })) || [];
            actions.push(...quickFixes);
        });
    }
    return actions;
});
connection.onDocumentFormatting((params) => {
    const document = documents.get(params.textDocument.uri);
    if (!document) {
        console.error('TextDocument not found.');
        return [];
    }
    const range = { start: { line: 0, character: 0 }, end: { line: document.lineCount, character: 0 } };
    const formatted = lspServer.doFormatting(document, params.options);
    return [
        {
            range,
            newText: formatted
        }
    ];
});
connection.onReferences((params) => {
    const document = documents.get(params.textDocument.uri);
    if (!document) {
        console.error('TextDocument not found.');
        return [];
    }
    const semanticToken = lspServer
        .parseForSemanticTokens(document)
        .find(t => (0, protocol_translation_1.positionInRange)(document, params.position, t.range));
    if (!semanticToken) {
        return [];
    }
    let references = lspServer.doReferences(document, params.position).map(reference => {
        return {
            uri: document.uri,
            range: reference
        };
    });
    documents
        .all()
        .filter(doc => isLanguageIdSupported(doc) && doc.uri !== params.textDocument.uri)
        .forEach(doc => {
        const semanticTokens = lspServer.parseForSemanticTokens(doc);
        references = references.concat(semanticTokens
            .filter(t => (0, lsp_server_1.isSemanticTokenReference)(t, semanticToken))
            .map(t => ({ uri: doc.uri, range: t.range })));
    });
    return references;
});
connection.onHover((params) => {
    const document = documents.get(params.textDocument.uri);
    const contents = [];
    if (!document) {
        console.error('TextDocument not found.');
        return { contents };
    }
    const token = lspServer.getTokenByPosition(document, params.position);
    if (token?.text === undefined) {
        return { contents };
    }
    const functionItem = flinkdb_schema_json_1.default.functions.find(f => token.text.localeCompare(f.name, undefined, { sensitivity: 'accent' }) === 0);
    if (functionItem) {
        contents.push(functionItem.description);
    }
    return {
        contents
    };
});
connection.onFoldingRanges((params) => {
    const document = documents.get(params.textDocument.uri);
    if (!document) {
        console.error('TextDocument not found.');
        return [];
    }
    return lspServer.doFoldingRanges(document);
});
connection.onRenameRequest((params) => {
    const document = documents.get(params.textDocument.uri);
    if (!document) {
        console.error('TextDocument not found.');
        return;
    }
    const semanticToken = lspServer
        .parseForSemanticTokens(document)
        .find(t => (0, protocol_translation_1.positionInRange)(document, params.position, t.range));
    if (!semanticToken) {
        return;
    }
    const workspaceEdit = { changes: {} };
    documents
        .all()
        .filter(isLanguageIdSupported)
        .forEach(doc => {
        const tokens = lspServer.parseForSemanticTokens(doc).filter(t => (0, lsp_server_1.isSemanticTokenReference)(t, semanticToken));
        workspaceEdit.changes[doc.uri] = tokens.map(t => ({
            newText: params.newName,
            range: t.range
        }));
    });
    return workspaceEdit;
});
// TODO: implement other custom commands
connection.onExecuteCommand((params) => {
    if (params.command === constants_1.ServerCommands.EXTRACT_SQL_STRUCTURE) {
        const uri = params.arguments?.[0];
        const options = params.arguments?.[1];
        if (!uri) {
            console.error('Invalid document URI provided for Extract SQL Structure command.');
            return;
        }
        const document = documents.get(uri);
        if (!document) {
            console.error('TextDocument not found.');
            return;
        }
        if (options !== undefined && typeof options === 'object') {
            return lspServer.parseStructure(document, options);
        }
        return lspServer.parseStructure(document);
    }
});
// Make the text document manager listen on the connection
// for open, change and close text document events
documents.listen(connection);
// Listen on the connection
connection.listen();
//# sourceMappingURL=server.js.map