/// <summary>
        /// This is a utility method to change the chatter segments into a ManyWho message format.
        /// </summary>
        public String GetMessageText(ChatterMessage chatterMessage)
        {
            String text          = chatterMessage.Body.Text;
            String userAtMention = null;
            IList <ChatterMessageSegment> chatterMessageSegments = chatterMessage.Body.MessageSegments.Where(x => x.Type == ChatterMessageSegmentType.Mention.ToString()).ToList();

            foreach (ChatterMessageSegment chatterMessageSegment in chatterMessageSegments)
            {
                // This is the user at mention piece
                userAtMention = String.Format(SalesforceServiceSingleton.CHATTER_MENTIONED_USER_NAME_SPAN, Guid.NewGuid().ToString(), chatterMessageSegment.User.Id, chatterMessageSegment.User.Name);

                // Parse the at mention into the message text so we have it as one block as opposed to a complex set of objects
                text = text.Replace(chatterMessageSegment.Text, userAtMention);
            }

            return(text);
        }
        /// <summary>
        /// This method allows the user to share the flow app in salesforce with their friends.
        /// </summary>
        public MessageAPI PostNotification(INotifier notifier, IAuthenticatedWho authenticatedWho, String oauthToken, ServiceRequestAPI serviceRequest, String endpointUrl, String flowLink, ChatterPostedMessage chatterPostedMessage)
        {
            HttpResponseMessage      httpResponseMessage      = null;
            HttpClient               httpClient               = null;
            MediaTypeFormatter       jsonFormatter            = null;
            MultipartFormDataContent multipartFormDataContent = null;
            ChatterMessage           chatterMessage           = null;
            ChatterAttachmentLink    chatterAttachmentLink    = null;
            MessageAPI               message = null;
            String chatterBaseUrl            = null;
            String adminEmail = null;

            if (oauthToken == null ||
                oauthToken.Trim().Length == 0)
            {
                throw new ArgumentNullException("BadRequest", "OAuthToken cannot be null or blank.");
            }

            if (endpointUrl == null ||
                endpointUrl.Trim().Length == 0)
            {
                throw new ArgumentNullException("BadRequest", "EndpointUrl cannot be null or blank.");
            }

            // Grab the values necessary to post the message over to chatter
            chatterBaseUrl = ValueUtils.GetContentValue(SalesforceServiceSingleton.SERVICE_VALUE_CHATTER_BASE_URL, serviceRequest.configurationValues, true);
            adminEmail     = ValueUtils.GetContentValue(SalesforceServiceSingleton.SERVICE_VALUE_ADMIN_EMAIL, serviceRequest.configurationValues, true);

            // Now we can create the multipart form we're going to post over to salesforce
            multipartFormDataContent = new MultipartFormDataContent();

            if (flowLink != null &&
                flowLink.Trim().Length > 0)
            {
                // We also add the link to the app so the user has it
                chatterAttachmentLink = new ChatterAttachmentLink();
                chatterAttachmentLink.AttachmentType = "Link";
                chatterAttachmentLink.Url            = flowLink;
                chatterAttachmentLink.UrlName        = "Link to ManyWho Flow";

                chatterPostedMessage.Attachment = chatterAttachmentLink;
            }

            // We enclose the request in a for loop to handle http errors
            for (int i = 0; i < SalesforceHttpUtils.MAXIMUM_RETRIES; i++)
            {
                try
                {
                    // Create a new client object
                    httpClient = SalesforceHttpUtils.CreateHttpClient(oauthToken);

                    // Create a new json formatter so the request will be in the right format
                    jsonFormatter = new JsonMediaTypeFormatter();

                    // Use the JSON formatter to create the content of the chatter post
                    multipartFormDataContent.Add(new ObjectContent <ChatterPostedMessage>(chatterPostedMessage, jsonFormatter), "json");

                    // Post the message over to chatter
                    httpResponseMessage = httpClient.PostAsync(endpointUrl, multipartFormDataContent).Result;

                    // Check the status of the response and respond appropriately
                    if (httpResponseMessage.IsSuccessStatusCode)
                    {
                        // Grab the chatter message from the post
                        chatterMessage = httpResponseMessage.Content.ReadAsAsync <ChatterMessage>().Result;

                        // Convert it over to a manywho message
                        message = SalesforceSocialSingleton.GetInstance().ChatterMessageToMessageAPI(chatterBaseUrl, null, chatterMessage);

                        // We successfully executed the request, we can break out of the retry loop
                        break;
                    }
                    else
                    {
                        // Make sure we handle the lack of success properly
                        BaseHttpUtils.HandleUnsuccessfulHttpResponseMessage(notifier, authenticatedWho, i, httpResponseMessage, endpointUrl);
                    }
                }
                catch (Exception exception)
                {
                    // Make sure we handle the exception properly
                    BaseHttpUtils.HandleHttpException(notifier, authenticatedWho, i, exception, endpointUrl);
                }
                finally
                {
                    // Clean up the objects from the request
                    BaseHttpUtils.CleanUpHttp(httpClient, null, httpResponseMessage);
                }
            }

            return(message);
        }
        /// <summary>
        /// This is a utility method for translating chatter messages into a compatible format for ManyWho.
        /// </summary>
        public MessageAPI ChatterMessageToMessageAPI(String chatterBaseUrl, String parentId, ChatterMessage chatterMessage)
        {
            MessageAPI    message    = null;
            AttachmentAPI attachment = null;

            message = new MessageAPI();

            if (chatterMessage.Attachment != null)
            {
                attachment         = new AttachmentAPI();
                attachment.name    = chatterMessage.Attachment.Title;
                attachment.iconUrl = string.Format("{0}{1}",
                                                   SettingUtils.GetStringSetting("ManyWho.CDNBasePath"),
                                                   SalesforceServiceSingleton.CHATTER_DEFAULT_FILE_IMAGE_URL);
                attachment.description = chatterMessage.Attachment.Description;
                attachment.type        = chatterMessage.Attachment.FileType;
                attachment.size        = chatterMessage.Attachment.FileSize;
                attachment.downloadUrl = chatterMessage.Attachment.DownloadUrl;

                // We need to scrub the download url as this url is the REST API that does not work through the browser
                if (string.IsNullOrWhiteSpace(chatterMessage.Attachment.DownloadUrl) == false &&
                    chatterMessage.Attachment.DownloadUrl.IndexOf("servlet.shepherd", StringComparison.OrdinalIgnoreCase) < 0 &&
                    chatterMessage.Attachment.DownloadUrl.IndexOf("/services/data/v", StringComparison.OrdinalIgnoreCase) >= 0 &&
                    chatterMessage.Attachment.DownloadUrl.IndexOf("/chatter/files", StringComparison.OrdinalIgnoreCase) > 0)
                {
                    String[] urlParts = chatterMessage.Attachment.DownloadUrl.Split('/');

                    // Check to make absolutely sure we have enough parts before adapting the url
                    if (chatterMessage.Attachment.DownloadUrl.StartsWith("https://", StringComparison.OrdinalIgnoreCase) == true &&
                        urlParts.Length >= 8)
                    {
                        // E.g. https://c.cs80.visual.force.com/services/data/v27.0/chatter/files/069250000000ixwAAA/content?versionNumber=1
                        // Get the file identifier, and make sure it's pointing to the correct instance
                        attachment.downloadUrl = chatterBaseUrl + "/" + urlParts[8];
                    }
                    else if (chatterMessage.Attachment.DownloadUrl.StartsWith("/services/data", StringComparison.OrdinalIgnoreCase) == true &&
                             urlParts.Length >= 6)
                    {
                        // E.g. /services/data/v27.0/chatter/files/069250000000jBeAAI/content?versionNumber=1
                        // We don't have the full url, so we need to adapt a smaller part
                        attachment.downloadUrl = chatterBaseUrl + "/" + urlParts[6];
                    }
                }

                message.attachments = new List <AttachmentAPI>();
                message.attachments.Add(attachment);
            }

            message.id          = chatterMessage.Id;
            message.repliedToId = null;

            if (chatterMessage.Comments != null)
            {
                message.commentsCount = chatterMessage.Comments.Total;

                if (chatterMessage.Comments.Comments != null &&
                    chatterMessage.Comments.Comments.Count > 0)
                {
                    // Convert the child messages over for this message
                    message.comments = this.ChatterMessageToMessageAPI(chatterBaseUrl, message.id, chatterMessage.Comments.Comments);
                }
            }

            if (chatterMessage.MyLike != null)
            {
                message.myLikeId = chatterMessage.MyLike.Id;
            }

            message.createdDate = DateTime.Parse(chatterMessage.CreatedDate);
            message.comments    = null;

            if (chatterMessage.Likes != null &&
                chatterMessage.Likes.Likes != null &&
                chatterMessage.Likes.Likes.Count > 0)
            {
                message.likerIds = new List <String>();

                foreach (ChatterLikeItem chatterLikeItem in chatterMessage.Likes.Likes)
                {
                    if (chatterLikeItem.User != null)
                    {
                        message.likerIds.Add(chatterLikeItem.User.Id);
                    }
                }
            }

            // The actor will be non-null for root posts, but it's the user for comments
            if (chatterMessage.Actor != null)
            {
                message.sender = this.ChatterUserInfoToWhoAPI(chatterMessage.Actor);
            }
            else
            {
                message.sender = this.ChatterUserInfoToWhoAPI(chatterMessage.User);
            }

            message.text = this.GetMessageText(chatterMessage);

            return(message);
        }