"use strict";
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
    if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
        if (ar || !(i in from)) {
            if (!ar) ar = Array.prototype.slice.call(from, 0, i);
            ar[i] = from[i];
        }
    }
    return to.concat(ar || Array.prototype.slice.call(from));
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.formatMethod = void 0;
var recreateQueryOnelinerFromSyntaxTree_1 = require("../recreateQueryOnelinerFromSyntaxTree");
var types_1 = require("../types");
var utils_1 = require("../utils");
var layoutUtils_1 = require("../layoutUtils");
var utils_2 = require("./utils");
// Groups arguments into argument groups an adds a localIndentation property
var formatMethod = function (formatSyntaxTree) { return function (config) { return function (syntaxTree) {
    var method = formatSyntaxTree((0, utils_2.withNoEndDotInfo)(config))(syntaxTree.method);
    var argumentsWillNotBeWrapped = (0, layoutUtils_1.willFitOnLine)(syntaxTree, config, config.horizontalPosition);
    if (argumentsWillNotBeWrapped) {
        var recreatedQuery = (0, recreateQueryOnelinerFromSyntaxTree_1.default)(config, config.horizontalPosition)(syntaxTree);
        return {
            type: types_1.TokenType.Method,
            method: method,
            // The arguments property is here so that the resulted syntax tree can
            // still be understood by recreateQueryOnelinerFromSyntaxTree
            arguments: syntaxTree.arguments,
            argumentGroups: [
                syntaxTree.arguments.reduce(function (argumentGroup, syntaxTree) {
                    return __spreadArray(__spreadArray([], argumentGroup, true), [
                        formatSyntaxTree(
                        // Since the method's arguments will be on the same line, their horizontal position is increased by the
                        // method's width plus the width of the opening parenthesis
                        (0, utils_1.pipe)(utils_2.withZeroIndentation, utils_2.withZeroDotInfo, (0, utils_2.withIncreasedHorizontalPosition)(method.width +
                            1 +
                            (config.shouldStartWithDot ? 1 : 0) +
                            argumentGroup.map(function (_a) {
                                var width = _a.width;
                                return width;
                            }).reduce(utils_1.sum, 0) +
                            argumentGroup.length))(config))(syntaxTree),
                    ], false);
                }, []),
            ],
            argumentsShouldStartOnNewLine: false,
            shouldStartWithDot: false,
            shouldEndWithDot: Boolean(config.shouldEndWithDot),
            localIndentation: config.localIndentation,
            horizontalPosition: config.horizontalPosition,
            width: recreatedQuery.trim().length,
        };
    }
    // shouldEndWithDot has to reside on the method object, so the end dot can be
    // placed after the method parentheses. shouldStartWithDot has to be passed on
    // further down so the start dot can be placed after the indentation.
    var horizontalPosition = config.horizontalPosition + method.width + (config.shouldStartWithDot ? 1 : 0) + 1;
    var greedyArgumentGroups = syntaxTree.arguments.reduce(function (acc, arg) {
        var formattedArg = formatSyntaxTree((0, utils_1.pipe)(utils_2.withZeroIndentation, utils_2.withZeroDotInfo, (0, utils_2.withHorizontalPosition)(horizontalPosition))(config))(arg);
        var currentGroupWidth = acc.currentGroup.map(function (_a) {
            var width = _a.width;
            return width;
        }).reduce(utils_1.sum, 0) + Math.max(acc.currentGroup.length - 1, 0) * 2;
        var potentialGroupWidth = acc.currentGroup.length > 0 ? currentGroupWidth + 2 + formattedArg.width : formattedArg.width;
        if (acc.currentGroup.length > 0 && horizontalPosition + potentialGroupWidth > config.maxLineLength) {
            return {
                groups: __spreadArray(__spreadArray([], acc.groups, true), [acc.currentGroup], false),
                currentGroup: [
                    formatSyntaxTree((0, utils_1.pipe)((0, utils_2.withIndentation)(horizontalPosition), utils_2.withZeroDotInfo, (0, utils_2.withHorizontalPosition)(horizontalPosition))(config))(arg),
                ],
            };
        }
        return __assign(__assign({}, acc), { currentGroup: __spreadArray(__spreadArray([], acc.currentGroup, true), [
                formatSyntaxTree((0, utils_1.pipe)((0, utils_2.withIndentation)(horizontalPosition), utils_2.withZeroDotInfo, (0, utils_2.withHorizontalPosition)(horizontalPosition))(config))(arg),
            ], false) });
    }, { groups: [], currentGroup: [] });
    var argumentGroups = greedyArgumentGroups.currentGroup.length > 0
        ? __spreadArray(__spreadArray([], greedyArgumentGroups.groups, true), [greedyArgumentGroups.currentGroup], false) : greedyArgumentGroups.groups;
    var indentationWidth = horizontalPosition;
    var greedyFits = argumentGroups.every(function (group) {
        var groupWidth = group.map(function (_a) {
            var width = _a.width;
            return width;
        }).reduce(utils_1.sum, 0) + (group.length - 1) * 2;
        return indentationWidth + groupWidth <= config.maxLineLength;
    });
    if (greedyFits) {
        var lastArgumentGroup = (0, utils_1.last)(argumentGroups);
        // Add the width of the last line of parameters, the dots between them and the indentation of the parameters
        var width = lastArgumentGroup
            ? lastArgumentGroup.map(function (_a) {
                var width = _a.width;
                return width;
            }).reduce(utils_1.sum, 0) + (lastArgumentGroup.length - 1) * 2
            : 0;
        return {
            type: types_1.TokenType.Method,
            method: method,
            arguments: syntaxTree.arguments,
            argumentGroups: argumentGroups,
            argumentsShouldStartOnNewLine: false,
            localIndentation: config.localIndentation,
            horizontalPosition: config.horizontalPosition,
            shouldStartWithDot: false,
            shouldEndWithDot: Boolean(config.shouldEndWithDot),
            width: width,
        };
    }
    // Fallback to wrap-all
    var wrapAllArgumentGroups = syntaxTree.arguments.map(function (step) { return [
        formatSyntaxTree((0, utils_1.pipe)((0, utils_2.withIndentation)(horizontalPosition), utils_2.withZeroDotInfo, (0, utils_2.withHorizontalPosition)(horizontalPosition))(config))(step),
    ]; });
    var lastWrapAllArgumentGroup = (0, utils_1.last)(wrapAllArgumentGroups);
    var wrapAllWidth = lastWrapAllArgumentGroup
        ? lastWrapAllArgumentGroup.map(function (_a) {
            var width = _a.width;
            return width;
        }).reduce(utils_1.sum, 0) + (lastWrapAllArgumentGroup.length - 1) * 2
        : 0;
    return {
        type: types_1.TokenType.Method,
        method: method,
        arguments: syntaxTree.arguments,
        argumentGroups: wrapAllArgumentGroups,
        argumentsShouldStartOnNewLine: false,
        localIndentation: config.localIndentation,
        horizontalPosition: config.horizontalPosition,
        shouldStartWithDot: false,
        shouldEndWithDot: Boolean(config.shouldEndWithDot),
        width: wrapAllWidth,
    };
}; }; };
exports.formatMethod = formatMethod;
