'use strict';

var syntaxTree = require('../syntax-tree.js');
var astUtils = require('../utils/ast-utils.js');
var cstUtils = require('../utils/cst-utils.js');
var promiseUtils = require('../utils/promise-utils.js');
var uriUtils = require('../utils/uri-utils.js');
var cancellation = require('../../../../../../../_virtual/cancellation.js');

/******************************************************************************
 * Copyright 2021 TypeFox GmbH
 * This program and the accompanying materials are made available under the
 * terms of the MIT License, which is available in the project root.
 ******************************************************************************/
class DefaultAstNodeDescriptionProvider {
    constructor(services) {
        this.astNodeLocator = services.workspace.AstNodeLocator;
        this.nameProvider = services.references.NameProvider;
    }
    createDescription(node, name, document) {
        const doc = document !== null && document !== void 0 ? document : astUtils.getDocument(node);
        name !== null && name !== void 0 ? name : (name = this.nameProvider.getName(node));
        const path = this.astNodeLocator.getAstNodePath(node);
        if (!name) {
            throw new Error(`Node at path ${path} has no name.`);
        }
        let nameNodeSegment;
        const nameSegmentGetter = () => { var _a; return nameNodeSegment !== null && nameNodeSegment !== void 0 ? nameNodeSegment : (nameNodeSegment = cstUtils.toDocumentSegment((_a = this.nameProvider.getNameNode(node)) !== null && _a !== void 0 ? _a : node.$cstNode)); };
        return {
            node,
            name,
            get nameSegment() {
                return nameSegmentGetter();
            },
            selectionSegment: cstUtils.toDocumentSegment(node.$cstNode),
            type: node.$type,
            documentUri: doc.uri,
            path
        };
    }
}
class DefaultReferenceDescriptionProvider {
    constructor(services) {
        this.nodeLocator = services.workspace.AstNodeLocator;
    }
    async createDescriptions(document, cancelToken = cancellation.cancellationExports.CancellationToken.None) {
        const descr = [];
        const rootNode = document.parseResult.value;
        for (const astNode of astUtils.streamAst(rootNode)) {
            await promiseUtils.interruptAndCheck(cancelToken);
            astUtils.streamReferences(astNode).filter(refInfo => !syntaxTree.isLinkingError(refInfo)).forEach(refInfo => {
                // TODO: Consider logging a warning or throw an exception when DocumentState is < than Linked
                const description = this.createDescription(refInfo);
                if (description) {
                    descr.push(description);
                }
            });
        }
        return descr;
    }
    createDescription(refInfo) {
        const targetNodeDescr = refInfo.reference.$nodeDescription;
        const refCstNode = refInfo.reference.$refNode;
        if (!targetNodeDescr || !refCstNode) {
            return undefined;
        }
        const docUri = astUtils.getDocument(refInfo.container).uri;
        return {
            sourceUri: docUri,
            sourcePath: this.nodeLocator.getAstNodePath(refInfo.container),
            targetUri: targetNodeDescr.documentUri,
            targetPath: targetNodeDescr.path,
            segment: cstUtils.toDocumentSegment(refCstNode),
            local: uriUtils.UriUtils.equals(targetNodeDescr.documentUri, docUri)
        };
    }
}

exports.DefaultAstNodeDescriptionProvider = DefaultAstNodeDescriptionProvider;
exports.DefaultReferenceDescriptionProvider = DefaultReferenceDescriptionProvider;
