/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
 *  Copyright (C) Marco Klein alias WorldRacer, WorldRacer92, WorldRacer_original  *
 *                                                                                 *
 *   This program is free software: you can redistribute it and/or modify          *
 *   it under the terms of the GNU General Public License as published by          *
 *   the Free Software Foundation, either version 3 of the License, or             *
 *   (at your option) any later version.                                           *
 *                                                                                 *
 *   This program is distributed in the hope that it will be useful,               *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of                *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                 *
 *   GNU General Public License for more details.                                  *
 *                                                                                 *
 *   You should have received a copy of the GNU General Public License             *
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.         *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace devNetworks
{
    /// <summary>
    /// This class represents a client
    /// </summary>
    public class Client
    {
        #region Public Attributes
        /// <summary>
        /// Socket. (TcpClient)
        /// </summary> 
        public System.Net.Sockets.TcpClient Socket
        {
            get { return _Socket; }
            set { _Socket = value; }
        }
        #endregion
 
        #region Private Attributes
 
        // Thread for handling server Messages
        System.Threading.Thread _ClientThread = null;
 
        // Socket to handle with
        private System.Net.Sockets.TcpClient _Socket = null;
 
        // IP-Adress of the endpoint 
        private string _IPAdress = string.Empty;
 
        // Port to connect at the entpoint
        private int _Port = 0;
 
        // Contains whether we are connected or not.
        private bool _Connected = false;
 
        // Bufferlength
        int _BufferLength = 4096;
 
        // Get a client stream for reading and writing.
        //  Stream stream = client.GetStream();
        System.Net.Sockets.NetworkStream _Stream;
 
        // How shall the messages be encoded to?
        System.Text.Encoding _EncodingInstance = System.Text.Encoding.ASCII;
        #endregion
 
        #region Constructor
        /// <summary>
        /// Initializes a Client
        /// </summary>
        /// <param name="IPAdress">IP-Adress of the endpoint</param>
        /// <param name="Port">Port to connect at the entpoint</param>
        /// <param name="ConnectImmediately">Should I connect directly?</param>
        /// <param name="BufferLength">How long shall the received messages be?</param>
        /// <param name="EncodingInstance">How shall the messages be encoded to?</param>        
        public Client(string IPAdress, int Port, System.Text.Encoding EncodingInstance, bool ConnectImmediately = false, int BufferLength = 4096)
        {
            // Save the values
            if (BufferLength > 0)
            {
                _BufferLength = BufferLength;
            }
            else
            {
                _BufferLength = 4096;
            }
            
            _EncodingInstance = EncodingInstance;
            
            // If we shall connect immediately...
            if (ConnectImmediately)
            {
                try
                {
                    // Create a socket which connects immediately
                    _Socket = new System.Net.Sockets.TcpClient(IPAdress, Port);
                    _Connected = _Socket.Connected;
                }
                catch (Exception)
                {
 
                }
            }
            else
            {
                // Else, initialize a new, not connecting socket
                _Socket = new System.Net.Sockets.TcpClient();
                _IPAdress = IPAdress;
                _Port = Port;
            }            
        }
        #endregion
 
        #region Private Methods
        /// <summary>
        /// Worker Function for client listening
        /// </summary>
        private void _ClientThreadFunc()
        {
            // Enter listening loop
            while (true)
            {
                // Give the other threads 1 miliseconds to do their work, else a 100% CPU load is guaranteed.
                System.Threading.Thread.Sleep(1);
 
                // Message Bytes
                Byte[] data = new Byte[_BufferLength];
 
                // String to store the response ASCII representation.
                string responseData = string.Empty;
 
                // Read the first batch of the TcpServer response bytes.
                Int32 bytes = _Stream.Read(data, 0, data.Length);
 
                // Placeholder for writing in the recieved data.
                responseData = _EncodingInstance.GetString(data, 0, bytes);
 
                // Call MessageReceived event, if it has event handlers
                if (MessageRecieved != null)
                {
                    MessageRecieved(this, responseData);
                }
            }
        }
        #endregion
 
        #region Public Methods
        /// <summary>
        /// Sends a message to the Server
        /// </summary>
        /// <param name="Message">Message to send</param>
        public void SendMessage(string Message)
        {
            // Convert string into bytes
            byte[] msg = _EncodingInstance.GetBytes(Message);
 
            // Send the bytes to the stream.
            _Stream.Write(msg, 0, msg.Length);
        }
        /// <summary>
        /// Connect to the endpoint
        /// </summary>
        /// <returns></returns>
        public bool Connect()
        {            
            // If we have an IP
            if (_IPAdress == string.Empty || _Port == 0)
            {
                // If not, return false
                return false;
            }
            else
            {
                // If there was a socket before
                if (Socket != null)
                {
                    // and if it was connected, disconnect it
                    if (!_Socket.Connected)
                        _Socket.Close();
                }
                else
                {
                    // else create a new one.
                    _Socket = new System.Net.Sockets.TcpClient();
                }
 
                // If everything's fine, connect it.
                _Socket.Connect(_IPAdress, _Port);
                
                // If the socket is connected
                if (_Socket.Connected)
                {
                    // Retrieve a stream
                    _Stream = _Socket.GetStream();
 
                    // And start the listening thread
                    _ClientThread = new System.Threading.Thread(new System.Threading.ThreadStart(_ClientThreadFunc));
                    _ClientThread.Start();                    
                }
 
                // Last but not least, return success or fail message
                return _Socket.Connected;
            }
        }        
        #endregion
 
        #region Events
        /// <summary>
        /// Called when the client received a message
        /// </summary>
        /// <param name="sender">This ServerClient</param>
        /// <param name="Message">Received message</param>
        public delegate void MessageRecievedDelegate(object sender, string Message);
 
        /// <summary>
        /// Called when the client received a message
        /// </summary>
        public event MessageRecievedDelegate MessageRecieved;
        #endregion
 
    }
}