// TODO comment this
        static string GetSignatures(string json)
        {
            dynamic inputJson = JsonConvert.DeserializeObject(json);
            string  document  = inputJson.textDocument;

            int line      = inputJson.caret.line;
            int character = inputJson.caret.character;
            Pos caret     = new Pos(line, character);

            var parser = ParserData.GetParser(document, new Parse.Pos(caret.line, caret.character));

            int methodIndex    = 0;
            int parameterIndex = 0;

            MethodNode methodNode = null;

            SignatureHelp signatures = null;

            if (parser.Success)
            {
                if (parser.Bav.SelectedNode.ElementAtOrDefault(0) is MethodNode)
                {
                    methodNode     = (MethodNode)parser.Bav.SelectedNode[0];
                    parameterIndex = methodNode.Parameters.Length;
                }
                else if (parser.Bav.SelectedNode.ElementAtOrDefault(0) is IExpressionNode &&
                         parser.Bav.SelectedNode.ElementAtOrDefault(1) is MethodNode)
                {
                    methodNode     = (MethodNode)parser.Bav.SelectedNode[1];
                    parameterIndex = Array.IndexOf(methodNode.Parameters, parser.Bav.SelectedNode[0]);
                }

                SignatureInformation information = null;
                if (methodNode != null)
                {
                    Type methodType = Element.GetMethod(methodNode.Name);

                    if (methodType != null)
                    {
                        Element element = (Element)Activator.CreateInstance(methodType);

                        information = new SignatureInformation(
                            element.ToString(),
                            "",
                            element.ParameterData.Select(p =>
                                                         new ParameterInformation(p.Name, "")
                                                         ).ToArray());
                    }
                }

                signatures = new SignatureHelp
                             (
                    new SignatureInformation[] { information },
                    methodIndex,
                    parameterIndex
                             );
            }

            return(JsonConvert.SerializeObject(signatures));
        }
        static string ParseDocument(string document, int clientPort)
        {
            var data = ParserData.GetParser(document, null);

            if (data.Rules != null && data.Diagnostics.Count == 0)
            {
                string final = Program.RuleArrayToWorkshop(data.Rules, data.VarCollection);
                using (var wc = new WebClient())
                {
                    wc.UploadString($"http://localhost:{clientPort}/", final);
                }
            }

            return(JsonConvert.SerializeObject(data.Diagnostics.ToArray()));
        }
        // https://microsoft.github.io/language-server-protocol/specification#textDocument_hover
        static string GetHover(string json)
        {
            dynamic inputJson = JsonConvert.DeserializeObject(json);
            string  document  = inputJson.textDocument;

            int line      = inputJson.caret.line;
            int character = inputJson.caret.character;
            Pos caret     = new Pos(line, character);

            var parser = ParserData.GetParser(document, new Parse.Pos(caret.line, caret.character));

            Hover hover = null;

            if (parser.Success && parser.Bav.SelectedNode.Count > 0)
            {
                switch (parser.Bav.SelectedNode[0])
                {
                case MethodNode methodNode:

                    var type = Translate.GetMethodType(parser.UserMethods, methodNode.Name);

                    if (type == null)
                    {
                        hover = null;
                    }

                    Parameter[] parameters;
                    if (type == Translate.MethodType.Method)
                    {
                        parameters = Element.GetMethod(methodNode.Name).GetCustomAttributes <Parameter>()
                                     .ToArray();
                    }
                    else if (type == Translate.MethodType.CustomMethod)
                    {
                        parameters = CustomMethods.GetCustomMethod(methodNode.Name).GetCustomAttributes <Parameter>()
                                     .ToArray();
                    }
                    else if (type == Translate.MethodType.UserMethod)
                    {
                        parameters = UserMethod.GetUserMethod(parser.UserMethods, methodNode.Name).Parameters;
                    }
                    else
                    {
                        parameters = null;
                    }

                    if (parameters != null)
                    {
                        hover = new Hover(new MarkupContent(MarkupContent.Markdown, methodNode.Name + "(" + Parameter.ParameterGroupToString(parameters) + ")"))
                        {
                            range = methodNode.Range
                        }
                    }
                    ;
                    break;

                default:
                    hover = null;
                    break;
                }
            }

            return(JsonConvert.SerializeObject(hover));
        }
        static string GetAutocomplete(string json)
        {
            /*
             *  Format:
             *      textDocument
             *      caret
             *          caret.line
             *          caret.character
             */
            dynamic inputJson = JsonConvert.DeserializeObject(json);

            string document = inputJson.textDocument;

            int line      = inputJson.caret.line;
            int character = inputJson.caret.character;
            Pos caret     = new Pos(line, character);

            var parser = ParserData.GetParser(document, new Parse.Pos(caret.line, caret.character));

            List <CompletionItem> completion = new List <CompletionItem>();

            switch (parser.Bav?.SelectedNode.FirstOrDefault())
            {
            // Ruleset
            case RulesetNode rulesetNode:

                completion.AddRange(new CompletionItem[]
                {
                    // TODO insert text
                    new CompletionItem("rule")
                    {
                        kind = CompletionItem.Keyword
                    },
                    new CompletionItem("define")
                    {
                        kind = CompletionItem.Keyword
                    },
                    new CompletionItem("method")
                    {
                        kind = CompletionItem.Keyword
                    }
                });
                break;

            // Rule node
            case RuleNode ruleNode:

                // Event type
                if (ruleNode.IsEventOptionSelected())
                {
                    completion.AddRange(EnumData.GetEnum <RuleEvent>().GetCompletion());
                }

                // Player
                else if (ruleNode.IsPlayerOptionSelected())
                {
                    completion.AddRange(EnumData.GetEnum <PlayerSelector>().GetCompletion());
                }

                // Team
                else if (ruleNode.IsTeamOptionSelected())
                {
                    completion.AddRange(EnumData.GetEnum <TeamSelector>().GetCompletion());
                }

                else
                {
                    completion.AddRange(new CompletionItem[]
                    {
                        new CompletionItem("Event")
                        {
                            kind = CompletionItem.Enum
                        },
                        new CompletionItem("Team")
                        {
                            kind = CompletionItem.Enum
                        },
                        new CompletionItem("Player")
                        {
                            kind = CompletionItem.Enum
                        },
                    });
                }
                break;

            // Actions
            case BlockNode blockNode:

                // Get all action methods
                completion.AddRange(Element.ActionList.Select(m =>
                                                              new CompletionItem(m.Name.Substring(2))
                {
                    kind   = CompletionItem.Method,
                    detail = ((Element)Activator.CreateInstance(m)).ToString(),
                }));
                if (parser.Success)
                {
                    // Get all variables
                    if (blockNode.RelatedScopeGroup != null)
                    {
                        completion.AddRange(blockNode.RelatedScopeGroup.GetCompletionItems());
                    }
                    // Get custom methods
                    if (parser.UserMethods != null)
                    {
                        completion.AddRange(UserMethod.CollectionCompletion(parser.UserMethods));
                    }
                }

                break;

            // Values
            case MethodNode methodNode:

                completion.AddRange(Element.ValueList.Select(m =>
                                                             new CompletionItem(m.Name.Substring(2))
                {
                    kind   = CompletionItem.Method,
                    detail = ((Element)Activator.CreateInstance(m)).ToString(),
                }));

                completion.AddRange(EnumData.GetAllEnumCompletion());

                if (parser.Success)
                {
                    // Get all variables
                    if (methodNode.RelatedScopeGroup != null)
                    {
                        completion.AddRange(methodNode.RelatedScopeGroup?.GetCompletionItems());
                    }
                    // Get custom methods
                    if (parser.UserMethods != null)
                    {
                        completion.AddRange(UserMethod.CollectionCompletion(parser.UserMethods));
                    }
                }

                break;

            // If the selected node is a string node, show all strings.
            case StringNode stringNode:

                completion.AddRange(Constants.Strings.Select(str =>
                                                             new CompletionItem(str)
                {
                    kind = CompletionItem.Text
                }
                                                             ));

                break;

            case EnumNode enumNode:
                var add = EnumData.GetEnum(enumNode.Type)?.GetCompletion();

                if (add != null)
                {
                    completion.AddRange(add);
                }

                break;
            }

            return(JsonConvert.SerializeObject(completion.ToArray()));
        }