using System;
using Ozeki.VoIP;
using System.Threading;

namespace _05_Instant_Messages
{
    class Softphone
    {
        private ISoftPhone _softphone; // softphone object
        private IPhoneLine _phoneLine; // phoneline object

        // Our default constructor, initalizes our softphone with deafult parameters.
        public Softphone()
        {
            _softphone = SoftPhoneFactory.CreateSoftPhone(5000, 10000);
        }

        // We are using this method to register to a PBX.
        public void Register(bool registrationRequired, string displayName, string userName, string authenticationId, string registerPassword, string domainHost, int domainPort)
        {
            try
            {
                // To register to a PBX, we need to create a SIP account
                var account = new SIPAccount(registrationRequired, displayName, userName, authenticationId, registerPassword, domainHost, domainPort);

                // With the SIP account and the NAT configuration, we can create a phoneline.
                _phoneLine = _softphone.CreatePhoneLine(account);

                // The phoneline has states, we need to handle the event, when it is being changed.
                _phoneLine.RegistrationStateChanged += phoneLine_PhoneLineStateChanged;
                _phoneLine.InstantMessaging.MessageReceived += phoneLine_InstantMessageReceived;

                // If our phoneline is created, we can register that.
                _softphone.RegisterPhoneLine(_phoneLine);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error during SIP registration: " + ex);
            }
        }

        void phoneLine_InstantMessageReceived(object sender, InstantMessage e)
        {
            DispatchAsync(() =>
            {
                var handler = IncomingMessage;
                if (handler != null)
                    handler(this, e);
            });
        }

        void phoneLine_PhoneLineStateChanged(object sender, RegistrationStateChangedArgs e)
        {
            DispatchAsync(() =>
            {
                var handler = PhoneLineStateChanged;
                if (handler != null)
                    handler(this, e);
            });
        }

        // This method is used to solve the task blockings.
        private void DispatchAsync(Action action)
        {
            ThreadPool.QueueUserWorkItem(o => action());
        }

        public event EventHandler<RegistrationStateChangedArgs> PhoneLineStateChanged;
        public event EventHandler<InstantMessage> IncomingMessage;

        public void SendMessage(InstantMessage message)
        {
            _phoneLine.InstantMessaging.SendMessage(message);
        }
    }
}