"use strict";
var __spreadArray = (this && this.__spreadArray) || function (to, from) {
    for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
        to[j] = from[i];
    return to;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.processComments = exports.getTokenLeadingComments = exports.printNodeWithComments = exports.printTokenWithComments = void 0;
var doc_1 = require("prettier/doc");
var utils_1 = require("../../types/utils");
var concat = doc_1.builders.concat, hardline = doc_1.builders.hardline, lineSuffix = doc_1.builders.lineSuffix, breakParent = doc_1.builders.breakParent, literalline = doc_1.builders.literalline;
/**
 * Takes a token and return a doc with:
 * - concatenated leading comments
 * - the token image
 * - concatenated trailing comments
 *
 * @param {IToken} token
 * @return a doc with the token and its comments
 */
function printTokenWithComments(token) {
    return printWithComments(token, token.image, getTokenLeadingComments, getTokenTrailingComments);
}
exports.printTokenWithComments = printTokenWithComments;
/**
 * Takes a node and return a doc with:
 * - concatenated leading comments
 * - the node doc value
 * - concatenated trailing comments
 *
 * @param {CstNode} node
 * @param {Doc} value - the converted node value
 * @return a doc with the token and its comments
 */
function printNodeWithComments(node, value) {
    return printWithComments(node, value, getNodeLeadingComments, getNodeTrailingComments);
}
exports.printNodeWithComments = printNodeWithComments;
function printWithComments(nodeOrToken, value, getLeadingComments, getTrailingComments) {
    var leadingComments = getLeadingComments(nodeOrToken);
    var trailingComments = getTrailingComments(nodeOrToken, value);
    return leadingComments.length === 0 && trailingComments.length === 0
        ? value
        : concat(__spreadArray(__spreadArray(__spreadArray([], leadingComments), [value]), trailingComments));
}
/**
 * @param {IToken} token
 * @return an array containing processed leading comments and separators
 */
function getTokenLeadingComments(token) {
    return getLeadingComments(token, token);
}
exports.getTokenLeadingComments = getTokenLeadingComments;
/**
 * @param {CstNode} node
 * @return an array containing processed leading comments and separators
 */
function getNodeLeadingComments(node) {
    return getLeadingComments(node, node.location);
}
function getLeadingComments(nodeOrToken, location) {
    var arr = [];
    if (nodeOrToken.leadingComments !== undefined) {
        var previousEndLine = nodeOrToken.leadingComments[0].endLine;
        var step = void 0;
        arr.push(concat(formatComment(nodeOrToken.leadingComments[0])));
        for (var i = 1; i < nodeOrToken.leadingComments.length; i++) {
            step = nodeOrToken.leadingComments[i].startLine - previousEndLine;
            if (step === 1 ||
                nodeOrToken.leadingComments[i].startOffset > location.startOffset) {
                arr.push(hardline);
            }
            else if (step > 1) {
                arr.push(hardline, hardline);
            }
            arr.push(concat(formatComment(nodeOrToken.leadingComments[i])));
            previousEndLine = nodeOrToken.leadingComments[i].endLine;
        }
        step = location.startLine - previousEndLine;
        if (step === 1 ||
            nodeOrToken.leadingComments[nodeOrToken.leadingComments.length - 1]
                .startOffset > location.startOffset) {
            arr.push(hardline);
        }
        else if (step > 1) {
            arr.push(hardline, hardline);
        }
    }
    return arr;
}
/**
 * @param {IToken} token
 * @return an array containing processed trailing comments and separators
 */
function getTokenTrailingComments(token) {
    return getTrailingComments(token, token.image, token);
}
/**
 * @param {CstNode} node
 * @param {string} value
 * @return an array containing processed trailing comments and separators
 */
function getNodeTrailingComments(node, value) {
    return getTrailingComments(node, value, node.location);
}
function getTrailingComments(nodeOrToken, value, location) {
    var arr = [];
    var previousEndLine = location.endLine;
    if (nodeOrToken.trailingComments !== undefined) {
        nodeOrToken.trailingComments.forEach(function (comment, idx) {
            var separator = "";
            if (comment.startLine !== previousEndLine) {
                arr.push(hardline);
            }
            else if (value !== "" && idx === 0) {
                separator = " ";
            }
            if (comment.tokenType.name === "LineComment") {
                arr.push(lineSuffix(concat([separator, concat(formatComment(comment)), breakParent])));
            }
            else {
                arr.push(concat(formatComment(comment)));
            }
            previousEndLine = comment.endLine;
        });
    }
    return arr;
}
function isJavaDoc(comment, lines) {
    var isJavaDoc = true;
    if (comment.tokenType.name === "TraditionalComment" && lines.length > 1) {
        for (var i = 1; i < lines.length; i++) {
            if (lines[i].trim().charAt(0) !== "*") {
                isJavaDoc = false;
                break;
            }
        }
    }
    else {
        isJavaDoc = false;
    }
    return isJavaDoc;
}
function formatJavaDoc(lines) {
    var res = [lines[0].trim()];
    for (var i = 1; i < lines.length; i++) {
        res.push(hardline);
        res.push(" " + lines[i].trim());
    }
    return res;
}
function formatComment(comment) {
    var res = [];
    var lines = comment.image.split("\n");
    if (isJavaDoc(comment, lines)) {
        return formatJavaDoc(lines);
    }
    lines.forEach(function (line) {
        res.push(line);
        res.push(literalline);
    });
    res.pop();
    return res;
}
function processComments(docs) {
    if (!Array.isArray(docs)) {
        if (utils_1.isCstElementOrUndefinedIToken(docs)) {
            return printTokenWithComments(docs);
        }
        return docs;
    }
    return docs.map(function (elt) {
        if (utils_1.isCstElementOrUndefinedIToken(elt)) {
            return printTokenWithComments(elt);
        }
        return elt;
    });
}
exports.processComments = processComments;
