using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;

namespace LLNet.GUI
{
    public class CanalTCP
    {
          #region "constructores"

        /// <summary> Crea una instancia del canal ISO8583 XML
        /// </summary>
        /// <param name="host">Direccion ip del host remoto</param>
        /// <param name="port">Puerto TCP del host remoto</param>
        /// <param name="timeout">Tiempo maximo de espera</param>
        public CanalTCP(string host,
                    string port,
                    string timeout)
        {
            this.host = host;
            this.port = port;
            this.timeout = timeout;
        }

        #endregion

        #region "variables privadas"
        /// <summary>
        /// Direccion ip del host remoto
        /// </summary>
        private string host;
        /// <summary>
        /// Puerto TCP del host remoto
        /// </summary>
        private string port;
        /// <summary>
        /// Tiempo maximo de espera
        /// </summary>
        private string timeout;
        /// <summary>
        /// TcpClient usado por el canal ISO8583 XML
        /// Cliente para un servicio de red TCP
        /// </summary>
        private System.Net.Sockets.TcpClient tcpClient;
        /// <summary>
        /// NetworkStream usado para recibir y enviar los
        /// mensajes con el TcpClient
        /// </summary>
        private NetworkStream networkStream;
        #endregion

        #region "propiedades"
        /// <summary>
        /// Puerto TCP del host remoto
        /// </summary>
        public string Host
        {
            get { return host; }
            set { host = value; }
        }

        /// <summary>
        /// Puerto TCP del host remoto
        /// </summary>
        public string Port
        {
            get { return port; }
            set { port = value; }
        }

        /// <summary>
        /// Tiempo maximo de espera
        /// </summary>
        public string Timeout
        {
            get { return timeout; }
            set { timeout = value; }
        }

        #endregion

        #region "funciones publicas"
        /// <summary> Envia un requerimiento al host remoto
        /// </summary>
        /// <param name="m">Requerimiento ISO8583 XML</param>
        /// <returns>Respuesta ISO8583 XML</returns>
        public ISOMsg Send(ISOMsg m)
        {
            ISOMsg r = null;
            try
            {
                if (Connect())
                {
                    Byte[] dataOutput = System.Text.Encoding.ASCII.GetBytes(m.toString());
                    networkStream = tcpClient.GetStream();
                    networkStream.Write(dataOutput, 0, dataOutput.Length);
                    r = receive();
                }
            }
            catch (System.Net.Sockets.SocketException ex)
            {
                GUI.CApp.ShowMessage( ex.Message ,"Error al enviar el Mensaje",false);
                try
                {
                    tcpClient.Close();
                }
                catch (ApplicationException ex1)
                {
                    GUI.CApp.ShowMessage( ex1.Message ,"No fue posible cerrar la conexion TCP",false);
                }
            }
            catch (System.IO.IOException ex2)
            {
                GUI.CApp.ShowMessage( ex2.Message ,"Error al recibir el Mensaje de Respuesta", false );
                try
                {
                    tcpClient.Close();
                }
                catch (ApplicationException ex3)
                {
                    GUI.CApp.ShowMessage( ex3.Message ,"No fue posible cerrar la conexion TCP", false );
                }
            }
            catch (ApplicationException ex4)
            {
                GUI.CApp.ShowMessage( ex4.Message ,"Error al enviar el mensaje", false );
                try
                {
                    tcpClient.Close();
                }
                catch (ApplicationException ex5)
                {
                    GUI.CApp.ShowMessage( ex5.Message ,"No fue posible cerrar la conexion TCP",false );
                }
            }
            return r;
        }
        #endregion

        #region "funciones privadas"
        /// <summary> Establece la conexion con el host remoto
        /// </summary>
        /// <returns>true: Exitoso; false: fallo</returns>
        private bool Connect()
        {
            bool connect = false;
            tcpClient = new System.Net.Sockets.TcpClient();

            try
            {
                tcpClient.ReceiveTimeout = int.Parse(this.Timeout);
                tcpClient.Connect(Host, int.Parse(Port));
                connect = true;
            }
            catch (System.Net.Sockets.SocketException ex)
            {
                System.Console.WriteLine("No fue posible conectarse via TCP", ex);
            }
            catch (ApplicationException ex1)
            {
                System.Console.WriteLine("No fue posible conectarse via TCP", ex1);
                try
                {
                    tcpClient.Close();
                }
                catch (ApplicationException ex2)
                {
                    System.Console.WriteLine("No fue posible cerrar la conexion TCP", ex2);
                }
            }
            return connect;
        }

        /// <summary>Recibe un mensaje ISO8583 XML
        /// </summary>
        /// <returns>Mensaje ISO8583 XML</returns>
        private ISOMsg receive()
        {
            string response = "";
            ISOMsg r = null;
            byte[] dataInput = null;
            try
            {
                while (true)
                {
                    dataInput = new byte[tcpClient.ReceiveBufferSize + 1];
                    Int32 bytes = networkStream.Read(dataInput, 0, Convert.ToInt32(tcpClient.ReceiveBufferSize));
                    response += System.Text.Encoding.ASCII.GetString(dataInput, 0, bytes);
                    if (response.Substring(response.Length - 11).Equals("</isomsg>" + Convert.ToChar(0x0d) + Convert.ToChar(0x0a)))
                    {
                        break;
                    }
                }
                r = ISOMsg.unpack(response);
                tcpClient.Close();
            }

            catch (System.IO.IOException ex)
            {
                GUI.CApp.ShowMessage( ex.Message ,"Error al recibir el Mensaje de Respuesta",false);
                try
                {
                    tcpClient.Close();
                }
                catch (ApplicationException ex2)
                {
                     GUI.CApp.ShowMessage( ex2.Message ,"No fue posible cerrar la conexion TCP",false);
                }
            }
            catch (ApplicationException ex1)
            {
                 GUI.CApp.ShowMessage( ex1.Message ,"Error al recibir el Mensaje de Respuesta",false);
                try
                {
                    tcpClient.Close();
                }
                catch (ApplicationException ex2)
                {
                     GUI.CApp.ShowMessage( ex2.Message ,"No fue posible cerrar la conexion TCP",false);
                }
            }
            return r;
        }

        #endregion
    }
}
