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

namespace CommunicationSampleApp.Classes
{
    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;
        //Directory to store call log file
        public static string CallLogDirectoryPath = @".\\CallLogFolder";
        private static MediaServicesInstance mediaServices;
        private static Device mediaDevice;
        private static AudioInterface audioInterface;
        MicrophoneDevice defaultMicrophone;
        SpeakerDevice defaultSpeaker;
        List<MicrophoneDevice> lastMicrophoneList;
        List<SpeakerDevice> lastSpeakerList;

        //If you are connecting to IPOffice deployment, change this value to true
        //Also this requires installation of "Third party IP Endpoints" license in IPO
        private bool isConfiguredForIPOffice = false;

        private UserConfiguration userConfiguration;
        private SipUserConfiguration sipUserConfig;

        public SDKManager()
        {
            Configuration.ProductVersion = Client.Version.Split(' ')[1].Replace('(', ' ');
        }     
           
        public static SDKManager GetInstance()
        {
            if (SdkManagerInstance == null)
            {
                SdkManagerInstance = new SDKManager();
            }

            return SdkManagerInstance;
        }
        public static User GetUser()
        {
            return SDKManager.UserInstance;
        }

        public static string GetApplicationVersion()
        {
            // Product version is extacted from Client SDK version for sample application
            // If, the SDK version: x.x (yyy.y.y Build zzz)
            // then, Application version: yyy.y.y
            return (Client.Version.Split(' ')[1].Replace('(', ' '));
        }

        /// <summary>
        ///  Set the ClientConfiguration object
        /// </summary>
        public void SetClientConfiguration()
        {
            if (!Directory.Exists(Configuration.DataDirectory))
            {
                System.IO.Directory.CreateDirectory(Configuration.DataDirectory);
            }
            ClientConfigurationInstance = new ClientConfiguration(Configuration.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 (Configuration.UserAgentInstanceId.Length > 0)
            {
                return Configuration.UserAgentInstanceId;
            }
            else
            {
                string UserAgentInstanceId = Guid.NewGuid().ToString();
                Configuration.UserAgentInstanceId = UserAgentInstanceId;
                CommunicationSampleApp.Properties.Settings.Default.UserAgentInstanceId = UserAgentInstanceId;
                CommunicationSampleApp.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.Error;
            //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)
        {
            ClientShutdownCompletedEvent.Invoke(sender, e);
        }

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

        /// <summary>
        /// Set UserConfiguration object with UserConfiguration parameters
        /// </summary>
        public void SetUserConfiguration()
        {
            userConfiguration = new UserConfiguration();
            if (!Directory.Exists(CallLogDirectoryPath))
            {
                System.IO.Directory.CreateDirectory(CallLogDirectoryPath);
            }
            string callLogFilePath = Path.Combine(CallLogDirectoryPath, Configuration.SipUserName+"LogFile.xml");
            userConfiguration.LocalCallLogFilePath = callLogFilePath;
            sipUserConfig = new SipUserConfiguration();
            if (isConfiguredForIPOffice)
            {
                setUpIPOSpecificConfiguration();
            }
            else
            {
                setUpAuraSpecificConfiguration();
            }
            if ((!String.IsNullOrEmpty(Configuration.SipServerAddress)) && (!String.IsNullOrEmpty(Configuration.SipUserName)) && (!String.IsNullOrEmpty(Configuration.SipPassword)) && (!String.IsNullOrEmpty(Configuration.SipDomain)))
            {
                sipUserConfig.Enabled = true;
            }
            else
            {
                sipUserConfig.Enabled = false;
            }
            TransportType transportType;
            if (Configuration.IsSecure)
            {
                transportType = TransportType.Tls;
            }
            else
            {
                transportType = TransportType.Tcp;
            }
            SignalingServer signalingServer = new SignalingServer(transportType, Configuration.SipServerAddress, Configuration.SipPort, FailbackPolicy.Automatic); //5060 - TCP & 5061 -Tls
            SignalingServerGroup sipsignallingServerGroup = new SignalingServerGroup(signalingServer);
            sipUserConfig.ConnectionPolicy = new ConnectionPolicy(sipsignallingServerGroup);
            sipUserConfig.UserId = Configuration.SipUserName;
            sipUserConfig.Domain = Configuration.SipDomain;
            sipUserConfig.CredentialProvider = new CredentialProvider(Configuration.SipUserName, Configuration.SipPassword, Configuration.SipDomain);
            sipUserConfig.MediaEncryptionTypeArray = new MediaEncryptionType[] { MediaEncryptionType.Aes128Sha1Hmac32, MediaEncryptionType.Aes128Sha1Hmac80, MediaEncryptionType.Aes256Sha1Hmac32, MediaEncryptionType.Aes256Sha1Hmac80, MediaEncryptionType.None };
            userConfiguration.SipUserConfiguration = sipUserConfig;
            userConfiguration.WcsConfiguration.Enabled = true;
            LocalContactConfiguration localContactConfiguration = new LocalContactConfiguration(true);
            userConfiguration.LocalContactConfiguration = localContactConfiguration;
            if ((!String.IsNullOrEmpty(Configuration.ACSUrl)) && (!String.IsNullOrEmpty(Configuration.ACSUserName)) && (!String.IsNullOrEmpty(Configuration.ACSPassword)) && (!String.IsNullOrEmpty(Configuration.ACSPort.ToString())))
            {
                userConfiguration.AcsConfiguration.Enabled = true;
            }
            else
            {
                userConfiguration.AcsConfiguration.Enabled = false;
            }
            userConfiguration.AcsConfiguration.CredentialProvider = new CredentialProvider(Configuration.ACSUserName, Configuration.ACSPassword, null);
            userConfiguration.AcsConfiguration.ServerInfo = new ServerInfo(Configuration.ACSUrl, Configuration.ACSPort, Configuration.ACSIsSecure);
            userConfiguration.ConferenceConfiguration.ConferenceFactoryURI = null;
            if (UserInstance != null)
            {
                ClientInstance.RemoveUser(UserInstance, true);
            }
            ClientInstance.CreateUser(userConfiguration, (userCreated,userEx) => 
            {
                if (userEx != null)
                {
                    Console.Write("user creation Failed");
                }
                else
                {
                    UserInstance = userCreated;
                    AddUser(UserInstance);
                    UserInstance.Start();
                }
            });
        }

        private void setUpIPOSpecificConfiguration()
        {
            IPOfficeConfiguration ipoConfiguration = userConfiguration.IPOfficeConfiguration;
            userConfiguration.PpmConfiguration.Enabled = false;
            userConfiguration.AmmConfiguration.Enabled = false;
            userConfiguration.PresenceConfiguration.Enabled = false;
            ipoConfiguration.Enabled = true;
            ipoConfiguration.ContactsEnabled = true;
            ipoConfiguration.PresenceEnabled = true;
            ipoConfiguration.CredentialProvider = sipUserConfig.CredentialProvider;
            userConfiguration.IPOfficeConfiguration = ipoConfiguration;

        }

        private void setUpAuraSpecificConfiguration()
        {
            userConfiguration.PpmConfiguration.Enabled = true;
            userConfiguration.PpmConfiguration.ContactsEnabled = true;
            userConfiguration.PpmConfiguration.CredentialProvider = sipUserConfig.CredentialProvider;
            if ((!String.IsNullOrEmpty(Configuration.MessagingServiceServerAddress)) && (!String.IsNullOrEmpty(Configuration.MessagingServiceUserName)) && (!String.IsNullOrEmpty(Configuration.MessagingServicePassword)) && (!String.IsNullOrEmpty(Configuration.MessagingServiceServerPort.ToString())))
            {
                userConfiguration.AmmConfiguration.Enabled = true;
            }
            else
            {
                userConfiguration.AmmConfiguration.Enabled = false;
            }

            userConfiguration.AmmConfiguration.CredentialProvider = new CredentialProvider(Configuration.MessagingServiceUserName, Configuration.MessagingServicePassword, null);
            userConfiguration.AmmConfiguration.ServerInfo = new ServerInfo(Configuration.MessagingServiceServerAddress, Configuration.MessagingServiceServerPort, Configuration.MessagingServiceServerIsSecure);
            userConfiguration.AmmConfiguration.PollIntervalInMinutes = Configuration.PollIntervalInMinutes;
            userConfiguration.PresenceConfiguration.Enabled = true;

        }

        /// <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.ContactService != null)
            {
                ContactManager.ContactServiceInstance = user.ContactService;
                ContactManager.GetInstance().RegisterForContactServiceEvents();
            }
            if (user.CallLogService != null)
            {
                CallLogManager.CallLogServiceInstance = user.CallLogService;
                CallLogManager.GetInstance().AddCallLogServiceEvents(user.CallLogService);
            }
            if (user.CallFeatureService != null)
            {
                CallFeatureManager.CallFeatureServiceInstance = user.CallFeatureService;
                CallFeatureManager.GetInstance().RegisterForCallFeatureServiceEvents();
            }
            if (user.MessagingService != null)
            {
                MessagingServiceManager.MessagingServiceInstance = user.MessagingService;
                MessagingServiceManager.GetInstance().RegisterForMessagingServiceEvents();
            }
            if (user.CollaborationService != null)
            {
                CollaborationManager.CollaborationServiceInstance = user.CollaborationService;
                CollaborationManager.GetInstance().RegisterWebCollaborationServiceEvents();
            }
        }

        /// <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();
            }
            CallFeatureManager.GetInstance().UnregisterFromCallFeatureServiceEvents();
            if (user.ContactService != null)
            {
                ContactManager.GetInstance().StopContactPresence();
                ContactManager.GetInstance().UnregisterFromContactServiceEvents();
            }
            if (user.CallLogService != null)
            {
                CallLogManager.GetInstance().RemoveCallLogServiceEvents(user.CallLogService);
            }
            if (user.MessagingService != null)
            {
                MessagingServiceManager.GetInstance().UnregisterForMessagingServiceEvents();
            }
            if (user.CollaborationService != null)
            {
                CollaborationManager.GetInstance().UnregisterWebCollaborationServiceEvents();
            }
            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)
        {
            Configuration.Isloginsuccess = true;
            ContactManager contactManager = ContactManager.GetInstance();
            contactManager.GetContacts();
        }
        public void RegistrationFailed(object sender, RegistrationFailureEventArgs e)
        {
           Console.Write("Registration Failed" + e.Error.ToString());
        }
        public void UnregistrationSuccessful(object sender, EventArgs e)
        {
            Configuration.Isloginsuccess = false;
            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
    }
}
