private static string MapAttributesToJsonTemplate(Microsoft.Xrm.Sdk.Entity record, string jsonTemplate, string orgUrl, bool doHyperlinks = true, bool doLinksAsAdaptive = true)
        {
            try
            {
                if (!string.IsNullOrEmpty(jsonTemplate))
                {
                    foreach (KeyValuePair <string, object> kvp in record.Attributes)
                    {
                        if (!jsonTemplate.Contains("{" + kvp.Key + "}"))
                        {
                            // move to next element if not detected within the template
                            continue;
                        }

                        string type      = kvp.Value.GetType().Name.ToLower();
                        string value     = kvp.Value.ToString();
                        string hyperlink = string.Empty;

                        switch (type)
                        {
                        case ("entityreference"):
                        {
                            Microsoft.Xrm.Sdk.EntityReference refVal = (Microsoft.Xrm.Sdk.EntityReference)kvp.Value;
                            value = refVal.Name;
                            if (doHyperlinks)
                            {
                                hyperlink = orgUrl + "/main.aspx?forceUCI=1&etn=" + refVal.LogicalName + "&id=" + refVal.Id + "&pagetype=entityrecord";
                            }
                            break;
                        }

                        case ("optionsetvalue"):
                        {
                            value = record.GetValueDisplayString(kvp.Key);
                            break;
                        }

                        case ("datetime"):
                        {
                            DateTime dtVal = (DateTime)kvp.Value;
                            value = dtVal.ToString("dd/MM/yyyy");
                            break;
                        }

                        case ("money"):
                        {
                            Money mVal = (Money)kvp.Value;
                            value = mVal.Value.ToString("#,###,##0");
                            break;
                        }

                        case ("entitycollection"):
                        {
                            if (kvp.Value != null)
                            {
                                Microsoft.Xrm.Sdk.EntityCollection collection = (Microsoft.Xrm.Sdk.EntityCollection)kvp.Value;
                                value = collection.ToCommaSeparatedString();
                            }
                            else
                            {
                                value = "None";
                            }
                            break;
                        }

                        default:
                        {
                            object o = kvp.Value;
                            if (o != null)
                            {
                                value = o.ToString();
                            }
                            else
                            {
                                value = "";
                            }
                            break;
                        }
                        }

                        if (!String.IsNullOrEmpty(hyperlink))
                        {
                            if (doLinksAsAdaptive)
                            {
                                // In AdaptiveCards, Links are formatted as [caption](url link)
                                jsonTemplate = jsonTemplate.Replace("{" + kvp.Key.ToLower() + "}", "[" + value + "](" + hyperlink + ")");
                            }
                            else
                            {
                                jsonTemplate = jsonTemplate.Replace("{" + kvp.Key.ToLower() + "}", hyperlink);
                            }
                        }
                        else
                        {
                            jsonTemplate = jsonTemplate.Replace("{" + kvp.Key.ToLower() + "}", value);
                        }
                        if (orgUrl != null)
                        {
                            jsonTemplate = jsonTemplate.Replace("{recordurl}", orgUrl + "/main.aspx?" + "etn=" + record.LogicalName + "&id=%7B" + record.Id + "%7D" + "&pagetype=entityrecord" + "&forceUCI=1");
                        }
                    }

                    // final step - remove all occuring strings by "{ and }" - effectively blanking the unmapped schemas
                    string result = jsonTemplate;
                    while (true)
                    {
                        int indexOfOpen  = result.IndexOf("\"{");
                        int indexOfClose = result.IndexOf("}\"", indexOfOpen + 1);

                        if (indexOfOpen < 0 && indexOfClose < 0)
                        {
                            break;
                        }
                        result = result.Substring(0, indexOfOpen) + "\"" + result.Substring(indexOfClose + 1);
                    }

                    if (result != jsonTemplate)
                    {
                        jsonTemplate = result;
                    }
                }
                return(jsonTemplate);
            }
            catch (Exception e)
            {
                throw new Exception("SS21.Examples.TeamBot.AdaptiveCardFactory.MapAttributesToJsonTemplate :: ERROR :: Unable to map attributes to JSON template due to the following reason/s " + Environment.NewLine + e.Message);
            }
        }
        public static string ProcessDynamicContent(Microsoft.Xrm.Sdk.Entity record, string jsonTemplate)
        {
            try
            {
                JObject jobject = JObject.Parse(jsonTemplate);

                JArray a        = JArray.Parse(jobject["body"].ToString());
                JArray newArray = new JArray();

                foreach (JObject o in a.Children <JObject>())
                {
                    bool   dynamicContent = false;
                    string schemaName     = string.Empty;

                    foreach (JProperty p in o.Properties())
                    {
                        if (p.Name.Equals("dynamicContent"))
                        {
                            dynamicContent = true;
                        }
                        if (p.Name.Equals("text"))
                        {
                            // extract schema name between { } ex. {description}
                            // schemaName = description
                            schemaName = (string)o["text"];

                            if (!string.IsNullOrEmpty(schemaName))
                            {
                                schemaName = schemaName.Substring(1, schemaName.Length - 2);
                            }
                        }
                    }

                    // placeholder json for new textbox element
                    string jsonElement = @"{
                         ""type"": ""TextBlock"",
                         ""text"": """",
                         ""wrap"": true,
                         }";

                    if (!String.IsNullOrEmpty(schemaName))
                    {
                        // get value by schema name from Record
                        if (record.Contains(schemaName))
                        {
                            string fieldValue = (string)record[schemaName];

                            // remove html and perform string split
                            fieldValue = ConvertHTMLToText(fieldValue);

                            if (record.LogicalName == "email")
                            {
                                // remove any emails after the first detected email in the chain
                                int stringPosition = fieldValue.IndexOf("From:");

                                if (stringPosition != -1)
                                {
                                    fieldValue = fieldValue.Substring(0, stringPosition);
                                }

                                // attempt to remove signature by mapping from name
                                Microsoft.Xrm.Sdk.EntityCollection collection = (Microsoft.Xrm.Sdk.EntityCollection)record["from"];
                                string fromValue = collection.ToCommaSeparatedString();
                                stringPosition = fieldValue.IndexOf(fromValue);

                                if (stringPosition != -1)
                                {
                                    fieldValue = fieldValue.Substring(0, stringPosition);
                                }
                            }

                            // dodge - replace multiple line break characters with a unique break string
                            fieldValue = Regex.Replace(fieldValue, "[\r\n\f]", "/crmcs/", System.Text.RegularExpressions.RegexOptions.IgnoreCase);

                            string[] fieldValues = fieldValue.Split(new string[] { "/crmcs/" }, StringSplitOptions.None);

                            for (int i = 0; i < fieldValues.Length; i++)
                            {
                                string value = fieldValues[i];

                                if (!string.IsNullOrEmpty(value))
                                {
                                    JObject newElement = null;

                                    if (i == 0)
                                    {
                                        // first value to replace current element
                                        newElement = o;
                                    }
                                    else
                                    {
                                        // next value set as new textbox element
                                        newElement = JObject.Parse(jsonElement);
                                    }
                                    newElement["text"] = value;
                                    newArray.Add(newElement);
                                }
                            }
                        }
                        else
                        {
                            // do nothing
                        }
                    }
                    else
                    {
                        newArray.Add(o);
                    }
                }

                jobject["body"] = newArray;

                // return formatted JSON Template as string to keep things consistent
                return(jobject.ToString());
            }
            catch (Exception ex)
            {
                throw new Exception("ProcessDynamicContent :: " + ex.Message);
            }
        }