/******************************************************************************/
/*                                                                            */
/* Copyright Avaya LLC.                                                       */
/*                                                                            */
/******************************************************************************/
using System;
using System.Collections.Generic;
using Avaya.ClientServices;

namespace CommunicationSampleApp.Classes
{
    class MessagingServiceManager
    {
        public static MessagingService MessagingServiceInstance;
        public static MessagingServiceManager MessagingServiceManagerInstance;
        public static List<Conversation> ConversationList = new List<Conversation>();
        public static Conversation SelectedConversation;
        public static IList<Message> MessageList;
        public static Message NewMessage;
        public static event EventHandler MessagingServiceAvailableEvent;
        public static event EventHandler UpdateConversationUIEvent;
        public static event EventHandler ViewConversationUIEvent;
        public static event EventHandler ParicipantAddedSuccessEvent;
        public static event EventHandler UpdateViewConversationUIEvent;
        public static event EventHandler ComposingParticipantsChangedEvent;
        public static event EventHandler StartConversationSuccessEvent;
        public static Conversation CurrentConversation;
        public static Conversation ActiveConversation;
        public static Message CreatedMessage;
        public static String ComposingParticipants = String.Empty;
        public static bool IsAttachment = false;
        public static string AttachedFileLocation;
        public static string AttachedFileName;
        public static List<Attachment> SelectedConversationAttachmentList = new List<Attachment>();
        public static Attachment SelectedAttachment;
        

        public static MessagingServiceManager GetInstance()
        {
            if (MessagingServiceManagerInstance == null)
            {
                MessagingServiceManagerInstance = new MessagingServiceManager();
            }
            return MessagingServiceManagerInstance;
        }

        /// <summary>
        /// Events related to messaging service
        /// </summary>
        public void RegisterForMessagingServiceEvents()
        {
            MessagingServiceInstance.MessagingServiceAvailable += MessagingServiceAvailable;
            MessagingServiceInstance.MessagingServiceUnavailable += MessagingServiceUnavailable;
        }

        public void UnregisterForMessagingServiceEvents()
        {
            MessagingServiceInstance.MessagingServiceAvailable -= MessagingServiceAvailable;
            MessagingServiceInstance.MessagingServiceUnavailable -= MessagingServiceUnavailable;
        }

        public void MessagingServiceAvailable(Object Sender, EventArgs e)
        {
            //retrive active conversation of logged user
            ConversationRetrievalWatcher conversationRetrievalWatcher = new ConversationRetrievalWatcher();
            InstallConversationRetrievalWatcherEventHandlers(conversationRetrievalWatcher);
            MessagingServiceInstance.RetrieveActiveConversations(conversationRetrievalWatcher);
            MessagingServiceAvailableEvent(this , EventArgs.Empty);
        }

        public void InstallConversationRetrievalWatcherEventHandlers(ConversationRetrievalWatcher conversationRetrievalWatcher)
        {
            conversationRetrievalWatcher.DataRetrievalProgress += ConversationDataRetrievalProgress;
            conversationRetrievalWatcher.DataRetrievalDone += ConversationDataRetrievalDone;
            conversationRetrievalWatcher.DataRetrievalCollectionChanged += ConversationDataRetrievalCollectionChanged;
        }

        public void MessagingServiceUnavailable(Object Sender, EventArgs e)
        {
            Console.Write("Messaging Service Unavailable");
        }

        void ConversationDataRetrievalDone(object sender, EventArgs e)
        {
            UpdateConversationUIEvent(this, EventArgs.Empty);
        }

        void ConversationDataRetrievalProgress(object sender, DataRetrievalEventArgs<Conversation> e)
        {
        }

        void ConversationDataRetrievalCollectionChanged(object sender, DataCollectionChangedEventArgs<Conversation> e)
        {
            //add/remove conversations object in ConversationList - used to display Conversation list on UI 
            foreach (Conversation conversation in e.ChangedItems)
            {
                //add active conversation in ConversationList
                if (e.ChangeType == DataCollectionChangeType.ItemsAdded)
                {
                    if (conversation.IsActive)
                    {
                        MessagingServiceManager.ConversationList.Add(conversation);
                        conversation.ComposingParticipantsChanged += ComposingParticipantsChanged;
                        conversation.TotalUnreadMessageCountChanged += TotalUnreadMessageCountChanged;
                        conversation.TotalUnreadAttachmentCountChanged += TotalUnreadAttachmentCountChanged;
                    }
                }
                //Remove deleted conversation from ConversationList
                else if (e.ChangeType == DataCollectionChangeType.ItemsDeleted)
                {
                    MessagingServiceManager.ConversationList.Remove(conversation);
                    UpdateConversationUIEvent(this, EventArgs.Empty);
                }
            }
        }

        public void ComposingParticipantsChanged(object sender,MessagingParticipantListEventArgs e)
        {
            //Check if any participant is composing
            if (e.Participants.Count > 0)
            {
                foreach (Participant participant in e.Participants)
                {
                    //Display name of composing participant on UI
                    ComposingParticipants = participant.DisplayName + " is typing...";
                }
                MessagingServiceManager.ComposingParticipantsChangedEvent(this, EventArgs.Empty);
            }
            else
            {
                //No participant is composing, update UI 
                ComposingParticipants = string.Empty;
                MessagingServiceManager.ComposingParticipantsChangedEvent(this, EventArgs.Empty);
            }
        }

        public void TotalUnreadMessageCountChanged(object sender, EventArgs e)
        {
            UpdateConversationUIEvent(this, EventArgs.Empty);
        }

        public void TotalUnreadAttachmentCountChanged(object sender, EventArgs e)
        {
            UpdateConversationUIEvent(this, EventArgs.Empty);
        }

        /// <summary>
        /// Display contents of conversation
        /// </summary>
        public void DisplayConversation()
        {
            if (MessagingServiceManager.SelectedConversation != null)
            {
                MessageRetrievalWatcher messageRetrieval = new MessageRetrievalWatcher();
                addMessageRetrivalEvents(messageRetrieval);
                SelectedConversation.RetrieveMessages(messageRetrieval);
                if(SelectedConversation.MarkAllContentAsReadCapability.Allowed)
                {
                    SelectedConversation.MarkAllContentAsRead((MessagingFailureEventArgs error) => { });
                }
            }
        }

        public void addMessageRetrivalEvents(MessageRetrievalWatcher messageRetrieval)
        {
            messageRetrieval.DataRetrievalProgress += DataRetrievalProgress;
            messageRetrieval.DataRetrievalDone += DataRetrievalDone;
            messageRetrieval.DataRetrievalCollectionChanged += DataRetrievalCollectionChanged;
        }

        public void removeMessageRetrivalEvents(MessageRetrievalWatcher messageRetrieval)
        {
            messageRetrieval.DataRetrievalProgress -= DataRetrievalProgress;
            messageRetrieval.DataRetrievalDone -= DataRetrievalDone;
            messageRetrieval.DataRetrievalCollectionChanged -= DataRetrievalCollectionChanged;
        }

        public void DataRetrievalProgress(object sender, DataRetrievalEventArgs<Message> message)
        {
            MessageList = ((DataRetrievalWatcher<Message, MessagingFailureEventArgs>)sender).GetSnapshot();
        }

        public void DataRetrievalDone(object sender, EventArgs e)
        {
            ViewConversationUIEvent(this, EventArgs.Empty);
        }

        public void DataRetrievalCollectionChanged(object sender, DataCollectionChangedEventArgs<Message> message)
        {
            foreach (Message msg in message.ChangedItems)
            {
                NewMessage = msg;
            }
            UpdateViewConversationUIEvent(this, EventArgs.Empty);
        }

        public void AddMessageEvents(Message message)
        {
            message.StatusChanged += StatusChanged;
        }
        public void RemoveMessageEvents(Message message)
        {
            message.StatusChanged -= StatusChanged;
        }
        public void StatusChanged(object sender, EventArgs e)
        {
            DisplayConversation();
        }

        /// <summary>
        /// Leave selected active conversation
        /// </summary>
        public void LeaveConversation()
        {
            SelectedConversation.Leave((error) =>
            {
                if (error == null)
                {
                    Console.Write("Leave conversation error success");
                }
                else
                {
                    NotificationHelper.ShowNotification("Leave conversation error : " + error.Error.ToString());
                }
            });
        }

        /// <summary>
        /// Create new conversation
        /// </summary>
        public void CreateConversation(string remoteAddress)
        {
            CurrentConversation = MessagingServiceInstance.CreateConversation();
            SelectedConversation = null;
            AddParticipantToConversation(remoteAddress);
        }

        /// <summary>
        /// Add participant to conversation
        /// </summary>
        /// <param name="remoteAddress"></param>
        public void AddParticipantToConversation(string remoteAddress)
        {
            var conversation = CurrentConversation;

            if (conversation != null)
            {
                if (conversation.AddParticipantsCapability.Allowed)
                {
                    List<String> addresses = new List<string>() { remoteAddress };
                    conversation.AddParticipantAddresses(addresses, (conv, participants, error) =>
                    {
                        if (error == null)
                        {
                            ActiveConversation = conv;
                            ParicipantAddedSuccessEvent(this, EventArgs.Empty);
                            StartConversation();
                        }
                        else
                        {
                            NotificationHelper.ShowNotification("Add participant failed : " + error.Error);
                            MessagingServiceInstance.RemoveConversation(conv, null);
                        }
                    });
                }
                else
                {
                    NotificationHelper.ShowNotification("AddParticipantsCapability : Not Allowed");
                }
            }
            else
            {
                Console.Write("Conversation not found");
            }
        }
        /// <summary>
        /// Start new conversation
        /// </summary>
        public void StartConversation()
        {
            if(CurrentConversation != null)
            {
                var conversation = CurrentConversation;
                if (conversation != null)
                {
                    if (conversation.StartCapability.Allowed)
                    {
                        //Starting conversation
                        conversation.Start((e) =>
                        {
                            if (e != null)
                            {

                                Console.Write("Start failed for conversation" + e.Error);
                                NotificationHelper.ShowNotification("Conversation start failed : " + e.Error);
                            }
                            else
                            {
                                UpdateConversationUIEvent(this, EventArgs.Empty);
                                MessageRetrievalWatcher messageRetrival = new MessageRetrievalWatcher();
                                addMessageRetrivalEvents(messageRetrival);
                                conversation.RetrieveMessages(messageRetrival);
                                SelectedConversation = conversation;
                                StartConversationSuccessEvent(this, EventArgs.Empty);
                            }
                        });
                    }
                    else
                    {
                        NotificationHelper.ShowNotification("Start Conversation Capability : Not Allowed");
                    }
                }
                else
                {
                    Console.Write("Conversation not found");
                }
            }
            else
            {
                Console.Write("currentConversationID is NULL");
            }
        }

        /// <summary>
        /// Create new message object set body and set attachment and send message
        /// </summary>
        /// <param name="messageBody"></param>
        public void CreateAndSendMessage(String messageBody)
        {
            var conversation = CurrentConversation;
            if (conversation != null)
            {
                    // Create message
                    CreatedMessage = conversation.CreateMessage();
                if (CreatedMessage == null)
                {
                    NotificationHelper.ShowNotification("Message could not be created");
                    return;
                }
                else
                {
                    //Set attachment to message
                    if (IsAttachment == true)
                    {
                        Attachment attachment = CreatedMessage.CreateAttachment();
                        attachment.SetLocation(AttachedFileLocation, (attachment1, error) =>
                        {
                            if (error != null)
                            {
                                Console.Write("Set location error : " + error.Error.ToString());
                            }
                        });
                        attachment.SetName(AttachedFileName, (attachment1, error) =>
                        {
                            if (error != null)
                            {
                                Console.Write("Set name error : " + error.Error.ToString());
                            }
                        });
                    }
                    IsAttachment = false;
                    if (CreatedMessage.UpdateBodyCapability.Allowed)
                    {
                        // Set a body
                        CreatedMessage.SetBodyAndReportTyping(messageBody, (e) =>
                        {
                            if (e == null)
                            {
                                if (CreatedMessage.SendCapability.Allowed)
                                {
                                    AddMessageEvents(CreatedMessage);
                                        //Sending message
                                        CreatedMessage.Send((completionHandler) =>
                                            {
                                                if (completionHandler != null)
                                                {
                                                    Console.Write("Send message failed due to " + completionHandler.Error);
                                                }
                                                else
                                                {
                                                }
                                            });
                                }
                                else
                                {
                                    NotificationHelper.ShowNotification("Send Message Capability : Not Allowed");
                                }
                            }
                        });
                    }
                    else
                    {
                        NotificationHelper.ShowNotification("Update MessageBody Capability : Not Allowed");
                    }
                }
            }
            else
            {
                Console.Write("Conversation not found");
            }
        }

        /// <summary>
        /// Download the attachment at specified path
        /// </summary>
        /// <param name="path"></param>
        /// <param name="attachment"></param>
        public void DownloadAttachment(String path, Attachment attachment)
        {
            attachment.Download(path, (attachment1, error) =>
            {
                if (error != null)
                {
                    Console.Write("Attachment Downloading error : " + error.Error.ToString());
                }
                else
                {
                    Console.Write("Attachment Downloaded success : " + attachment1.Name);
                }
            });

        }
    }
}
