/******************************************************************************/
/*                                                                            */
/* Copyright Avaya LLC.                                                       */
/*                                                                            */
/******************************************************************************/
using Avaya.ClientServices;
using Avaya.ClientServices.Media;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Threading;

namespace SampleConferenceApp.SDK
{
    class SDKManager
    {
        public static SDKManager SdkManagerInstance;
        public static Client ClientInstance;
        public ClientConfiguration ClientConfigurationInstance;
        public static User UserInstance;
        public static VideoInterface VideoInterfaceInstance;
        public event EventHandler UserRegistrationSuccessfulEvent;
        public event EventHandler UserRegistrationInProgressEvent;
        public event EventHandler UserUnRegistrationSuccessfulEvent;
        public event EventHandler ClientShutdownCompletedEvent;        
        private static MediaServicesInstance mediaServices;
        private static Device mediaDevice;
        private static AudioInterface audioInterface;
        MicrophoneDevice defaultMicrophone;
        SpeakerDevice defaultSpeaker;
        List<MicrophoneDevice> lastMicrophoneList;
        List<SpeakerDevice> lastSpeakerList;
        private UserConfiguration userConfiguration;
           
        public static SDKManager GetInstance()
        {
            if (SdkManagerInstance == null)
            {
                SdkManagerInstance = new SDKManager();
            }

            return SdkManagerInstance;
        }
        public static User GetUser()
        {
            return SDKManager.UserInstance;
        }
        
        /// <summary>
        ///  Set the ClientConfiguration object
        /// </summary>
        public void SetClientConfiguration()
        {
            ClientConfigurationInstance = new ClientConfiguration(".\\DataDirectory");

            // A unique instance id of the user agent defined in RFC 5626.
            // For the real applications please generate unique value once (e.g. UUID [RFC4122]) and 
            // then save this in persistent storage for all future use.
            ClientConfigurationInstance.UserAgentInstanceId = GenerateUserAgentInstanceId();
            SecurityPolicyConfiguration securityPolicyConfiguration = new SecurityPolicyConfiguration();
            securityPolicyConfiguration.ContinueOnTlsServerIdentityFailure = true;
            securityPolicyConfiguration.RevocationCheckPolicy = SecurityPolicy.Disabled;
            ClientConfigurationInstance.SecurityPolicyConfiguration = securityPolicyConfiguration;
            MediaConfiguration mediaConfiguration = new MediaConfiguration();
            VoIPConfigurationAudio voIPConfigurationAudio = new VoIPConfigurationAudio();
            VoIPConfigurationVideo voIPConfigurationVideo = new VoIPConfigurationVideo();
            mediaConfiguration.VoIPAudioConfig = voIPConfigurationAudio;
            mediaConfiguration.VoIPVideoConfig = voIPConfigurationVideo;
            ClientConfigurationInstance.MediaConfiguration = mediaConfiguration;
        }

        /// <summary>
        /// Generates unique UserAgentInstanceId value
        /// </summary>
        private static string GenerateUserAgentInstanceId()
        {
            if (SampleConferenceApp.Properties.Settings.Default.UserAgentInstanceId.Length > 0)
            {
                return SampleConferenceApp.Properties.Settings.Default.UserAgentInstanceId;
            }
            else
            {
                string UserAgentInstanceId = Guid.NewGuid().ToString();
                SampleConferenceApp.Properties.Settings.Default.UserAgentInstanceId = UserAgentInstanceId;
                SampleConferenceApp.Properties.Settings.Default.Save();
                return UserAgentInstanceId;
            }            
        }

        /// <summary>
        /// Creates client object and set event handlers to client 
        /// </summary>
        public void StartClient()
        {
            SetClientConfiguration();
            if (ClientInstance != null)
            {
                ClientInstance.ShutdownCompleted -= ClientShutdownCompleted;
            }
            try
            {
                ClientInstance = new Client(ClientConfigurationInstance, Dispatcher.CurrentDispatcher);
            }
            catch (Exception ex)
            {
                Console.Write(ex.StackTrace);
            }
            ClientInstance.ShutdownCompleted += ClientShutdownCompleted;
            Client.LogLevel = Avaya.ClientServices.LogLevel.Debug;
            Client.LogMessage += LogMessage;
            mediaServices = ClientInstance.MediaServices;
            VideoInterfaceInstance = mediaServices.getVideoInterface();
            audioInterface = mediaServices.getAudioInterface();
            mediaDevice = mediaServices.getDeviceInterface();

            lastMicrophoneList = audioInterface.Microphones.ToList();
            lastSpeakerList = audioInterface.Speakers.ToList();
            for (int i = 0; i < lastMicrophoneList.Count; i++)
            {
                MicrophoneDevice mic = lastMicrophoneList[i];
                if (mic.isDefaultCommunicationsDevice || mic.isDefaultConsoleDevice || mic.isDefaultMultimediaDevice)
                {
                    defaultMicrophone = mic;
                    break;
                }
            }
            if (defaultMicrophone != null)
            {
                audioInterface.selectMicrophone(defaultMicrophone);
            }

            for (int i = 0; i < lastSpeakerList.Count; i++)
            {
                SpeakerDevice speaker = lastSpeakerList[i];
                if (speaker.isDefaultCommunicationsDevice || speaker.isDefaultConsoleDevice || speaker.isDefaultMultimediaDevice)
                {
                    defaultSpeaker = speaker;
                    break;
                }
            }
            if (defaultSpeaker != null)
            {
                audioInterface.selectSpeaker(defaultSpeaker);
            }
        }

        private void ClientShutdownCompleted(object sender, EventArgs e)
        {
            ClientInstance.ShutdownCompleted -= ClientShutdownCompleted;
            ClientShutdownCompletedEvent.Invoke(sender, e);
        }

        public void ShutdownClient()
        {
            ClientInstance.Shutdown(true);
        }

        /// <summary>
        /// Set UserConfiguration object with UserConfiguration parameters
        /// </summary>
        public void SetUserConfiguration()
        {
            userConfiguration = new UserConfiguration();            
            userConfiguration.ConferenceConfiguration = new ConferenceConfiguration() { EnhancedConferencingEnabled = true, UccpEnabled = true, UccpAdditionalFeaturesEnabled = true };
            userConfiguration.HttpUserConfiguration = new HttpUserConfiguration() { Enabled = true };
            if (UserInstance != null)
            {
                ClientInstance.RemoveUser(UserInstance, true);
            }
            ClientInstance.CreateUser(userConfiguration, (userCreated, userEx) => 
            {
                if (userEx != null)
                {
                    Console.Write("User creation failed");
                    NotificationHelper.ShowNotification(string.Format("User creation failed: {0}", userEx.Reason));
                }
                else
                {
                    UserInstance = userCreated;
                    AddUser(UserInstance);
                    UserInstance.Start();
                }
            });
        }        

        /// <summary>
        /// Add event handlers to user object to handle all user related events  
        /// </summary>
        /// <param name="user"></param>
        public void AddUser(User user)
        {
            user.RegistrationInProgress += RegistrationInProgress;
            user.RegistrationSuccessful += RegistrationSuccessful;
            user.AllRegistrationsSuccessful += AllRegistrationsSuccessful;
            user.RegistrationFailed += RegistrationFailed;
            user.UnregistrationSuccessful += UnregistrationSuccessful;
            user.UnregistrationFailed +=UnregistrationFailed;
            user.AllRegistrationsFailed += AllRegistrationsFailed;
            if (user.CallService != null)
            {
                CallManager.CallServiceInstance = user.CallService;
                CallManager.GetInstance().AddCallServiceEvents();
            }
            if (user.UnifiedPortalService != null)
            {
                HttpUaCallManager.Initialize(user.UnifiedPortalService);
            }
        }

        /// <summary>
        /// Removes all event handlers from user object
        /// </summary>
        /// <param name="user"></param>
        public void RemoveUser(User user)
        {
            user.RegistrationSuccessful -= RegistrationSuccessful;
            user.RegistrationFailed -= RegistrationFailed;
            user.AllRegistrationsSuccessful -= AllRegistrationsSuccessful;
            user.UnregistrationSuccessful -= UnregistrationSuccessful;
            user.UnregistrationFailed -= UnregistrationFailed;
            user.AllRegistrationsFailed -= AllRegistrationsFailed;
            if (user.CallService != null)
            {
                CallManager.GetInstance().RemoveCallServiceEvents();
            }
            user.Stop();
        }

        #region All user related event handlers

        public void RegistrationInProgress(object sender, EventArgs e)
        {
            UserRegistrationInProgressEvent.Invoke(this, EventArgs.Empty);
        }
        public void RegistrationSuccessful(object sender, EventArgs e)
        {
            UserRegistrationSuccessfulEvent.Invoke(this, EventArgs.Empty);
        }
        public void AllRegistrationsSuccessful(object sender, EventArgs e)
        {
        }
        public void RegistrationFailed(object sender, RegistrationFailureEventArgs e)
        {
           Console.Write("Registration Failed" + e.Error.ToString());
        }
        public void UnregistrationSuccessful(object sender, EventArgs e)
        {            
            UserUnRegistrationSuccessfulEvent.Invoke(this, EventArgs.Empty);
        }
        public void UnregistrationFailed(object sender, RegistrationFailureEventArgs e)
        {
            User user = (User)sender;
        }
        public void AllRegistrationsFailed(object sender, AllRegistrationsFailureEventArgs e)
        {
            Console.Write("All Registration Failed");
            NotificationHelper.ShowNotification("All Registration Failed");
        }

        public void LogMessage(object sender, LogMessageEventArgs e)
        {
            WriteLog(e.Level.ToString(), e.Tag, e.Message);
        }
        public void WriteLog(String Level, String Tag, String Message)
        {
            Console.WriteLine("\n" + DateTime.Now.ToString(("MM-dd-yyyy hh:mm:ss")) + ": " + Level + " : " + Tag + " : " + Message);
            //Console.WriteLine("\n"+ Level + " : " + Tag + " : " + Message);
        }

        #endregion
    }
}
