/// <summary>
 /// Remove client from the server.
 /// </summary>
 /// <param name="server"></param>
 /// <param name="client"></param>
 public static void Release(GXServer server, GXClient client)
 {
     lock (m_syncRoot)
     {
         try
         {
             if (client.Tracing)
             {
                 server.Media.OnTrace -= new TraceEventHandler(client.media_OnTrace);
                 client.Tracing = false;
             }
         }
         catch (Exception ex)
         {
             //Ignore if fails.
             System.Diagnostics.Debug.WriteLine(ex.Message);
         }
         int cnt = 0;
         lock (server.Clients.SyncRoot)
         {                    
             cnt = server.Clients.Count;
         }
         if (cnt == 1)
         {
             server.m_Sender.Closing.Set();
             server.m_Receiver.Closing.Set();
             server.m_SendThread.Join();
             server.m_ReceiverThread.Join();
             if (server.Media != null)
             {                        
                 if (server.Media != null)
                 {
                     server.Media.Close();
                 }                        
             }
             server.Clients.Remove(client);
             m_instances.Remove(server.m_Name);
         }
         else
         {
             server.Clients.Remove(client);
         }
     }
 }
        /// <summary>
        /// GXServer class factory.
        /// </summary>
        public static GXServer Instance(Gurux.Common.IGXMedia media, GXClient client)
        {
            lock (m_syncRoot)
            {                
                if (m_instances == null)
                {
                    m_instances = new Dictionary<string, GXServer>();
                    Handlers = new Dictionary<IGXEventHandler, object>();
                }
                string name = media.Name;
                if (string.IsNullOrEmpty(name))
                {
                    name = media.MediaType;
                }
                GXServer server;
                if (m_instances.ContainsKey(name))
                {
                    server = m_instances[name];
                    if (server.m_bParseReceivedPacket != client.ParseReceivedPacket)
                    {
                        throw new Exception(Resources.ServerFailedToAcceptNewClientParseReceivedPacketValueIsInvalid);
                    }
					if (!object.Equals(server.m_ReplyPacket.Eop, client.Eop))
                    {
                        throw new Exception(Resources.ServerFailedToAcceptNewClientEopValueIsInvalid);
                    }
                    if (!object.Equals(server.m_ReplyPacket.Bop, client.Bop))
                    {
                        throw new Exception(Resources.ServerFailedToAcceptNewClientBopValueIsInvalid);
                    }
                    if (server.m_ReplyPacket.ByteOrder != client.ByteOrder)
                    {
                        throw new Exception(Resources.ServerFailedToAcceptNewClientByteOrdersAreNotSame);
                    }
                    if (server.m_ReplyPacket.MinimumSize != client.MinimumSize)
                    {
                        throw new Exception(Resources.ServerFailedToAcceptNewClientMinimumSizeValueIsInvalid);
                    }
                    if (!server.m_ReplyPacket.ChecksumSettings.Equals(client.ChecksumSettings))
                    {
                        throw new Exception(Resources.ServerFailedToAcceptNewClientChecksumSettingsAreNotSame);
                    }                    
                    lock (server.Clients.SyncRoot)
                    {
                        server.Clients.Add(client);
                    }
                    return server;
                }                
                server = new GXServer(name);
                server.m_ReplyPacket = client.CreatePacket();
                lock (server.Clients.SyncRoot)
                {
                    server.Clients.Add(client);
                }
                server.m_bParseReceivedPacket = client.ParseReceivedPacket;
                media.OnClientDisconnected += new Gurux.Common.ClientDisconnectedEventHandler(server.OnClientDisconnected);
                media.OnClientConnected += new Gurux.Common.ClientConnectedEventHandler(server.OnClientConnected);
                media.OnError += new Gurux.Common.ErrorEventHandler(server.OnError);
                media.OnMediaStateChange += new Gurux.Common.MediaStateChangeEventHandler(server.OnMediaStateChange);
                media.OnReceived += new Gurux.Common.ReceivedEventHandler(server.OnReceived);
                server.m_Media = media;
                m_instances[name] = server;
                server.m_Sender = new GXServerSender(server);
                server.m_Receiver = new GXServerReceiver(server);                
                server.m_SendThread = new Thread(new ThreadStart(server.m_Sender.Run));
                server.m_SendThread.IsBackground = true;
                server.m_SendThread.Start();
                server.m_ReceiverThread = new Thread(new ThreadStart(server.m_Receiver.Run));
                server.m_ReceiverThread.IsBackground = true;
                server.m_ReceiverThread.Start();
                return server;
            }
        }
		/// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="parent"></param>
        public GXServerReceiver(GXServer parent)
        {
            Parent = parent;
        }
 /// <summary>
 /// Closes the connection to the GXCom. 
 /// The used media is not closed, if there is more than one client that uses GXCom. 
 /// The media is closed, when the last GXClient closes connection.
 /// It is recommended to use Close method, instead of MediaClose. 
 /// </summary>
 /// <seealso cref="CloseMedia">CloseMedia</seealso> 
 public void CloseServer()
 {
     if (m_Server != null)
     {
         NotifyVerbose(this, Resources.ClientClosesServer);
         GXServer.Release(m_Server, this);
         m_Server = null;
         NotifyUnload();
     }
 }
 /// <summary>
 /// Assigns new media, after media settings are changed.
 /// </summary>
 /// <remarks>
 /// The media must be created before calling this method. 
 /// See methods EnumMedias and SelectMedia. 
 /// Active media is implemented with GetCurrentMedia method.
 /// AssignMedia closes the active media and selects a new one. 
 /// The protocol settings do not change, when AssignMedia is called. 
 /// After AssignMedia is called, the media must be opened with MediaOpen method.
 /// The new media is selected with the SelectMedia method.
 /// </remarks>
 /// <param name="media">New media component.</param>
 /// <seealso cref="SelectMedia">SelectMedia</seealso> 
 /// <seealso cref="Properties">Properties</seealso> 
 public void AssignMedia(Gurux.Common.IGXMedia media)
 {
     IGXMediaContainer tmp = media as IGXMediaContainer;
     if (tmp != null)
     {                
         media = (media as IGXMediaContainer).Media;
         media.MediaContainer = tmp;
     }
     CloseServer();
     m_MediaType = "";
     if (media != null)
     {
         if (media != null)
         {
             m_MediaType = media.MediaType;
             m_MediaSettings = media.Settings;
         }
         if (m_MediaSettings != null)
         {
             m_MediaSettings = m_MediaSettings.Replace("\r\n", "");
         }
         NotifyLoad();
         //Notify that media is changed.
         NotifyMediaStateChange(MediaState.Changed);
         m_Server = GXServer.Instance(media, this);
         //If handler is given before server is up.
         if (Handler != null)
         {
             m_Server.AddEventHandler(Handler, Clients);
             Handler = null;
             Clients = null;
         }
         //Notify is media is already open.
         if (media.IsOpen)
         {
             NotifyMediaStateChange(MediaState.Open);
         }
     }
 }
 /// <summary>
 /// Constructor.
 /// </summary>
 /// <param name="parent"></param>
 public GXServerSender(GXServer parent)
 {
     Parent = parent;			            
 }