/// <summary>
        /// Generates the property definitions.
        /// </summary>
        /// <param name="actionInfo">The action information.</param>
        /// <returns></returns>
        public string GeneratePropertyDefinitions(ActionInfo actionInfo)
        {
            string tooltip            = $"{actionInfo.GenerateCommandName()} :";
            var    strPropsDefinition = "";

            foreach (var param in actionInfo.Params)
            {
                var    blocklyType      = param.Value.type.TranslateToBlocklyType();
                var    typeName         = param.Key;
                string blocklyTypeCheck = blocklyType;
                if (blocklyTypeCheck?.Length > 0)
                {
                    blocklyTypeCheck = $"'{blocklyTypeCheck}'";
                }

                if (blocklyTypeCheck == "'Array'")
                {
                    //Dictionary<string,string> is ienumerable, but an object
                    blocklyTypeCheck = "null";
                }

                strPropsDefinition += $@"
                    this.appendValueInput('val_{typeName}')
                    .setCheck({blocklyTypeCheck})
                    .appendField('{typeName}'); ";

                tooltip += $"{typeName}: {blocklyType}";
            }
            if (actionInfo.ReturnType.id != null)
            {
                tooltip += $" returns: {actionInfo.ReturnType.TranslateToBlocklyType()}";
            }

            return(strPropsDefinition + ";" + $" this.setTooltip('{tooltip}');");
        }
        /// <summary>
        /// blockly javascript code for action.
        /// </summary>
        /// <param name="actionInfo">The action information.</param>
        /// <param name="key">key</param>
        /// <returns></returns>
        public string GenerateFunctionJS(ActionInfo actionInfo, string key)
        {
            var    paramsStr     = "";
            var    paramsBodyStr = "";
            string argsXHR       = "";

            string[] argsBody = null;

            if (actionInfo.HasParams)
            {
                argsBody = actionInfo.Params.Where(it => it.Value.bs == BindingSourceDefinition.Body)
                           .Select(it => it.Key)
                           .ToArray();

                if (argsBody.Length > 0)
                {
                    paramsBodyStr = string.Join(Environment.NewLine,
                                                argsBody.Select(it => $"objBody['val_{it}'] =obj['val_{it}'];"));
                }

                paramsStr = string.Join(Environment.NewLine,
                                        actionInfo.Params.Select(param =>

                                                                 $@" 
                        obj['val_{param.Key}'] = Blockly.JavaScript.valueToCode(block, 'val_{param.Key}', Blockly.JavaScript.ORDER_ATOMIC);"
                                                                 )
                                        );


                argsXHR = string.Join(",", actionInfo.Params.Select(param => $@"${{obj['val_{param.Key}']}}"));
            }

            if (argsBody?.Length > 0)
            {
                argsXHR += ",${JSON.stringify(objBody)}";
            }

            var returnValue = " return [code, Blockly.JavaScript.ORDER_NONE];";

            return($@"
                        Blockly.JavaScript['{actionInfo.GenerateCommandName()}'] = function(block) {{
                        var obj={{}};
                        var objBody={{}};
                        {paramsStr}
                        {paramsBodyStr}
                        var code =`{GenerateGet(actionInfo)}({argsXHR})`;
                        {returnValue}
                        }};
                    ");
        }
        /// <summary>
        /// Generates the function definition.
        /// blockly block definition for action
        /// </summary>
        /// <param name="actionInfo">The action information.</param>
        /// <returns></returns>
        public string GenerateFunctionDefinition(ActionInfo actionInfo)
        {
            var strPropsDefinition = GeneratePropertyDefinitions(actionInfo);

            var returnType = $@"this.setOutput(true,'{actionInfo.ReturnType.TranslateToBlocklyType()}');";
            var actionHash = actionInfo.CustomGetHashCode();

            var blockColor = BlocklyStringToColor.ConvertToHue(actionHash);

            return($@"
                Blockly.Blocks['{actionInfo.GenerateCommandName()}'] = {{
                          init: function() {{
                            this.setColour({blockColor});
                            this.appendDummyInput()
                                .appendField('{actionInfo.CommandDisplayName()}');
                                {strPropsDefinition}
                                {returnType}
                                }}//init
                        }};//{actionInfo.ActionName}
                        ");
        }
        /// <summary>
        /// Generates the property definitions.
        /// </summary>
        /// <param name="actionInfo">The action information.</param>
        /// <returns></returns>
        public string GeneratePropertyDefinitions(ActionInfo actionInfo)
        {
            string tooltip            = $"{actionInfo.GenerateCommandName()} :";
            var    strPropsDefinition = "";

            foreach (var param in actionInfo.Params)
            {
                var blocklyType = param.Value.type.TranslateToBlocklyType();
                var typeName    = param.Key;

                strPropsDefinition += $@"
                    this.appendValueInput('val_{typeName}')
                    .setCheck('{blocklyType}')
                    .appendField('{typeName}'); ";

                tooltip += $"{typeName}: {blocklyType}";
            }
            tooltip += $" returns: {actionInfo.ReturnType.TranslateToBlocklyType()}";

            return(strPropsDefinition + ";" + $" this.setTooltip('{tooltip}');");
        }
        /// <summary>
        /// Generates the function definition.
        /// blockly block definition for action
        /// </summary>
        /// <param name="actionInfo">The action information.</param>
        /// <param name="key">key</param>
        /// <returns></returns>
        public string GenerateFunctionDefinition(ActionInfo actionInfo, string key)
        {
            var strPropsDefinition = GeneratePropertyDefinitions(actionInfo);
            var returnType         = "";

            if (actionInfo.ReturnType.id != null)
            {
                returnType = $@"this.setOutput(true,'{actionInfo.ReturnType.TranslateToBlocklyType()}');";
            }
            else
            {
                returnType = $@"this.setOutput(true,'');";
            }
            var actionHash = actionInfo.CustomGetHashCode();

            string[] verbHasImage = new string[] { "patch", "get", "post", "put", "delete" };
            bool     hasImage     = verbHasImage.Contains(actionInfo.Verb.ToLower());
            var      blockColor   = BlocklyStringToColor.ConvertToHue(actionHash);
            string   site         = string.IsNullOrWhiteSpace(GenerateBlocklyFilesHostedService.InternalSiteUrl) ? "" : GenerateBlocklyFilesHostedService.InternalSiteUrl;

            return($@"
                Blockly.Blocks['{actionInfo.GenerateCommandName()}'] = {{
                          init: function() {{
                            this.setColour({blockColor});
                            this.appendDummyInput()" +

                   (hasImage?
                    $".appendField(new Blockly.FieldImage('{site}images/{actionInfo.Verb.ToLower()}.png', 90, 20, {{ alt: '{actionInfo.Verb}', flipRtl: 'FALSE' }}))"
                                :"") +
                   $".appendField('{actionInfo.CommandDisplayName(!hasImage)}');"
                   + Environment.NewLine
                   + $@"{strPropsDefinition}
                                {returnType}
                                }}//init
                        }};//{actionInfo.ActionName}
                        ");
        }