using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.ServiceModel;
using System.Threading;
using GatewayCommon;

namespace GatewayAPI
{
    public delegate void GatewayServerStatusHandler(bool online);
    public delegate void GatewayServerOnlineHandler(int onlineClientCount);

    [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.Single)]
    public class ServerControl : IServerMethods, IDisposable
    {
        static public event GatewayServerStatusHandler StatusChange;
        static public event GatewayServerOnlineHandler ClientDisconnected;
        static public event GatewayServerOnlineHandler ClientConnected;
        static public event GatewayCallHandler IncommingCall;
        static public event GatewayMessageHandler IncommingMessage;
        static public event GatewayCallHandler OutgoingCall;
        static public event GatewayMessageHandler OutgoingMessage;

        private GatewayControl cc;
        private static Dictionary<Guid, IServerCallbacks> callbacks = new Dictionary<Guid, IServerCallbacks>();
        private bool isAlive = false;
        private string gatewaySerialPort = "COM11";
        private int onlineClients = 0;
        public string pin = "4511";
        
        public bool IsAlive
        {
            get
            {
                return isAlive;
            }
        }
        public string GatewaySerialPort
        {
            get
            {
                return gatewaySerialPort;
            }
            set
            {
                this.gatewaySerialPort = value;
            }
        }
        public int OnlineClients
        {
            get
            {
                return onlineClients;
            }
        }

        public ServerControl()
        {
            this.Open();
        }
        public ServerControl(string gatewaySerialPort, string pin)
        {
            this.pin = pin;
            this.gatewaySerialPort = gatewaySerialPort;
            this.Open();
        }
        ~ServerControl()
        {
            this.Close();
        }
        public void Dispose()
        {
            this.Close();
        }
        public void Open()
        {
            cc = new GatewayControl(gatewaySerialPort);
            cc.IncommingMessage += new GatewayControl.IncommingMessageHandler(cc_IncommingMessage);
            cc.IncommingCall += new GatewayControl.IncommingCallHandler(cc_IncommingCall);
            cc.SetPin += new GatewayControl.PinRequestHandler(cc_SetPin);

            isAlive = true;
            if (StatusChange != null)
                StatusChange(isAlive);
        }

        public void Close()
        {
            isAlive = false;
            if (StatusChange != null)
                StatusChange(isAlive);
            if (cc.IsAlive)
                cc.Dispose();
        }

        public bool IsServerAlive()
        {
            return isAlive;
        }

        public void SubscribeCallback(Guid clientGuid)
        {
            IServerCallbacks tmpCallback;
            if (!callbacks.TryGetValue(clientGuid, out tmpCallback))
            {
                callbacks.Add(clientGuid, OperationContext.Current.GetCallbackChannel<IServerCallbacks>());
                onlineClients++;
                if (ClientConnected != null)
                    ClientConnected(onlineClients);
            }
        }
        public void UnsubscribeCallback(Guid clientGuid)
        {
            IServerCallbacks tmpCallback;
            if (callbacks.TryGetValue(clientGuid, out tmpCallback))
            {
                callbacks.Remove(clientGuid);
                onlineClients--;
                if (ClientDisconnected != null)
                    ClientDisconnected(onlineClients);
            }
        }

        public bool Test()
        {
            if (cc.IsAlive)
            {
                if (cc.TestCommunication())
                    return true;
            }
            return false;
        }
        public string[] GetGatewayInformation()
        {
            if (cc.IsAlive)
            {
                return cc.GetGatewayInformation();
            }
            return null;
        }
        public int GetSignalStatus()
        {
            if (cc.IsAlive)
            {
                return cc.GetSignalStatus();
            }
            return 0;
        }
        public bool SendSMS(string phoneNumber, string smsMessage, bool approve)
        {
            if (cc.IsAlive)
            {
                if (cc.SendSMS(phoneNumber, smsMessage, approve))
                {
                    if (OutgoingMessage != null)
                        OutgoingMessage(smsMessage, phoneNumber, DateTime.Now);
                    return true;
                }
            }
            return false;
        }
        public bool RingThePhone(string phoneNumber, bool approve)
        {
            if (cc.IsAlive)
            {
                if (cc.RingThePhone(phoneNumber, approve))
                {
                    if (OutgoingCall != null)
                        OutgoingCall(phoneNumber, DateTime.Now);
                    return true;
                }
            }
            return false;
        }

        void cc_IncommingCall(string phoneNumber, DateTime incommingDate)
        {
            if (IncommingCall != null)
                IncommingCall(phoneNumber, incommingDate);
            foreach (IServerCallbacks callback in callbacks.Values)
                callback.IncommingCall(phoneNumber, incommingDate);
        }
        void cc_IncommingMessage(string phoneNumber, string message, DateTime incommingDate)
        {
            if (IncommingMessage != null)
                IncommingMessage(phoneNumber, message, incommingDate);
            foreach (IServerCallbacks callback in callbacks.Values)
                callback.IncommingMessage(message, phoneNumber, incommingDate);
        }
        string cc_SetPin()
        {
            return this.pin;
        }
        
    }
}
