using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using Pluto.Registration;

namespace RegistrationAPI
{
    /// <remarks>
    /// Communication Manager to Practice Choice Client API
    /// </remarks>
    public static class API
    {
        #region Construction

        private static HiddenMainForm _hiddenFrm = null;
        static API()
        {            
            _hiddenFrm = new HiddenMainForm();
            _hiddenFrm.Opacity = 0;
            _hiddenFrm.Show();
            _hiddenFrm.Visible = false;            
        }

        #endregion

        #region Change Network Settings

        /// <summary>
        /// Use this function to change the URL and port for the client to use when
        /// communicating (affects entire API)
        /// </summary>
        /// <param name="url"></param>
        /// <param name="port"></param>
        public static void SetNetworkSettings(string url, uint port)
        {
            bool bChangeOccured = false;
            if (!String.IsNullOrEmpty(url) && String.Compare(_hiddenFrm.ClientChannel.Hostname, url, true) != 0)
            {
                bChangeOccured = true;
                _hiddenFrm.ClientChannel.Hostname = url;
            }
            if (port > 0 && _hiddenFrm.ClientChannel.Port != (int)port)
            {
                bChangeOccured = true;
                _hiddenFrm.ClientChannel.Port = (int)port;
            }
            if (bChangeOccured)
            {
                _hiddenFrm.ClientChannel.TargetUrl = String.Format("tcp://{0}:{1}/bin", _hiddenFrm.ClientChannel.Hostname, _hiddenFrm.ClientChannel.Port);
            }            
        }

        #endregion

        #region Public Methods (coded here)

        /// <summary>
        /// The max number of characters a practice name can take on
        /// </summary>
        public const int PRACTICENAME_LENGTH = 50;

        /// <summary>
        /// Const will be used when registering in order to distinguish an internal Practice from a real Customer
        /// </summary>
        public const string INTERNAL_TEST_PRACTICE = " (Mck)";

        /// <summary>
        /// Because the practice can only be 50 chars, call this function to get INTERNAL_TEST_PRACTICE
        /// </summary>
        /// <returns></returns>
        public static string GetMcKInternalizedPracticeName(string PracticeName)
        {
            if (!String.IsNullOrEmpty(PracticeName))
            {
                int nLen = PracticeName.Length + INTERNAL_TEST_PRACTICE.Length;
                if (nLen > RegistrationAPI.API.PRACTICENAME_LENGTH)
                {
                    string PName = PracticeName.Substring(0, (RegistrationAPI.API.PRACTICENAME_LENGTH - INTERNAL_TEST_PRACTICE.Length));
                    return (PName + INTERNAL_TEST_PRACTICE);
                }
                else
                {
                    return (PracticeName + INTERNAL_TEST_PRACTICE);
                }
            }
            return INTERNAL_TEST_PRACTICE.Trim();
        }

        #endregion

        #region Useful System Registration API Calls

        /// <summary>
        /// Retrieve the Api Mobile Host for the specified System Key
        /// </summary>
        /// <param name="SystemApiKey"></param>
        /// <returns></returns>
        public static Host GetApiMobile(string SystemApiKey)
        {
            if (!String.IsNullOrEmpty(SystemApiKey))
            {
                return _hiddenFrm.fRegistration.GetApiHostMobile(SystemApiKey);
            }
            return null;
        }

        /// <summary>
        /// Is Mobile Host Reachable
        /// </summary>
        /// <param name="SystemApiKey"></param>
        /// <returns></returns>
        public static bool IsApiMobileReachable(string SystemApiKey)
        {
            if (!String.IsNullOrEmpty(SystemApiKey))
            {
                return _hiddenFrm.fRegistration.IsClientReachable(SystemApiKey);
            }
            return false;
        }

        #endregion

        #region Useful Windows Client Registration API

        /// <summary>
        /// Allow retrival of different registration server
        /// </summary>
        /// <param name="UserApiKey"></param>
        /// <param name="UserApiPin"></param>
        /// <param name="host"></param>
        /// <param name="port"></param>
        public static void GetRegistrationServer(string UserApiKey, string UserApiPin, out string host, out uint port)
        {
            host = String.Empty;
            port = 0;
            string systemAPIKey = _hiddenFrm.fRegistration.RegisterNewClient(UserApiKey, UserApiPin);
            if (!String.IsNullOrEmpty(systemAPIKey))
            {
                Host hostServer = _hiddenFrm.fRegistration.GetRegistrationServer(systemAPIKey);
                if (!String.IsNullOrEmpty(hostServer.host) && hostServer.port > 0)
                {
                    host = hostServer.host;
                    port = (uint)hostServer.port;
                }
            }
        }

        /// <summary>
        /// Register a new Practice, should only be called once for a new practice
        /// </summary>
        /// <param name="ServerGuid"></param>
        /// <param name="PracticeName"></param>
        /// <param name="InternalIP"></param>
        /// <param name="ExternalIP"></param>
        /// <param name="Port"></param>
        /// <param name="ServerType"></param>
        /// <param name="UserApiKey"></param>
        /// <param name="UserApiPin"></param>
        /// <returns></returns>
        public static bool RegisterNewServerPractice(Guid ServerGuid, string PracticeName, string InternalIP, string ExternalIP, uint Port, string ServerType, out string UserApiKey, out string UserApiPin)
        {
            UserApiKey = String.Empty;
            UserApiPin = String.Empty;
            if (!String.IsNullOrEmpty(PracticeName) && (!String.IsNullOrEmpty(InternalIP) || !String.IsNullOrEmpty(ExternalIP)) &&
                Port > 0 && !String.IsNullOrEmpty(ServerType))
            {
                Server server = new Server();
                server.HostGUID = ServerGuid.ToString();
                server.InternalIP = InternalIP;
                server.ExternalIP = ExternalIP;
                server.Port = (int)Port;
                string PName = (PracticeName.Length > PRACTICENAME_LENGTH) ? PracticeName.Substring(0, PRACTICENAME_LENGTH) : PracticeName;
                bool bSuccess = _hiddenFrm.fRegistration.RegisterNewServerPractice(PName, server, ServerType, out UserApiKey, out UserApiPin);
                return bSuccess;
            }
            return false;
        }

        /// <summary>
        /// Retrieve the system api key for a userapikey and pin
        /// </summary>
        /// <param name="UserApiKey"></param>
        /// <param name="UserApiPin"></param>
        /// <returns></returns>
        public static string RegisterNewClient(string UserApiKey, string UserApiPin)
        {
            if (!String.IsNullOrEmpty(UserApiKey) && !String.IsNullOrEmpty(UserApiPin))
            {
                return _hiddenFrm.fRegistration.RegisterNewClient(UserApiKey, UserApiPin);
            }
            return String.Empty;
        }

        /// <summary>
        /// Retrieve the pin for a UserApiKey
        /// </summary>
        /// <param name="UserApiKey"></param>
        /// <returns></returns>
        public static string RetrieveUserApiKeyPin(string UserApiKey)
        {
            if (!String.IsNullOrEmpty(UserApiKey))
            {
                return _hiddenFrm.fRegistration.RetrieveNewClientPin(UserApiKey);
            }
            return String.Empty;
        }

        /// <summary>
        /// Update the server external ip, internal ip, and port
        /// </summary>
        /// <param name="ServerGuid"></param>
        /// <param name="InternalIP"></param>
        /// <param name="ExternalIP"></param>
        /// <param name="Port"></param>
        /// <returns></returns>
        public static bool UpdateServer(Guid ServerGuid, string InternalIP, string ExternalIP, uint Port)
        {
            if ((!String.IsNullOrEmpty(InternalIP) || !String.IsNullOrEmpty(ExternalIP)) && Port > 0)
            {
                Server server = new Server();
                server.HostGUID = ServerGuid.ToString();
                server.InternalIP = InternalIP;
                server.ExternalIP = ExternalIP;
                server.Port = (int)Port;
                bool bSuccess = _hiddenFrm.fRegistration.UpdateServer(server);
                return bSuccess;
            }
            return false;
        }

        /// <summary>
        /// Update the practice name for a specified userapikey
        /// </summary>
        /// <param name="UserApiKey"></param>
        /// <param name="UserApiPin"></param>
        /// <param name="PracticeName"></param>
        /// <returns></returns>
        public static bool UpdatePracticeName(string UserApiKey, string UserApiPin, string PracticeName)
        {
            if (!String.IsNullOrEmpty(UserApiKey) && !String.IsNullOrEmpty(UserApiPin) &&
                !String.IsNullOrEmpty(PracticeName))
            {
                string PName = (PracticeName.Length > PRACTICENAME_LENGTH) ? PracticeName.Substring(0, PRACTICENAME_LENGTH) : PracticeName;
                return _hiddenFrm.fRegistration.UpdatePracticeName(UserApiKey, UserApiPin, PName);
            }
            return false;
        }

        /// <summary>
        /// Callback from registration server to see if it can communicate to the specified ip / port
        /// </summary>
        /// <param name="ExternalIP"></param>
        /// <param name="Port"></param>
        /// <returns></returns>
        public static bool IsServerReachable(string ExternalIP, uint Port)
        {
            if (!String.IsNullOrEmpty(ExternalIP) && Port > 0)
            {
                Server server = new Server();
                server.ExternalIP = ExternalIP;
                server.Port = (int)Port;
                bool bRetVal = _hiddenFrm.fRegistration.IsServerReachable(server);
                return bRetVal;
            }
            return false;
        }

        /// <summary>
        /// Callback from registration server to see if the specified ip / port exposes a Pluto HostGUID
        /// </summary>
        /// <param name="ExternalIP"></param>
        /// <param name="Port"></param>
        /// <returns></returns>
        public static string RetrievePlutoHostGUID(string ExternalIP, uint Port)
        {
            if (!String.IsNullOrEmpty(ExternalIP) && Port > 0)
            {
                Server server = new Server();
                server.ExternalIP = ExternalIP;
                server.Port = (int)Port;
                string result = _hiddenFrm.fRegistration.RetrieveHostGUIDForServerFromInternet(server);
                return result;
            }
            return String.Empty;
        }

        /// <summary>
        /// Check to see if the Host Guid exists on the server
        /// </summary>
        /// <param name="ServerGuid"></param>
        /// <returns></returns>
        public static bool DoesServerHostGUIDExist(Guid HostGuid)
        {
            if (HostGuid != null)
            {
                bool bExists = _hiddenFrm.fRegistration.DoesServerHostGUIDExist(HostGuid.ToString());
                return bExists;
            }
            return false;
        }

        /// <summary>
        /// Allow the Service to communicate back to the Service that a new Version has been installed
        /// </summary>
        /// <param name="Version"></param>
        public static void ServerHasBeenUpdated(Guid HostGuid, string Version)
        {
            if (!String.IsNullOrEmpty(Version) && HostGuid != null)
            {
                _hiddenFrm.fRegistration.ServerHasBeenUpdated(HostGuid.ToString(), Version);
            }
        }

        #endregion

        #region AutoUpdate / Client / Server Calls

        public static Client[] GetExternalClients()
        {
            List<Client> clientToReturn = new List<Client>();
            Client[] clients = _hiddenFrm.fRegistration.GetClients(false);
            if (clients != null && clients.Length > 0)
            {                
                foreach (Client client in clients)
                {
                    if (!String.IsNullOrEmpty(client.host.host))
                    {
                        clientToReturn.Add(client);
                    }
                }
            }
            return clientToReturn.ToArray();
        }

        #endregion
    }
}
