"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DockerSignatures = void 0;
/* --------------------------------------------------------------------------------------------
 * Copyright (c) Remy Suen. All rights reserved.
 * Licensed under the MIT License. See License.txt in the project root for license information.
 * ------------------------------------------------------------------------------------------ */
var vscode_languageserver_textdocument_1 = require("vscode-languageserver-textdocument");
var dockerPlainText_1 = require("./dockerPlainText");
var dockerfile_ast_1 = require("dockerfile-ast");
var docker_1 = require("./docker");
var DockerSignatures = /** @class */ (function () {
    function DockerSignatures() {
        this.documentation = new dockerPlainText_1.PlainTextDocumentation();
    }
    DockerSignatures.prototype.computeSignatures = function (content, position) {
        var document = vscode_languageserver_textdocument_1.TextDocument.create("", "", 0, content);
        var dockerfile = dockerfile_ast_1.DockerfileParser.parse(document.getText());
        if (position.line === 0) {
            var directive = dockerfile.getDirective();
            if (directive !== null && directive.getDirective() === dockerfile_ast_1.Directive.escape) {
                return {
                    signatures: [
                        {
                            label: "escape=\\",
                            documentation: this.documentation.getDocumentation("signatureEscape"),
                            parameters: [
                                {
                                    label: "\\",
                                    documentation: this.documentation.getDocumentation("signatureEscape_Param")
                                }
                            ]
                        }
                    ],
                    activeSignature: 0,
                    activeParameter: 0
                };
            }
        }
        for (var _i = 0, _a = dockerfile.getComments(); _i < _a.length; _i++) {
            var comment = _a[_i];
            if (docker_1.Util.isInsideRange(position, comment.getRange())) {
                return {
                    signatures: [],
                    activeSignature: null,
                    activeParameter: null
                };
            }
        }
        var signatureHelp = this.getInstructionSignatures(document, dockerfile.getOnbuildTriggers(), position);
        if (!signatureHelp) {
            signatureHelp = this.getInstructionSignatures(document, dockerfile.getInstructions(), position);
            if (!signatureHelp) {
                signatureHelp = {
                    signatures: [],
                    activeSignature: null,
                    activeParameter: null
                };
            }
        }
        return signatureHelp;
    };
    DockerSignatures.prototype.getInstructionSignatures = function (document, instructions, position) {
        for (var _i = 0, instructions_1 = instructions; _i < instructions_1.length; _i++) {
            var instruction = instructions_1[_i];
            if (!docker_1.Util.isInsideRange(position, instruction.getRange())) {
                continue;
            }
            else if (docker_1.Util.isInsideRange(position, instruction.getInstructionRange())) {
                return null;
            }
            switch (instruction.getKeyword()) {
                case "ADD":
                    var add = instruction;
                    var addShellSignature = {
                        label: "ADD [flags] source ... dest",
                        documentation: this.documentation.getDocumentation("signatureAdd_Signature0"),
                        parameters: [
                            {
                                label: "[flags]",
                                documentation: this.documentation.getDocumentation("signatureAdd_Signature0_Param0")
                            },
                            {
                                label: "source",
                                documentation: this.documentation.getDocumentation("signatureAdd_Signature0_Param1")
                            },
                            {
                                label: "...",
                                documentation: this.documentation.getDocumentation("signatureAdd_Signature0_Param2")
                            },
                            {
                                label: "dest",
                                documentation: this.documentation.getDocumentation("signatureAdd_Signature0_Param3")
                            }
                        ]
                    };
                    var addJsonSignature = {
                        label: "ADD [flags] [ \"source\", ..., \"dest\" ]",
                        documentation: this.documentation.getDocumentation("signatureAdd_Signature1"),
                        parameters: [
                            {
                                label: "[flags]",
                                documentation: this.documentation.getDocumentation("signatureAdd_Signature1_Param0")
                            },
                            {
                                label: "["
                            },
                            {
                                label: "\"source\"",
                                documentation: this.documentation.getDocumentation("signatureAdd_Signature1_Param2")
                            },
                            {
                                label: "...",
                                documentation: this.documentation.getDocumentation("signatureAdd_Signature1_Param3")
                            },
                            {
                                label: "\"dest\"",
                                documentation: this.documentation.getDocumentation("signatureAdd_Signature1_Param4")
                            },
                            {
                                label: "]"
                            }
                        ]
                    };
                    return this.getJSONInstructionSignatureHelp(document, add, position, [addJsonSignature], addShellSignature, true, false, false, false);
                case "ARG":
                    var argSignatureHelp = {
                        signatures: [
                            {
                                label: "ARG name",
                                documentation: this.documentation.getDocumentation("signatureArg_Signature0"),
                                parameters: [
                                    {
                                        label: "name",
                                        documentation: this.documentation.getDocumentation("signatureArg_Signature0_Param")
                                    }
                                ]
                            },
                            {
                                label: "ARG name=defaultValue",
                                documentation: this.documentation.getDocumentation("signatureArg_Signature1"),
                                parameters: [
                                    {
                                        label: "name",
                                        documentation: this.documentation.getDocumentation("signatureArg_Signature1_Param0")
                                    },
                                    {
                                        label: "defaultValue",
                                        documentation: this.documentation.getDocumentation("signatureArg_Signature1_Param1")
                                    }
                                ]
                            }
                        ],
                        activeSignature: 0,
                        activeParameter: 0
                    };
                    var content = instruction.getTextContent();
                    var index = content.indexOf('=');
                    if (index !== -1) {
                        argSignatureHelp = {
                            signatures: [
                                {
                                    label: "ARG name=defaultValue",
                                    documentation: this.documentation.getDocumentation("signatureArg_Signature1"),
                                    parameters: [
                                        {
                                            label: "name",
                                            documentation: this.documentation.getDocumentation("signatureArg_Signature1_Param0")
                                        },
                                        {
                                            label: "defaultValue",
                                            documentation: this.documentation.getDocumentation("signatureArg_Signature1_Param1")
                                        }
                                    ]
                                }
                            ],
                            activeSignature: 0,
                            activeParameter: 0
                        };
                        if (document.offsetAt(position) > document.offsetAt(instruction.getRange().start) + index) {
                            argSignatureHelp.activeParameter = 1;
                        }
                    }
                    return argSignatureHelp;
                case "CMD":
                    var cmd = instruction;
                    var cmdJsonExecutableSignature = {
                        label: "CMD [ \"executable\", \"parameter\", ... ]",
                        documentation: this.documentation.getDocumentation("signatureCmd_Signature0"),
                        parameters: [
                            {
                                label: "["
                            },
                            {
                                label: "\"executable\"",
                                documentation: this.documentation.getDocumentation("signatureCmd_Signature0_Param1")
                            },
                            {
                                label: "\"parameter\"",
                                documentation: this.documentation.getDocumentation("signatureCmd_Signature0_Param2")
                            },
                            {
                                label: "...",
                                documentation: this.documentation.getDocumentation("signatureCmd_Signature0_Param3")
                            },
                            {
                                label: "]"
                            }
                        ]
                    };
                    var cmdJsonParameterSignature = {
                        label: "CMD [ \"parameter\", \"parameter2\", ... ]",
                        documentation: this.documentation.getDocumentation("signatureCmd_Signature1"),
                        parameters: [
                            {
                                label: "["
                            },
                            {
                                label: "\"parameter\"",
                                documentation: this.documentation.getDocumentation("signatureCmd_Signature1_Param1")
                            },
                            {
                                label: "\"parameter2\"",
                                documentation: this.documentation.getDocumentation("signatureCmd_Signature1_Param2")
                            },
                            {
                                label: "...",
                                documentation: this.documentation.getDocumentation("signatureCmd_Signature1_Param3")
                            },
                            {
                                label: "]"
                            }
                        ]
                    };
                    var cmdShellSignature = {
                        label: "CMD executable parameter ...",
                        documentation: this.documentation.getDocumentation("signatureCmd_Signature2"),
                        parameters: [
                            {
                                label: "executable",
                                documentation: this.documentation.getDocumentation("signatureCmd_Signature2_Param0")
                            },
                            {
                                label: "parameter",
                                documentation: this.documentation.getDocumentation("signatureCmd_Signature2_Param1")
                            },
                            {
                                label: "...",
                                documentation: this.documentation.getDocumentation("signatureCmd_Signature2_Param2")
                            }
                        ]
                    };
                    return this.getJSONInstructionSignatureHelp(document, cmd, position, [cmdJsonExecutableSignature, cmdJsonParameterSignature], cmdShellSignature, false, true, false, true);
                case "COPY":
                    var copy = instruction;
                    var flag = copy.getFromFlag();
                    if (flag !== null) {
                        var range = flag.getValueRange();
                        if (range !== null && docker_1.Util.isInsideRange(position, range)) {
                            return {
                                signatures: [
                                    {
                                        label: "--from=stage",
                                        documentation: this.documentation.getDocumentation("signatureCopyFlagFrom"),
                                        parameters: [
                                            {
                                                label: "stage",
                                                documentation: this.documentation.getDocumentation("signatureCopyFlagFrom_Param")
                                            }
                                        ]
                                    }
                                ],
                                activeSignature: 0,
                                activeParameter: 0
                            };
                        }
                    }
                    var copyShellSignature = {
                        label: "COPY [flags] source ... dest",
                        documentation: this.documentation.getDocumentation("signatureCopy_Signature0"),
                        parameters: [
                            {
                                label: "[flags]",
                                documentation: this.documentation.getDocumentation("signatureCopy_Signature0_Param0")
                            },
                            {
                                label: "source",
                                documentation: this.documentation.getDocumentation("signatureCopy_Signature0_Param1")
                            },
                            {
                                label: "...",
                                documentation: this.documentation.getDocumentation("signatureCopy_Signature0_Param2")
                            },
                            {
                                label: "dest",
                                documentation: this.documentation.getDocumentation("signatureCopy_Signature0_Param3")
                            }
                        ]
                    };
                    var copyJsonSignature = {
                        label: "COPY [flags] [ \"source\", ..., \"dest\" ]",
                        documentation: this.documentation.getDocumentation("signatureCopy_Signature1"),
                        parameters: [
                            {
                                label: "[flags]",
                                documentation: this.documentation.getDocumentation("signatureCopy_Signature1_Param0")
                            },
                            {
                                label: "["
                            },
                            {
                                label: "\"source\"",
                                documentation: this.documentation.getDocumentation("signatureCopy_Signature1_Param2")
                            },
                            {
                                label: "...",
                                documentation: this.documentation.getDocumentation("signatureCopy_Signature1_Param3")
                            },
                            {
                                label: "\"dest\"",
                                documentation: this.documentation.getDocumentation("signatureCopy_Signature1_Param4")
                            },
                            {
                                label: "]"
                            }
                        ]
                    };
                    return this.getJSONInstructionSignatureHelp(document, copy, position, [copyJsonSignature], copyShellSignature, true, false, false, false);
                case "ENTRYPOINT":
                    var entrypoint = instruction;
                    var entrypointJsonSignature = {
                        label: "ENTRYPOINT [ \"executable\", \"parameter\", ... ]",
                        documentation: this.documentation.getDocumentation("signatureEntrypoint_Signature0"),
                        parameters: [
                            {
                                label: "["
                            },
                            {
                                label: "\"executable\"",
                                documentation: this.documentation.getDocumentation("signatureEntrypoint_Signature0_Param1")
                            },
                            {
                                label: "\"parameter\"",
                                documentation: this.documentation.getDocumentation("signatureEntrypoint_Signature0_Param2")
                            },
                            {
                                label: "...",
                                documentation: this.documentation.getDocumentation("signatureEntrypoint_Signature0_Param3")
                            },
                            {
                                label: "]"
                            }
                        ]
                    };
                    var entrypointShellSignature = {
                        label: "ENTRYPOINT executable parameter ...",
                        documentation: this.documentation.getDocumentation("signatureEntrypoint_Signature1"),
                        parameters: [
                            {
                                label: "executable",
                                documentation: this.documentation.getDocumentation("signatureEntrypoint_Signature1_Param0")
                            },
                            {
                                label: "parameter",
                                documentation: this.documentation.getDocumentation("signatureEntrypoint_Signature1_Param1")
                            },
                            {
                                label: "...",
                                documentation: this.documentation.getDocumentation("signatureEntrypoint_Signature1_Param2")
                            }
                        ]
                    };
                    return this.getJSONInstructionSignatureHelp(document, entrypoint, position, [entrypointJsonSignature], entrypointShellSignature, false, true, false, true);
                case "ENV":
                    var envSignatures = [
                        {
                            label: "ENV key value",
                            documentation: this.documentation.getDocumentation("signatureEnv_Signature0"),
                            parameters: [
                                {
                                    label: "key",
                                    documentation: this.documentation.getDocumentation("signatureEnv_Signature0_Param0")
                                },
                                {
                                    label: "value",
                                    documentation: this.documentation.getDocumentation("signatureEnv_Signature0_Param1")
                                }
                            ]
                        },
                        {
                            label: "ENV key=value",
                            documentation: this.documentation.getDocumentation("signatureEnv_Signature1"),
                            parameters: [
                                {
                                    label: "key",
                                    documentation: this.documentation.getDocumentation("signatureEnv_Signature1_Param0")
                                },
                                {
                                    label: "value",
                                    documentation: this.documentation.getDocumentation("signatureEnv_Signature1_Param1")
                                }
                            ]
                        },
                        {
                            label: "ENV key=value key2=value2",
                            documentation: this.documentation.getDocumentation("signatureEnv_Signature2"),
                            parameters: [
                                {
                                    label: "key",
                                    documentation: this.documentation.getDocumentation("signatureEnv_Signature2_Param0")
                                },
                                {
                                    label: "value",
                                    documentation: this.documentation.getDocumentation("signatureEnv_Signature2_Param1")
                                },
                                {
                                    label: "key2",
                                    documentation: this.documentation.getDocumentation("signatureEnv_Signature2_Param2")
                                },
                                {
                                    label: "value2",
                                    documentation: this.documentation.getDocumentation("signatureEnv_Signature2_Param3")
                                }
                            ]
                        }
                    ];
                    return this.getPropertySignatureHelp(document, position, envSignatures, instruction.getProperties());
                case "EXPOSE":
                    var exposeSignatureHelp = {
                        signatures: [
                            {
                                label: "EXPOSE port ...",
                                documentation: this.documentation.getDocumentation("signatureExpose"),
                                parameters: [
                                    {
                                        label: "port",
                                        documentation: this.documentation.getDocumentation("signatureExpose_Param0")
                                    },
                                    {
                                        label: "...",
                                        documentation: this.documentation.getDocumentation("signatureExpose_Param1")
                                    }
                                ]
                            }
                        ],
                        activeSignature: 0,
                        activeParameter: 0
                    };
                    var exposeArgs = instruction.getArguments();
                    if (exposeArgs.length > 0 && document.offsetAt(position) > document.offsetAt(exposeArgs[0].getRange().end)) {
                        exposeSignatureHelp.activeParameter = 1;
                    }
                    return exposeSignatureHelp;
                case "FROM":
                    return this.getFromSignatureHelp(position, instruction);
                case "HEALTHCHECK":
                    var healthcheckCmdEmptySignature = {
                        label: "HEALTHCHECK [flags] CMD ...",
                        documentation: this.documentation.getDocumentation("signatureHealthcheck_Signature0"),
                        parameters: [
                            {
                                label: "CMD"
                            }
                        ]
                    };
                    var healthcheckCmdNormalSignature = {
                        label: "HEALTHCHECK [flags] CMD ...",
                        documentation: this.documentation.getDocumentation("signatureHealthcheck_Signature1"),
                        parameters: [
                            {
                                label: "[flags]",
                                documentation: this.documentation.getDocumentation("signatureHealthcheck_Signature1_Param0")
                            },
                            {
                                label: "CMD"
                            },
                            {
                                label: "...",
                                documentation: this.documentation.getDocumentation("signatureHealthcheck_Signature1_Param2")
                            }
                        ]
                    };
                    var healthcheckNoneSignature = {
                        label: "HEALTHCHECK NONE",
                        documentation: this.documentation.getDocumentation("signatureHealthcheck_Signature2"),
                        parameters: [
                            {
                                label: "NONE"
                            }
                        ]
                    };
                    var healthcheck = instruction;
                    var flags = healthcheck.getFlags();
                    for (var _a = 0, flags_1 = flags; _a < flags_1.length; _a++) {
                        var flag_1 = flags_1[_a];
                        var range = flag_1.getValueRange();
                        if (range !== null && docker_1.Util.isInsideRange(position, range)) {
                            switch (flag_1.getName()) {
                                case "interval":
                                    return {
                                        signatures: [
                                            {
                                                label: "HEALTHCHECK --interval=30s ...",
                                                documentation: this.documentation.getDocumentation("signatureHealthcheck"),
                                                parameters: [
                                                    {
                                                        label: "30s",
                                                        documentation: this.documentation.getDocumentation("signatureHealthcheckFlagInterval_Param")
                                                    }
                                                ]
                                            }
                                        ],
                                        activeSignature: 0,
                                        activeParameter: 0
                                    };
                                case "retries":
                                    return {
                                        signatures: [
                                            {
                                                label: "HEALTHCHECK --retries=3 ...",
                                                documentation: this.documentation.getDocumentation("signatureHealthcheck"),
                                                parameters: [
                                                    {
                                                        label: "3",
                                                        documentation: this.documentation.getDocumentation("signatureHealthcheckFlagRetries_Param")
                                                    }
                                                ]
                                            }
                                        ],
                                        activeSignature: 0,
                                        activeParameter: 0
                                    };
                                case "start-period":
                                    return {
                                        signatures: [
                                            {
                                                label: "HEALTHCHECK --start-period=5s ...",
                                                documentation: this.documentation.getDocumentation("signatureHealthcheck"),
                                                parameters: [
                                                    {
                                                        label: "5s",
                                                        documentation: this.documentation.getDocumentation("signatureHealthcheckFlagStartPeriod_Param")
                                                    }
                                                ]
                                            }
                                        ],
                                        activeSignature: 0,
                                        activeParameter: 0
                                    };
                                case "timeout":
                                    return {
                                        signatures: [
                                            {
                                                label: "HEALTHCHECK --timeout=30s ...",
                                                documentation: this.documentation.getDocumentation("signatureHealthcheck"),
                                                parameters: [
                                                    {
                                                        label: "30s",
                                                        documentation: this.documentation.getDocumentation("signatureHealthcheckFlagTimeout_Param")
                                                    }
                                                ]
                                            }
                                        ],
                                        activeSignature: 0,
                                        activeParameter: 0
                                    };
                            }
                            break;
                        }
                    }
                    var healthcheckArgs = healthcheck.getArguments();
                    if (flags.length == 0 && healthcheckArgs.length === 0) {
                        // no flags or args, suggest both CMD and NONE
                        return {
                            signatures: [
                                healthcheckCmdEmptySignature,
                                healthcheckNoneSignature
                            ],
                            activeSignature: 0,
                            activeParameter: 0
                        };
                    }
                    var subcommand = healthcheck.getSubcommand();
                    if (subcommand === null) {
                        return {
                            signatures: [
                                healthcheckCmdNormalSignature
                            ],
                            activeSignature: 0,
                            activeParameter: 0
                        };
                    }
                    var beforeSubcommand = subcommand.isBefore(position);
                    var afterSubcommand = subcommand.isAfter(position);
                    var subcommandValue = subcommand.getValue();
                    if ("NONE".indexOf(subcommandValue.toUpperCase()) === 0) {
                        if (beforeSubcommand) {
                            // after a NONE, nothing to show
                            return null;
                        }
                        return {
                            signatures: [
                                healthcheckNoneSignature
                            ],
                            activeSignature: 0,
                            activeParameter: 0
                        };
                    }
                    var activeHealthcheckParameter = beforeSubcommand ? 2 : afterSubcommand ? 0 : 1;
                    return {
                        signatures: [
                            healthcheckCmdNormalSignature
                        ],
                        activeSignature: 0,
                        activeParameter: activeHealthcheckParameter
                    };
                case "LABEL":
                    var labelSignatures = [
                        {
                            label: "LABEL key value",
                            documentation: this.documentation.getDocumentation("signatureLabel_Signature0"),
                            parameters: [
                                {
                                    label: "key",
                                    documentation: this.documentation.getDocumentation("signatureLabel_Signature0_Param0")
                                },
                                {
                                    label: "value",
                                    documentation: this.documentation.getDocumentation("signatureLabel_Signature0_Param1")
                                }
                            ]
                        },
                        {
                            label: "LABEL key=value",
                            documentation: this.documentation.getDocumentation("signatureLabel_Signature1"),
                            parameters: [
                                {
                                    label: "key",
                                    documentation: this.documentation.getDocumentation("signatureLabel_Signature1_Param0")
                                },
                                {
                                    label: "value",
                                    documentation: this.documentation.getDocumentation("signatureLabel_Signature1_Param1")
                                }
                            ]
                        },
                        {
                            label: "LABEL key=value key2=value2",
                            documentation: this.documentation.getDocumentation("signatureLabel_Signature2"),
                            parameters: [
                                {
                                    label: "key",
                                    documentation: this.documentation.getDocumentation("signatureLabel_Signature2_Param0")
                                },
                                {
                                    label: "value",
                                    documentation: this.documentation.getDocumentation("signatureLabel_Signature2_Param1")
                                },
                                {
                                    label: "key2",
                                    documentation: this.documentation.getDocumentation("signatureLabel_Signature2_Param2")
                                },
                                {
                                    label: "value2",
                                    documentation: this.documentation.getDocumentation("signatureLabel_Signature2_Param3")
                                }
                            ]
                        }
                    ];
                    return this.getPropertySignatureHelp(document, position, labelSignatures, instruction.getProperties());
                case "MAINTAINER":
                    return {
                        signatures: [
                            {
                                label: "MAINTAINER name",
                                documentation: this.documentation.getDocumentation("signatureMaintainer"),
                                parameters: [
                                    {
                                        label: "name",
                                        documentation: this.documentation.getDocumentation("signatureMaintainer_Param")
                                    }
                                ]
                            }
                        ],
                        activeSignature: 0,
                        activeParameter: 0
                    };
                case "ONBUILD":
                    var onbuildArgs = instruction.getArguments();
                    if (onbuildArgs.length > 0 && onbuildArgs[0].isBefore(position)) {
                        return null;
                    }
                    return {
                        signatures: [
                            {
                                label: "ONBUILD INSTRUCTION",
                                documentation: this.documentation.getDocumentation("signatureOnbuild"),
                                parameters: [
                                    {
                                        label: "INSTRUCTION",
                                        documentation: this.documentation.getDocumentation("signatureOnbuild_Param")
                                    }
                                ]
                            }
                        ],
                        activeSignature: 0,
                        activeParameter: 0
                    };
                case "RUN":
                    var run_1 = instruction;
                    var runShellSignature = {
                        label: "RUN command parameter ...",
                        documentation: this.documentation.getDocumentation("signatureRun_Signature0"),
                        parameters: [
                            {
                                label: "command",
                                documentation: this.documentation.getDocumentation("signatureRun_Signature0_Param0")
                            },
                            {
                                label: "parameter",
                                documentation: this.documentation.getDocumentation("signatureRun_Signature0_Param1")
                            },
                            {
                                label: "...",
                                documentation: this.documentation.getDocumentation("signatureRun_Signature0_Param2")
                            }
                        ]
                    };
                    var runJsonSignature = {
                        label: "RUN [ \"command\", \"parameter\", ... ]",
                        documentation: this.documentation.getDocumentation("signatureRun_Signature1"),
                        parameters: [
                            {
                                label: "["
                            },
                            {
                                label: "\"command\"",
                                documentation: this.documentation.getDocumentation("signatureRun_Signature1_Param1")
                            },
                            {
                                label: "\"parameter\"",
                                documentation: this.documentation.getDocumentation("signatureRun_Signature1_Param2")
                            },
                            {
                                label: "...",
                                documentation: this.documentation.getDocumentation("signatureRun_Signature1_Param3")
                            },
                            {
                                label: "]"
                            }
                        ]
                    };
                    return this.getJSONInstructionSignatureHelp(document, run_1, position, [runJsonSignature], runShellSignature, false, false, false, true);
                case "SHELL":
                    var shell = instruction;
                    var shellSignatureHelp = {
                        signatures: [
                            {
                                label: "SHELL [ \"executable\", \"parameter\", ... ]",
                                documentation: this.documentation.getDocumentation("signatureShell"),
                                parameters: [
                                    {
                                        label: "["
                                    },
                                    {
                                        label: "\"executable\"",
                                        documentation: this.documentation.getDocumentation("signatureShell_Param1")
                                    },
                                    {
                                        label: "\"parameter\"",
                                        documentation: this.documentation.getDocumentation("signatureShell_Param2")
                                    },
                                    {
                                        label: "...",
                                        documentation: this.documentation.getDocumentation("signatureShell_Param3")
                                    },
                                    {
                                        label: "]"
                                    }
                                ]
                            }
                        ],
                        activeSignature: 0,
                        activeParameter: null
                    };
                    shellSignatureHelp.activeParameter = this.getJSONSignatureActiveParameter(document, shell, position, false, false, true);
                    return shellSignatureHelp.activeParameter === -1 ? null : shellSignatureHelp;
                case "STOPSIGNAL":
                    return {
                        signatures: [
                            {
                                label: "STOPSIGNAL signal",
                                documentation: this.documentation.getDocumentation("signatureStopsignal"),
                                parameters: [
                                    {
                                        label: "signal",
                                        documentation: this.documentation.getDocumentation("signatureStopsignal_Param")
                                    }
                                ]
                            }
                        ],
                        activeSignature: 0,
                        activeParameter: 0
                    };
                case "USER":
                    var userSignatureHelp = {
                        signatures: [
                            {
                                label: "USER user",
                                documentation: this.documentation.getDocumentation("signatureUser_Signature0"),
                                parameters: [
                                    {
                                        label: "user",
                                        documentation: this.documentation.getDocumentation("signatureUser_Signature0_Param")
                                    }
                                ]
                            },
                            {
                                label: "USER user:group",
                                documentation: this.documentation.getDocumentation("signatureUser_Signature1"),
                                parameters: [
                                    {
                                        label: "user",
                                        documentation: this.documentation.getDocumentation("signatureUser_Signature1_Param0")
                                    },
                                    {
                                        label: "group",
                                        documentation: this.documentation.getDocumentation("signatureUser_Signature1_Param1")
                                    }
                                ]
                            },
                            {
                                label: "USER uid",
                                documentation: this.documentation.getDocumentation("signatureUser_Signature2"),
                                parameters: [
                                    {
                                        label: "uid",
                                        documentation: this.documentation.getDocumentation("signatureUser_Signature2_Param")
                                    }
                                ]
                            },
                            {
                                label: "USER uid:gid",
                                documentation: this.documentation.getDocumentation("signatureUser_Signature3"),
                                parameters: [
                                    {
                                        label: "uid",
                                        documentation: this.documentation.getDocumentation("signatureUser_Signature3_Param0")
                                    },
                                    {
                                        label: "gid",
                                        documentation: this.documentation.getDocumentation("signatureUser_Signature3_Param1")
                                    }
                                ]
                            }
                        ],
                        activeSignature: 0,
                        activeParameter: 0
                    };
                    var userSeparatorIndex = instruction.getTextContent().indexOf(":");
                    if (userSeparatorIndex !== -1) {
                        userSignatureHelp = {
                            signatures: [
                                {
                                    label: "USER user:group",
                                    documentation: this.documentation.getDocumentation("signatureUser_Signature1"),
                                    parameters: [
                                        {
                                            label: "user",
                                            documentation: this.documentation.getDocumentation("signatureUser_Signature1_Param0")
                                        },
                                        {
                                            label: "group",
                                            documentation: this.documentation.getDocumentation("signatureUser_Signature1_Param1")
                                        }
                                    ]
                                },
                                {
                                    label: "USER uid:gid",
                                    documentation: this.documentation.getDocumentation("signatureUser_Signature3"),
                                    parameters: [
                                        {
                                            label: "uid",
                                            documentation: this.documentation.getDocumentation("signatureUser_Signature3_Param0")
                                        },
                                        {
                                            label: "gid",
                                            documentation: this.documentation.getDocumentation("signatureUser_Signature3_Param1")
                                        }
                                    ]
                                }
                            ],
                            activeSignature: 0,
                            activeParameter: 0
                        };
                        if (document.offsetAt(position) > document.offsetAt(instruction.getRange().start) + userSeparatorIndex) {
                            userSignatureHelp.activeParameter = 1;
                        }
                    }
                    return userSignatureHelp;
                case "VOLUME":
                    var volume = instruction;
                    var volumeJsonSignature = {
                        label: "VOLUME [ \"/vol\", ... ]",
                        documentation: this.documentation.getDocumentation("signatureVolume_Signature1"),
                        parameters: [
                            {
                                label: "["
                            },
                            {
                                label: "\"/vol\"",
                                documentation: this.documentation.getDocumentation("signatureVolume_Signature1_Param1")
                            },
                            {
                                label: "...",
                                documentation: this.documentation.getDocumentation("signatureVolume_Signature1_Param2")
                            },
                            {
                                label: "]"
                            }
                        ]
                    };
                    var volumeShellSignature = {
                        label: "VOLUME /vol ...",
                        documentation: this.documentation.getDocumentation("signatureVolume_Signature0"),
                        parameters: [
                            {
                                label: "/vol",
                                documentation: this.documentation.getDocumentation("signatureVolume_Signature0_Param0")
                            },
                            {
                                label: "...",
                                documentation: this.documentation.getDocumentation("signatureVolume_Signature0_Param1")
                            }
                        ]
                    };
                    return this.getJSONInstructionSignatureHelp(document, volume, position, [volumeJsonSignature], volumeShellSignature, false, true, true, true);
                case "WORKDIR":
                    return {
                        signatures: [
                            {
                                label: "WORKDIR /the/workdir/path",
                                documentation: this.documentation.getDocumentation("signatureWorkdir"),
                                parameters: [
                                    {
                                        label: "/the/workdir/path",
                                        documentation: this.documentation.getDocumentation("signatureWorkdir_Param")
                                    }
                                ]
                            }
                        ],
                        activeSignature: 0,
                        activeParameter: 0
                    };
            }
        }
        return null;
    };
    DockerSignatures.prototype.getFromSignatureHelp = function (position, from) {
        var baseImage = {
            label: "FROM baseImage",
            documentation: this.documentation.getDocumentation("signatureFrom_Signature0"),
            parameters: [
                {
                    label: "baseImage",
                    documentation: this.documentation.getDocumentation("signatureFrom_Signature0_Param")
                }
            ]
        };
        var baseImageTag = {
            label: "FROM baseImage:tag",
            documentation: this.documentation.getDocumentation("signatureFrom_Signature1"),
            parameters: [
                {
                    label: "baseImage",
                    documentation: this.documentation.getDocumentation("signatureFrom_Signature1_Param0")
                },
                {
                    label: "tag",
                    documentation: this.documentation.getDocumentation("signatureFrom_Signature1_Param1")
                }
            ]
        };
        var baseImageDigest = {
            label: "FROM baseImage@digest",
            documentation: this.documentation.getDocumentation("signatureFrom_Signature2"),
            parameters: [
                {
                    label: "baseImage",
                    documentation: this.documentation.getDocumentation("signatureFrom_Signature2_Param0")
                },
                {
                    label: "digest",
                    documentation: this.documentation.getDocumentation("signatureFrom_Signature2_Param1")
                }
            ]
        };
        var baseImageStage = {
            label: "FROM baseImage AS stage",
            documentation: this.documentation.getDocumentation("signatureFrom_Signature3"),
            parameters: [
                {
                    label: "baseImage",
                    documentation: this.documentation.getDocumentation("signatureFrom_Signature3_Param0")
                },
                {
                    // placeholder parameter to get the activeParameter to line
                    // up with all three signature types of FROM
                    // see rcjsuen/dockerfile-language-service#8
                    label: ""
                },
                {
                    label: "AS",
                },
                {
                    label: "stage",
                    documentation: this.documentation.getDocumentation("signatureFrom_Signature3_Param2")
                }
            ]
        };
        var baseImageTagStage = {
            label: "FROM baseImage:tag AS stage",
            documentation: this.documentation.getDocumentation("signatureFrom_Signature4"),
            parameters: [
                {
                    label: "baseImage",
                    documentation: this.documentation.getDocumentation("signatureFrom_Signature4_Param0")
                },
                {
                    label: "tag",
                    documentation: this.documentation.getDocumentation("signatureFrom_Signature4_Param1")
                },
                {
                    label: "AS",
                },
                {
                    label: "stage",
                    documentation: this.documentation.getDocumentation("signatureFrom_Signature4_Param3")
                }
            ]
        };
        var baseImageDigestStage = {
            label: "FROM baseImage@digest AS stage",
            documentation: this.documentation.getDocumentation("signatureFrom_Signature5"),
            parameters: [
                {
                    label: "baseImage",
                    documentation: this.documentation.getDocumentation("signatureFrom_Signature5_Param0")
                },
                {
                    label: "digest",
                    documentation: this.documentation.getDocumentation("signatureFrom_Signature5_Param1")
                },
                {
                    label: "AS",
                },
                {
                    label: "stage",
                    documentation: this.documentation.getDocumentation("signatureFrom_Signature5_Param3")
                }
            ]
        };
        var fromSignatures = [
            baseImage, baseImageTag, baseImageDigest,
            baseImageStage, baseImageTagStage, baseImageDigestStage
        ];
        var args = from.getArguments();
        if (args.length >= 3 && args[2].isBefore(position)) {
            return null;
        }
        else if (args.length === 0) {
            return {
                signatures: fromSignatures,
                activeSignature: 0,
                activeParameter: 0
            };
        }
        var image = args[0].getValue();
        var digest = image.indexOf('@') !== -1;
        var tag = !digest && image.indexOf(':') !== -1;
        var stagesOnly = args.length > 1 || args[0].isBefore(position);
        return {
            signatures: this.getFromSignatures(fromSignatures, tag, digest, stagesOnly),
            activeSignature: 0,
            activeParameter: this.getFromActiveParameter(position, from, tag, digest, args)
        };
    };
    DockerSignatures.prototype.getFromSignatures = function (fromSignatures, tag, digest, stagesOnly) {
        if (digest) {
            return stagesOnly ? [fromSignatures[5]] : [fromSignatures[2], fromSignatures[5]];
        }
        else if (tag) {
            return stagesOnly ? [fromSignatures[4]] : [fromSignatures[1], fromSignatures[4]];
        }
        return stagesOnly ? [fromSignatures[3], fromSignatures[4], fromSignatures[5]] : fromSignatures;
    };
    DockerSignatures.prototype.getFromActiveParameter = function (position, from, tag, digest, args) {
        var inTag = tag && docker_1.Util.isInsideRange(position, from.getImageTagRange());
        var inDigest = digest && docker_1.Util.isInsideRange(position, from.getImageDigestRange());
        if (args.length === 1) {
            if (args[0].isBefore(position)) {
                return 2;
            }
        }
        else if (args.length === 2) {
            if (args[1].isBefore(position)) {
                return 3;
            }
            else if (docker_1.Util.isInsideRange(position, args[1].getRange()) || args[0].isBefore(position)) {
                return 2;
            }
        }
        else {
            if (docker_1.Util.isInsideRange(position, args[2].getRange()) || args[1].isBefore(position)) {
                return 3;
            }
            else if (docker_1.Util.isInsideRange(position, args[1].getRange()) || args[0].isBefore(position)) {
                return 2;
            }
        }
        return inTag || inDigest ? 1 : 0;
    };
    DockerSignatures.prototype.getJSONInstructionSignatureHelp = function (document, instruction, position, jsonSignatures, shellSignature, hasFlags, jsonFirst, singleParameter, finalRepeats) {
        var activeParameter = this.getJSONSignatureActiveParameter(document, instruction, position, hasFlags, singleParameter, finalRepeats);
        if (activeParameter === -1) {
            activeParameter = this.getSignatureActiveParameter(instruction, position, hasFlags, singleParameter ? 1 : 2, finalRepeats);
            return {
                signatures: [shellSignature],
                activeSignature: 0,
                activeParameter: activeParameter
            };
        }
        else if (activeParameter === 0) {
            if (jsonFirst) {
                jsonSignatures.push(shellSignature);
                return {
                    signatures: jsonSignatures,
                    activeSignature: 0,
                    activeParameter: 0
                };
            }
            jsonSignatures.unshift(shellSignature);
            return {
                signatures: jsonSignatures,
                activeSignature: 0,
                activeParameter: 0
            };
        }
        else if (activeParameter === 1 && hasFlags) {
            if (jsonFirst) {
                jsonSignatures.push(shellSignature);
                return {
                    signatures: jsonSignatures,
                    activeSignature: 0,
                    activeParameter: 1
                };
            }
            jsonSignatures.unshift(shellSignature);
            return {
                signatures: jsonSignatures,
                activeSignature: 0,
                activeParameter: 1
            };
        }
        return {
            signatures: jsonSignatures,
            activeSignature: 0,
            activeParameter: activeParameter
        };
    };
    DockerSignatures.prototype.getJSONSignatureActiveParameter = function (document, instruction, position, hasFlags, singleParameter, finalRepeats) {
        var flagsOffset = hasFlags ? 1 : 0;
        if (hasFlags) {
            var flags = instruction.getFlags();
            if (flags.length > 0) {
                var flagPosition = flags[flags.length - 1].getRange().end;
                if (docker_1.Util.positionBefore(position, flagPosition) || docker_1.Util.positionEquals(position, flagPosition)) {
                    return 0;
                }
            }
        }
        var closingBracket = instruction.getClosingBracket();
        if (closingBracket) {
            var range = closingBracket.getRange();
            if (range.end.line === position.line && range.end.character === position.character) {
                if (singleParameter) {
                    return 3 + flagsOffset;
                }
                return 4 + flagsOffset;
            }
            else if (closingBracket.isBefore(position)) {
                return -1;
            }
        }
        var jsonStrings = instruction.getJSONStrings();
        if (!singleParameter && jsonStrings.length > 1 && jsonStrings[1].isBefore(position)) {
            if (jsonStrings.length === 2) {
                return 3 + flagsOffset;
            }
            if (finalRepeats || docker_1.Util.isInsideRange(position, jsonStrings[jsonStrings.length - 1].getRange())) {
                return 3 + flagsOffset;
            }
            return 2 + flagsOffset;
        }
        if (jsonStrings.length > 0 && jsonStrings[0].isBefore(position)) {
            if (jsonStrings.length > 2) {
                return 2 + flagsOffset;
            }
            var start = document.offsetAt(jsonStrings[0].getRange().end);
            var end = document.offsetAt(position);
            var between = document.getText().substring(start, end);
            if (between.indexOf(',') === -1) {
                return 1 + flagsOffset;
            }
            if (finalRepeats) {
                return 2 + flagsOffset;
            }
            return 3 + flagsOffset;
        }
        var openingBracket = instruction.getOpeningBracket();
        if (openingBracket) {
            var range = openingBracket.getRange();
            if ((range.end.line === position.line && range.end.character === position.character) || openingBracket.isBefore(position)) {
                return 1 + flagsOffset;
            }
            return 0 + flagsOffset;
        }
        else if (instruction.getArguments().length === 0) {
            return 0 + flagsOffset;
        }
        return -1;
    };
    DockerSignatures.prototype.getSignatureActiveParameter = function (instruction, position, hasFlags, max, finalRepeats) {
        var flagsOffset = hasFlags ? 1 : 0;
        var args = instruction.getArguments();
        if (finalRepeats) {
            for (var i = args.length - 1; i >= 0; i--) {
                if (args[i].isBefore(position)) {
                    return Math.min(i + 1, max) + flagsOffset;
                }
                else if (docker_1.Util.isInsideRange(position, args[i].getRange())) {
                    return Math.min(i, max) + flagsOffset;
                }
            }
        }
        switch (args.length) {
            case 1:
                if (args[0].isBefore(position)) {
                    return 2 + flagsOffset;
                }
                return 0 + flagsOffset;
            default:
                if (args[args.length - 1].isBefore(position) || docker_1.Util.isInsideRange(position, args[args.length - 1].getRange())) {
                    return 2 + flagsOffset;
                }
                else if (args[0].isBefore(position)) {
                    return 1 + flagsOffset;
                }
                return 0 + flagsOffset;
        }
    };
    DockerSignatures.prototype.getPropertySignatureHelp = function (document, position, signatures, properties) {
        return {
            signatures: this.getPropertySignatures(document, position, signatures, properties),
            activeSignature: 0,
            activeParameter: this.getPropertySignatureActiveParameter(document, position, properties)
        };
    };
    DockerSignatures.prototype.getPropertySignatures = function (document, position, signatures, properties) {
        if (properties.length === 0) {
            return signatures;
        }
        else if (properties.length === 1) {
            var valueRange = properties[0].getValueRange();
            if (valueRange === null) {
                return DockerSignatures.isNameBefore(properties[0], position) ? [signatures[0]] : signatures;
            }
            var delimiter = document.getText().substring(document.offsetAt(properties[0].getNameRange().end), document.offsetAt(valueRange.start));
            if (delimiter.indexOf('=') === -1) {
                return [signatures[0]];
            }
            else if (DockerSignatures.isValueBefore(properties[0], position)) {
                return [signatures[2]];
            }
        }
        else {
            return [signatures[2]];
        }
        return [signatures[1], signatures[2]];
    };
    DockerSignatures.prototype.getPropertySignatureActiveParameter = function (document, position, properties) {
        if (properties.length === 0) {
            return 0;
        }
        for (var i = properties.length - 1; i > 0; i--) {
            if (DockerSignatures.isInValue(properties[i], position)) {
                return 3;
            }
            else if (DockerSignatures.isNameBefore(properties[i], position) || DockerSignatures.isInName(properties[i], position)) {
                return 2;
            }
        }
        if (DockerSignatures.isInValue(properties[0], position)) {
            return 1;
        }
        else if (DockerSignatures.isValueBefore(properties[0], position)) {
            var delimiter = document.getText().substring(document.offsetAt(properties[0].getNameRange().end), document.offsetAt(properties[0].getValueRange().start));
            return delimiter.indexOf('=') === -1 ? 1 : 2;
        }
        return DockerSignatures.isNameBefore(properties[0], position) ? 1 : 0;
    };
    DockerSignatures.isInName = function (property, position) {
        return docker_1.Util.isInsideRange(position, property.getNameRange());
    };
    DockerSignatures.isNameBefore = function (property, position) {
        var range = property.getNameRange();
        if (DockerSignatures.isInName(property, position)) {
            return false;
        }
        else if (range.start.line < position.line) {
            return true;
        }
        return range.start.line === position.line ? range.end.character < position.character : false;
    };
    DockerSignatures.isInValue = function (property, position) {
        var range = property.getValueRange();
        return range ? docker_1.Util.isInsideRange(position, range) : false;
    };
    DockerSignatures.isValueBefore = function (property, position) {
        var range = property.getValueRange();
        if (range === null) {
            return false;
        }
        else if (range.start.line < position.line) {
            return true;
        }
        else if (range.start.line === position.line) {
            if (range.start.line === range.end.line) {
                return range.end.character < position.character;
            }
            return range.start.character < position.character;
        }
        return false;
    };
    return DockerSignatures;
}());
exports.DockerSignatures = DockerSignatures;
