"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.hover = hover;
const checker_js_1 = require("../checker.js");
const parser_js_1 = require("../parser.js");
const types_js_1 = require("../types.js");
const common_js_1 = require("./command/common.js");
const util_js_1 = require("./util.js");
function hover(doc, sourceFile, position) {
    const offset = doc.offsetAt(position);
    const g = sourceFile.graph;
    if (!g)
        return undefined;
    const node = (0, checker_js_1.findNodeAtOffset)(g, offset);
    if (node === undefined)
        return undefined;
    return getNodeHover(doc, sourceFile, node);
}
function getNodeHover(doc, sf, n) {
    const contents = getHoverContents(n);
    if (contents) {
        return {
            contents,
            range: (0, util_js_1.syntaxNodeToRange)(doc, sf, n),
        };
    }
    return undefined;
}
function getAssignedLabel(statement) {
    const assignments = statement.attributes.flatMap(a => a.assignments);
    const assignedLabel = assignments === null || assignments === void 0 ? void 0 : assignments.find(a => (0, checker_js_1.getIdentifierText)(a.leftId) === "label");
    return (assignedLabel === null || assignedLabel === void 0 ? void 0 : assignedLabel.rightId) ? (0, checker_js_1.getIdentifierText)(assignedLabel.rightId) : undefined;
}
function getHoverContents(n) {
    var _a, _b, _c;
    if ((0, parser_js_1.isIdentifierNode)(n)) {
        const parent = n.parent;
        if (parent) {
            switch (parent.kind) {
                case types_js_1.SyntaxKind.NodeId: {
                    if ((_a = n.symbol) === null || _a === void 0 ? void 0 : _a.references) {
                        const nodeIdentifierRefs = (_b = n.symbol) === null || _b === void 0 ? void 0 : _b.references;
                        const labelMentions = nodeIdentifierRefs.map(e => {
                            var _a, _b, _c;
                            return (_c = (_b = (_a = e.symbol) === null || _a === void 0 ? void 0 : _a.members) === null || _b === void 0 ? void 0 : _b.get("label")) === null || _c === void 0 ? void 0 : _c.firstMention.parent;
                        });
                        for (let i = labelMentions.length; i >= 0; i--) {
                            const s = labelMentions[i];
                            if (s === null || s === void 0 ? void 0 : s.rightId) {
                                return `(node) ${(0, checker_js_1.getIdentifierText)(n)}: ${(0, checker_js_1.getIdentifierText)(s.rightId)}`;
                            }
                        }
                    }
                    else if (((_c = parent.parent) === null || _c === void 0 ? void 0 : _c.kind) === types_js_1.SyntaxKind.NodeStatement) {
                        const label = getAssignedLabel(parent.parent);
                        if (label) {
                            return `(node) ${(0, checker_js_1.getIdentifierText)(n)}: ${label}`;
                        }
                    }
                    return `(node) ${(0, checker_js_1.getIdentifierText)(n)}`;
                }
                case types_js_1.SyntaxKind.Assignment: {
                    const assignment = parent;
                    const left = (0, checker_js_1.getIdentifierText)(assignment.leftId);
                    const right = (0, checker_js_1.getIdentifierText)(assignment.rightId);
                    return `(assignment) \`${left}\` = \`${right}\``;
                }
                case types_js_1.SyntaxKind.DirectedGraph:
                    return getGraphHover(parent);
                case types_js_1.SyntaxKind.UndirectedGraph:
                    return getGraphHover(parent);
                case types_js_1.SyntaxKind.SubGraphStatement: {
                    const sgs = parent;
                    const sg = sgs.subgraph;
                    return sg.id ? `(sub graph) ${(0, checker_js_1.getIdentifierText)(sg.id)}` : "(sub graph)";
                }
                case types_js_1.SyntaxKind.SubGraph: {
                    const sg = parent;
                    return sg.id ? `(sub graph) ${(0, checker_js_1.getIdentifierText)(sg.id)}` : "(sub graph)";
                }
                case types_js_1.SyntaxKind.IdEqualsIdStatement: {
                    const idEqId = parent;
                    const left = (0, checker_js_1.getIdentifierText)(idEqId.leftId);
                    const right = (0, checker_js_1.getIdentifierText)(idEqId.rightId);
                    return `(graph property) \`${left}\` = \`${right}\``;
                }
                case types_js_1.SyntaxKind.EdgeRhs:
                    return getEdgeHover(parent);
            }
            return types_js_1.SyntaxKind[parent.kind];
        }
        const fallback = types_js_1.SyntaxKind[n.kind];
        return fallback ? `(${fallback.toLowerCase()})` : undefined;
    }
    switch (n.kind) {
        case types_js_1.SyntaxKind.GraphKeyword:
        case types_js_1.SyntaxKind.DigraphKeyword:
        case types_js_1.SyntaxKind.StrictKeyword:
            return getGraphHover(n.parent);
        case types_js_1.SyntaxKind.DirectedGraph:
        case types_js_1.SyntaxKind.UndirectedGraph:
            return getGraphHover(n);
        case types_js_1.SyntaxKind.DirectedEdgeOp:
        case types_js_1.SyntaxKind.UndirectedEdgeOp:
            return getEdgeHover(n.parent);
        default:
            return undefined;
    }
}
function getGraphHover(g) {
    const direction = g.kind === types_js_1.SyntaxKind.DirectedGraph ? "directed" : "undirected";
    const graphId = g.id;
    const strict = g.strict ? "strict " : "";
    return graphId
        ? `(${strict}${direction} graph) ${(0, checker_js_1.getIdentifierText)(graphId)}`
        : `(${strict}${direction} graph)`;
}
function getEdgeHover(n) {
    const p = n.parent;
    if (!p || p.rhs.length === 0)
        return undefined;
    let source = undefined;
    for (const curr of p.rhs) {
        if (curr === n)
            break;
        source = curr.target;
    }
    if (source === undefined)
        source = p.source;
    const edgeOpStr = (0, common_js_1.getEdgeStr)(n.operation.kind);
    return source === undefined
        ? undefined
        : `(edge) ${getEdgeSourceOrTargetText(source)} ${edgeOpStr} ${getEdgeSourceOrTargetText(n.target)}`;
}
function getEdgeSourceOrTargetText(n) {
    return n.kind === types_js_1.SyntaxKind.NodeId
        ? (0, checker_js_1.getIdentifierText)(n.id)
        : n.id !== undefined
            ? `${(0, checker_js_1.getIdentifierText)(n.id)}`
            : "sub graph";
}
//# sourceMappingURL=hover.js.map