//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop

#include "CtrlElemento.h"
#include "CtrlSocket.h"
#include "CtrlPPal.h"

#pragma package(smart_init)
//---------------------------------------------------------------------------
//   Important: Methods and properties of objects in VCL can only be
//   used in a method called using Synchronize, for example:
//
//      Synchronize(UpdateCaption);
//
//   where UpdateCaption could look like:
//
//      void __fastcall ThreadSocket::UpdateCaption()
//      {
//        Form1->Caption = "Updated in a thread";
//      }
//---------------------------------------------------------------------------
__fastcall ThreadSocket::ThreadSocket(bool CreateSuspended)
    : TThread(CreateSuspended)
{
    CtrlCOP = 0;
    FreeOnTerminate = false;
}
//---------------------------------------------------------------------------
void __fastcall ThreadSocket::SetSocket( AnsiString IP_dst, int Socket )
{
  ClientSocket = new TClientSocket( CtrlPPal->Owner );
  ClientSocket->OnConnect    = SocketConnect;
  ClientSocket->OnDisconnect = SocketDisconnect;
  ClientSocket->OnError      = SocketError;
  ClientSocket->ClientType   = ctBlocking;
  ClientSocket->Address      = IP_dst;
  ClientSocket->Port         = Socket;

  SocketCreated = true;
}
//---------------------------------------------------------------------------
void __fastcall ThreadSocket::SocketDisconnect(TObject *Sender, TCustomWinSocket *Socket)
{
   CtrlPPal->Memo1->Lines->Insert( 0, (Now()).DateTimeString() + " :: Tramites Finalizados " + Socket->LocalAddress  + "  :: " + ClientSocket->Address );
}
//---------------------------------------------------------------------------
void __fastcall ThreadSocket::SocketError(TObject *Sender,
      TCustomWinSocket *Socket, TErrorEvent ErrorEvent, int &ErrorCode)
{
   if ( OWNER_Element )
   {
     OWNER_Element->StatusCode = ERROR;                     // Estamos en proceso de COMPROBACION / ERROR
     OWNER_Element->BlinkCode = IP_OFF;                     // --- ERROR INTENTANDO COMUNICAR --
//     OWNER_Element->Blink->Enabled = true;                  // Activamos el parpadeo
    OWNER_Element->Blink->Interval = 500;
   }

   CtrlPPal->Memo1->Lines->Insert( 0, (Now()).DateTimeString() + " :: Cliente ˇ ERROR ! " + AnsiString( ErrorCode ) + "::" + Socket->LocalAddress + "  :: " + ClientSocket->Address );
   ErrorCode = 0;
   ClientSocket->Active = false;
}
//---------------------------------------------------------------------------
void __fastcall ThreadSocket::SocketConnect(TObject *Sender,
      TCustomWinSocket *Socket)
{
  TWinSocketStream *pStream;

  CtrlPPal->Memo1->Lines->Insert( 0, (Now()).DateTimeString() + " :: Cliente Conectado ::" + Socket->LocalAddress + "  :: " + ClientSocket->Address );

  // create a TWinSocketStream for reading and writing
  pStream = new TWinSocketStream( Socket, 60000 );
  try
  {
    // fetch and process commands until the connection or thread is terminated
    if ( !Terminated && ClientSocket->Active )
    {
      try
      {
        int CodOp; double doubleT = (double)CtrlTiempo;
        CodOp = (CtrlCOP == QueryTIME) ? 6661 : (CtrlCOP == CloseWINDOWS) ? 6660 : (CtrlCOP == SettingSTATUS ) ? 6669 : (CtrlCOP == sendLIST) ? 6662 : 0;
        pStream->Write( &CodOp, sizeof(int) );
        switch( CtrlCOP )
        {
         case QueryTIME:
          double dTiempoInicio;
          pStream->WaitForData(30000);
          pStream->Read( &doubleT, sizeof(double) );
          pStream->WaitForData(30000);
          pStream->Read( &dTiempoInicio, sizeof(double) );
          if ( OWNER_Element )
            OWNER_Element->ClientTimeIs( doubleT, dTiempoInicio );               // Comunicamos el tiempo que dice tener el Clt.

          CtrlPPal->Memo1->Lines->Insert( 0, (Now()).DateTimeString() + " :: Peticion de Tiempo " + Socket->LocalAddress  + "  :: " + ClientSocket->Address );
          break;
         case CloseWINDOWS:
          CodOp = CtrlState;
          pStream->Write( &CodOp, sizeof(int) );
          pStream->Write( &doubleT, sizeof(double) );
          if ( OWNER_Element )
          {
            OWNER_Element->StatusCode = ERROR;                     // Estamos en proceso de COMPROBACION / ERROR
            OWNER_Element->BlinkCode = IP_OFF;                     // --- ERROR INTENTANDO COMUNICAR --
            OWNER_Element->Blink->Interval = 500;
          }
          CtrlPPal->Memo1->Lines->Insert( 0, (Now()).DateTimeString() + " :: Cierre de Windows " + Socket->LocalAddress  + "  :: " + ClientSocket->Address );
          break;
         case SettingSTATUS:
          CodOp = CtrlState;
          pStream->Write( &CodOp, sizeof(int) );
          pStream->Write( &doubleT, sizeof(double) );
          if ( OWNER_Element )
          {
            OWNER_Element->BlinkCode = NONE;                 // Desactivamos el parpadeo
            OWNER_Element->StatusCode = CtrlState ? WORKING : FREE;// Estamos en proceso de COLOCAR ESTADO
            OWNER_Element->Blink->Interval = 60000;
            OWNER_Element->ShowElementInfo();
            // Contabilizamos la conexión
            if ( CtrlState )
               OWNER_Element->HistoricoTermON( CtrlTiempo );
          }

          CtrlPPal->Memo1->Lines->Insert( 0, (Now()).DateTimeString() + " :: Cambio de estado (" + (CtrlState ? "ON":"OFF") + ")" + Socket->LocalAddress  + "  :: " + ClientSocket->Address );
          break;
         case sendLIST:
          CodOp = CtrlPPal->siMinimizar->Count;
//          CtrlPPal->Memo1->Lines->Insert( 0, "Elementos A: " + AnsiString( CodOp ) );
          pStream->Write( &CodOp, sizeof(int) );
          for ( int i=0; i<CodOp; i++ )
            pStream->Write( (void *)((CtrlPPal->siMinimizar->Strings[i]).c_str()), sizeof(char)*15 );
          CodOp = CtrlPPal->noMinimizar->Count;
          pStream->Write( &CodOp, sizeof(int) );
          for ( int i=0; i<CodOp; i++ )
            pStream->Write( (void *)((CtrlPPal->noMinimizar->Strings[i]).c_str()), sizeof(char)*15 );


          CodOp = CtrlPPal->snMinimizar->Count;
          pStream->Write( &CodOp, sizeof(int) );
          for ( int i=0; i<CodOp; i++ )
            pStream->Write( (void *)((CtrlPPal->snMinimizar->Strings[i]).c_str()), sizeof(char)*15 );
          CodOp = CtrlPPal->noAbrir->Count;
          pStream->Write( &CodOp, sizeof(int) );
          for ( int i=0; i<CodOp; i++ )
            pStream->Write( (void *)((CtrlPPal->noAbrir->Strings[i]).c_str()), sizeof(char)*15 );

          break;
         default:
          break;
        }
        pStream->WaitForData(30000);
        pStream->Read( &CodOp, sizeof(int) );
        if ( CodOp != 54321 )
        {
          CtrlPPal->Memo1->Lines->Insert( 0, (Now()).DateTimeString() + " :: Cliente RESPONDE ANORMALMENTE  " + Socket->LocalAddress );
        }
      }
      catch (Exception &E)
      {
        if (!E.ClassNameIs("EAbort"))
        {
            if ( OWNER_Element )
            {
             OWNER_Element->StatusCode = ERROR;                     // Estamos en proceso de COMPROBACION / ERROR
             OWNER_Element->BlinkCode = IP_OFF;                     // --- ERROR INTENTANDO COMUNICAR --
//     OWNER_Element->Blink->Enabled = true;                  // Activamos el parpadeo
    OWNER_Element->Blink->Interval = 500;
            }
            CtrlPPal->Memo1->Lines->Insert( 0, (Now()).DateTimeString() + " :: Error en el HILO de " + Socket->LocalAddress );
        }
      }
    }
  }
  __finally
  {
    delete pStream;
    OWNER_Element = NULL;
    Socket->Close();
  }
}
//---------------------------------------------------------------------------
void __fastcall ThreadSocket::Execute()
{
  if ( SocketCreated )
  {
    CtrlPPal->AnySocketActive++;
    try {
        ClientSocket->Active = true;
    } catch (Exception &E) {
        if (!E.ClassNameIs("EAbort"))
        {
           if ( OWNER_Element )
           {
             OWNER_Element->StatusCode = ERROR;                     // Estamos en proceso de COMPROBACION / ERROR
             OWNER_Element->BlinkCode = IP_OFF;                     // --- ERROR INTENTANDO COMUNICAR --
//     OWNER_Element->Blink->Enabled = true;                  // Activamos el parpadeo
    OWNER_Element->Blink->Interval = 500;
           }
          CtrlPPal->Memo1->Lines->Insert( 0, (Now()).DateTimeString() + " :: Error en el HILO de " + ClientSocket->Address + " (" + E.Message+")" ); // you must write HandleThreadException
        }
    }

    while ( !Terminated && ClientSocket->Active );  // Do nothing
    CtrlPPal->AnySocketActive--;
  }
}
//---------------------------------------------------------------------------


////////////////// GESTION DE LOS HILOS DE COMUNICACIÓN /////////////////////
void __fastcall ThreadSocket::Terminate(TObject *Sender) // this is the OnTerminate handler
{
  if ( SocketCreated )
  {
      if ( ClientSocket->Active )
        ClientSocket->Active = false;
      delete ClientSocket;
      SocketCreated = false;
  }
  pCache->Add( this ); // add pointer to this thread to the cache
}
//---------------------------------------------------------------------------
//###########################################################################
//###########################################################################
//###########################################################################


