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

#include <registry.hpp>
#include <ShellAPI.hpp>
#include <SysUtils.hpp>
#include <stdlib.h>
#include <math.h>

#include "CtrlPPal.h"
#include "TStatus.h"
#include "CtrlSocket.h"
#include "CtrlCfg.h"
#include "CtrlElemento.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "CoolForm"
#pragma resource "*.dfm"
TCtrlPPal *CtrlPPal;

////////////////////////////////////////////////////////////////////////////////
#define MsgDEMO "No olvide que esto es solo una demostración.\nPara adquirir la aplicación completa:\nPongase en contacto con JD soft.\n\te-mail: jd@infdj.com\n\tTlf: 95561-58-54 Fax: 95561-49-13"
#define DEMOSTRACION
#ifdef DEMOSTRACION
  #define CnElementosMAX 3
#else
  #define CnElementosMAX 11 // Num. máximo de elementos permitidos
#endif
////////////////////////////////////////////////////////////////////////////////

#define opLOG "Historic.log"

//---------------------------------------------------------------------------
__fastcall TCtrlPPal::TCtrlPPal(TComponent* Owner)
    : TForm(Owner)
{
 // Remote Control
 ClientHook = false;
 ServerHook = false;
  RemoteStart -> Visible = true;


  remoteBack->Visible = false;
  remoteLog->Visible = false;
  remoteClose->Visible = false;
 // Remote Control

 siMinimizar = new TStringList();   // Listado de Aplicaciones Especiales
 noMinimizar = new TStringList();   // Listado de Aplicaciones Especiales
 snMinimizar = new TStringList();   // Listado de Aplicaciones Especiales
 noAbrir     = new TStringList();   // Listado de Aplicaciones Especiales

 LoadProtectedList();               // Carga los listados de Aplicaicones protegidas

 nElementosMAX = CnElementosMAX;    // Número maximos de elementos
 Elementos = new TList();           // Lista de Elementos en funcionamiento
 AnySocketActive = 0;               // Nº de socket REALMENTE activos
 pCache = new TThreadList;          // Lista de Hilos de comunicación

 ChangePositionEnabled = false;     // Permiso para mover la posición de los elementos

 CheckAppIntegrity();               // El directorio de instalacion no puede moverse
 StartEventRecorder();              // Comenzamos la grabación de eventos
 TbElementosCFG->Active = true;     // Abrimos la tabla de elementos para hacerlos visibles
 TbPersonas->Active = true;
}
//---------------------------------------------------------------------------
void __fastcall TCtrlPPal::LoadProtectedList(void)
{
  //LoadProtectedList();
}
//---------------------------------------------------------------------------
void __fastcall TCtrlPPal::StartEventRecorder(void)
{
 TbHistorial->Active = true;        // Tabla de eventos del sistema
 try {
                                    // Cargamos todos los eventos anteriores
     Memo1->Lines->LoadFromFile( opLOG );
                                    // Si hay demasiados registros
     if ( Memo1->Lines->Count > 700 )
     {
       for ( int i=0; i<100; i++ )  // Eliminamos las 100 últimas entradas
        Memo1->Lines->Delete( 3 );
     }
 } catch(...) {
     Memo1->Lines->Clear();         // En caso de error, las eliminamos todas
 }
                                    //Fecha y hora del inicio de sesión
 Memo1->Lines->Insert( 0, (Now()).DateTimeString() + " :: Inicio de la sesión" );
}
//---------------------------------------------------------------------------
void __fastcall TCtrlPPal::iCloseDblClick(TObject *Sender)
{
 Close();
}
//---------------------------------------------------------------------------
void __fastcall TCtrlPPal::iMinClick(TObject *Sender)
{
  Application->Minimize();
}
//---------------------------------------------------------------------------
void __fastcall TCtrlPPal::iPosVClick(TObject *Sender)
{
#ifdef DEMOSTRACION
 ShowMessage( MsgDEMO );
#endif
  if ( ChangePositionEnabled || ( !ChangePositionEnabled && InputBox( "Programa BETA!!!", "Modificar:", "¿Que Modificar?") == "Esto es una beta" ) )
  {
    Graphics::TBitmap *Picture;

    ChangePositionEnabled = !ChangePositionEnabled;

    Picture = iPosV->GlyphNormal;
    iPosV->GlyphNormal = iPosV->GlyphPress;
    iPosV->GlyphPress  = Picture;
  }
}
//---------------------------------------------------------------------------
/**
 Comprueba que el directorio de la aplicación es siempre el mismo

 (De este modo, la aplicación no correra en ningún directorio distinto, del
  que se eligió para instalar)
**/
void __fastcall TCtrlPPal::CheckAppIntegrity(void)
{
  TRegistry *Registro;
  Registro = new TRegistry;
  Registro -> OpenKey( "\\Software\\JDsoft\\CtrlMstr", true );
  AnsiString AppPath;

   if ( ! Registro->ValueExists( "AppPath" ) )
   {
     Registro -> WriteString( "AppPath", Application->ExeName );
   } else {
     AppPath = Registro -> ReadString( "AppPath" );
     if ( AppPath != Application->ExeName )
     {
      ShowMessage( "Copia corrupta o ilegal del programa.\nVuelva a reinstalar el producto." );
      nElementosMAX = 0;
     }
   }

   AnsiString DiskSerial;
   char VolumeLabel[255], FileSystem[255];
   DWord SerialNumber, DW, SysFlags;

   GetVolumeInformation( "C:\\", VolumeLabel, 250, &SerialNumber, &DW, &SysFlags, FileSystem, 250);
   DiskSerial = AnsiString( ltoa(SerialNumber, FileSystem,10) );


   if ( ! Registro->ValueExists( "SerialNum" ) )
   {
     AnsiString Serial;
     Serial = InputBox( "Registrando el Programa:", "Número de Serie:", DiskSerial );
     if ( ! Manipula2( DiskSerial, Serial ) )
     {
       Registro -> WriteString( "SerialNum", Serial );
     }
   }
   if ( Manipula( DiskSerial, Registro -> ReadString( "SerialNum" ) ) )
   {
      ShowMessage( "Copia corrupta o ilegal del programa.\nVuelva a reinstalar el producto." );
      nElementosMAX = 0;
      Registro -> DeleteValue( "SerialNum" );
      Registro -> DeleteKey( "\\Software\\JDsoft\\CtrlMstr\\SerialNum" );
   }
}
//-----------------
bool __fastcall TCtrlPPal::Manipula2(AnsiString Serial, AnsiString Image)
{
 char buffer[80];
 AnsiString Sol;
 double ser = Serial.ToDouble();
 if ( ser < 0 ) ser = -1*ser;
 Sol = ltoa(sqrtl(ser), buffer, 10);
#ifndef DEMOSTRACION
 if ( Image == Sol )
#endif
  return false;

 return true;
}
//-----------------
bool __fastcall TCtrlPPal::Manipula(AnsiString Serial, AnsiString Image)
{
 char buffer[80];
 AnsiString Sol;
 double ser = Serial.ToDouble();
 if ( ser < 0 ) ser = -1*ser;
 Sol = ltoa(sqrtl(ser), buffer, 10);
#ifndef DEMOSTRACION
 if ( Image == Sol )
#endif
  return false;

 return true;
}
//---------------------------------------------------------------------------
void __fastcall TCtrlPPal::FormDestroy(TObject *Sender)
{
 delete siMinimizar;
 delete noMinimizar;
 delete snMinimizar;
 delete noAbrir;

 for( int i=0; i < Elementos->Count; i++ )
  delete (TElemento *)Elementos->Items[i];
 delete Elementos;
}
//---------------------------------------------------------------------------
void __fastcall TCtrlPPal::NewElementAt(int X, int Y, int NumEl, AnsiString IP, AnsiString Name )
{
  TElemento *Elemento;                          // Elemento a ser insertado
  Elemento = new TElemento(this);               // Pedimos memoria para él
  Elemento->Left = X;                           //
  Elemento->Top  = Y;                           //  FIJAMOS SUS PROPIEDADES
  Elemento->AutoSize = true;                    //
  Elemento->Transparent = true;                 //
  Elemento->PopupMenu = mElementoCFG;           // Menú contextual
  Elemento->OnDblClick  = ElementoDblClick;     //

  Elementos->Add( Elemento );                   // Añadimos el elemento a la lista
                                                // Lo hacemos visible
  Pizarra->InsertControl( Elemento );

  Elemento->SetElemento( NumEl, IP, Name );     // Y comenzamos la comunicación
}
//---------------------------------------------------------------------------
void __fastcall TCtrlPPal::PizarraDblClick(TObject *Sender)
{
 POINT MousePos;
 int X, Y;

 // Si lo que quiere es reubicar un nuevo elemento
 if ( ChangePositionEnabled )
 {
#ifndef DEMOSTRACION
   // Anexamos un nuevo elemento a la lista (Si no hemos llegado al límite)
   if ( Elementos->Count < nElementosMAX )
   {
        GetCursorPos(&MousePos);
        X = MousePos.x - Left - Pizarra->Left - iElementoV->Picture->Width  / 2;
        Y = MousePos.y - Top - Pizarra->Top  - iElementoV->Picture->Height / 2 ;
    try {
        // Lo damos de Alta en la tabla
/*
        TbElementosCFG -> InsertRecord( ARRAYOFCONST(
            ( Null,                 // Numero de Elemento
              X,                            // Posición X
              Y,                            // Posición Y
              false, "0.0.0.0", "new"+AnsiString(Elementos->Count)
            ) ) );
*/

        AnsiString NameOfElement = "new"+AnsiString(TbElementosCFG->FieldByName("NumElement")->AsInteger);

        TbElementosCFG -> Insert();
        TbElementosCFG -> Edit();
        TbElementosCFG -> FieldByName( "PosX" )-> AsInteger = X;
        TbElementosCFG -> FieldByName( "PosY" )-> AsInteger = Y;
        TbElementosCFG -> FieldByName( "Activo" )-> AsBoolean = false;
        TbElementosCFG -> FieldByName( "IP" )-> AsString = "0.0.0.0";
        TbElementosCFG -> FieldByName( "Name" )-> AsString = NameOfElement;
        TbElementosCFG -> Post();

        NewElementAt( X, Y, TbElementosCFG->FieldByName("NumElement")->AsInteger, "0.0.0.0", NameOfElement );
        Memo1->Lines->Insert( 0, (Now()).DateTimeString() + " :: Inserción de nuevos elementos" );
    } catch (...) {
        ShowMessage( "¿¿¿ SIN MEMORIA ???\nTu Güindows está petando" );
    }
   } else
    ShowMessage( "Ha superado el máximo número de elementos\n¡¡¡ IMPOSIBLE AÑADIR MAS !!!" );
#else
 ShowMessage( MsgDEMO );
#endif
 }
}
//---------------------------------------------------------------------------
void __fastcall TCtrlPPal::EliminarElemento(TObject *Sender)
{
 if ( ServerHook ) return;

 int TraceMeHacker;
 TraceMeHacker = Elementos->Count;

#ifndef DEMOSTRACION
 if ( ChangePositionEnabled )
 {
   TElemento *Elemento = (TElemento *)(mElementoCFG->PopupComponent);

   // Eliminamos el objeto de la tabla
   if ( TbElementosCFG -> Locate( "NumElement", Elemento->NumElemento, TLocateOptions() << loCaseInsensitive ) )
   {
      TbElementosCFG -> Delete();                  // Eliminamos el elemento de la TABLA
      Memo1->Lines->Insert( 0, (Now()).DateTimeString() + " :: Elemento nº " + AnsiString( Elemento->NumElemento ) + ", eliminado." );

      Pizarra->RemoveControl( Elemento );          // Eliminamos el elemento de la PIZARRA
      Elementos->Remove( Elemento );               // Eliminamos el elemento de la MEMORIA
      Elementos->Pack();
   }
 }
#else

 ShowMessage( MsgDEMO );

#endif

 if ( TraceMeHacker == Elementos->Count )
     ShowMessage( "Lo siento pero carece de permisos para modificar los terminales.\n¡¡Su intento ha quedado registrado!!" );

}
//---------------------------------------------------------------------------
void __fastcall TCtrlPPal::TbElementosCFGBeforeOpen(TDataSet *DataSet)
{
 // Si la tabla no existe, la creamos
 if ( access( (TbElementosCFG -> TableName).c_str(), 0 ) != 0 )
 {
	 // Usamos la propiedad FielDefs para definir
	 // las columnas que contendrá la tabla
     TbElementosCFG -> FieldDefs -> Clear();

	 TbElementosCFG -> FieldDefs -> Add("NumElement",  ftAutoInc,  0, false );
	 TbElementosCFG -> FieldDefs -> Add("PosX",        ftInteger,  0, false );
	 TbElementosCFG -> FieldDefs -> Add("PosY",        ftInteger,  0, false );
	 TbElementosCFG -> FieldDefs -> Add("Activo",      ftBoolean,  0, false );
	 TbElementosCFG -> FieldDefs -> Add("IP",          ftString,  15, false );
	 TbElementosCFG -> FieldDefs -> Add("Name",        ftString,   8, false );
	 TbElementosCFG -> FieldDefs -> Add("Comienzo",    ftDateTime, 0, false );
	 TbElementosCFG -> FieldDefs -> Add("Tiempo",      ftDateTime, 0, false );

     TbElementosCFG -> IndexDefs-> Clear();
	 TbElementosCFG->IndexDefs->Add("Primary", "NumElement", TIndexOptions() << ixPrimary << ixUnique );

	 // Creamos la base...
	 TbElementosCFG -> CreateTable();
     Memo1->Lines->Insert( 0, (Now()).DateTimeString() + " :: Iniciando sistema por primera vez..." );
 }
}
//---------------------------------------------------------------------------
void __fastcall TCtrlPPal::TbElementosCFGAfterOpen(TDataSet *DataSet)
{
  int i;   HoraActual = TDateTime::CurrentTime();

  // Cargamos todos los elementos
  TbElementosCFG -> First();     i = 0;
  while ( ! TbElementosCFG->Eof && i < nElementosMAX )
  {

/*
    if ( TbElementosCFG->FieldByName( "Activo" )->AsBoolean )
    {
     if ( MessageBox( NULL, AnsiString("El equipo arriba indicado se encuentra \"ocupado\"\n¿ Desea dejar libre este equipo ?").c_str(), AnsiString("Equipo " +  TbElementosCFG->FieldByName( "NumElement" )->AsString + "  ¿Activo?").c_str(), MB_YESNO ) != IDNO )
     {
       TbElementosCFG->Edit();
       TbElementosCFG->FieldByName( "Activo" )->AsBoolean = false;
       TbElementosCFG->Post();
       Memo1->Lines->Insert( 0, (Now()).DateTimeString() + " :: Elemento nº" + TbElementosCFG->FieldByName( "NumElement" )->AsString + ", estaba activo" );
     } else {
       Memo1->Lines->Insert( 0, (Now()).DateTimeString() + " :: Elemento nº" + TbElementosCFG->FieldByName( "NumElement" )->AsString + ", SIGUE activo" );
     }
    }
*/
    NewElementAt( TbElementosCFG->FieldByName( "PosX" )->AsInteger,
                  TbElementosCFG->FieldByName( "PosY" )->AsInteger,
                  TbElementosCFG->FieldByName( "NumElement" )->AsInteger,
                  TbElementosCFG->FieldByName( "IP" )->AsString,
                  TbElementosCFG->FieldByName( "Name" )->AsString
                );
    TbElementosCFG -> Next();    i++;
  }
}
//---------------------------------------------------------------------------
void __fastcall TCtrlPPal::Estado1Click(TObject *Sender)
{
 if ( !ServerHook )
  ElementoDblClick(mElementoCFG->PopupComponent);
}
//---------------------------------------------------------------------------
void __fastcall TCtrlPPal::ElementoDblClick(TObject *Sender)
{
  // Abrimos el cuadro de dialogo de Status...
  if ( ((TElemento *)Sender)->StatusCode != -1 )
  {
   TStatus *Status;
   Status = new TStatus(this);
   Status->SetElement( (TElemento *)Sender );
   Status -> ShowModal();
   delete Status;
  }
}
//---------------------------------------------------------------------------
void __fastcall TCtrlPPal::FormClose(TObject *Sender, TCloseAction &Action)
{
#ifdef DEMOSTRACION
 ShowMessage( MsgDEMO );
#endif
  clientHook->Close(); 
  Memo1->Lines->Insert( 0, (Now()).DateTimeString() + " :: Fin de la sesión" );
  Memo1->Lines->SaveToFile( opLOG );
}
//---------------------------------------------------------------------------
void __fastcall TCtrlPPal::FormDeactivate(TObject *Sender)
{
  FreeThreads();
}
//---------------------------------------------------------------------------
void __fastcall TCtrlPPal::Propiedades1Click(TObject *Sender)
{
 if ( ServerHook ) return;

 if ( ChangePositionEnabled )
 {
  TElementosCFG *ElementosCFG;
  ElementosCFG = new TElementosCFG(this);
  ElementosCFG -> ShowModal();
  delete ElementosCFG;
  Memo1->Lines->Insert( 0, (Now()).DateTimeString() + " :: Se han modificado las direcciones IP" );

  LoadProtectedList();
 }
}
//---------------------------------------------------------------------------
void __fastcall TCtrlPPal::CerrarWindows1Click(TObject *Sender)
{
 TElemento *Elemento = (TElemento *)(mElementoCFG->PopupComponent);

 if ( MessageBox( NULL, "¿ Realmente quiere cerrar el equipo ?", AnsiString("Equipo n: -- " + AnsiString( Elemento->NumElemento ) + " --" +"  Nombre: \""+Elemento->GiveMyName()+"\"" ).c_str(), MB_OKCANCEL ) == IDOK )
 {
   if ( ServerHook )
   {
     ServerHookCode = 5660;  ServerHookElement = Elemento->NumElemento;
     serverHook->Active = true;
   } else
    Elemento->CerrarWindows();
 }
}
//---------------------------------------------------------------------------
TThread  * TCtrlPPal::GetThread(void)
{
  TList *pList = pCache->LockList();
  TThread *NewThread;
  if (pList->Count) // cache is not empty
  {
    NewThread = (TThread *)pList->Items[0];
    pList->Delete(0); // remove from cache
  }
  else
    NewThread = (TThread *)new ThreadSocket(true); // create but don’t run
  pCache->UnlockList();
  return NewThread;
};
//---------------------------------------------------------------------------
void __fastcall TCtrlPPal::FreeThreads(void)
{
  TList *pList = pCache->LockList();
  for (int i = pList->Count - 1; i >= 0; i--)
  {

    delete pList->Items[i];
    pList->Delete(i);
  }
  pCache->UnlockList();
};
//---------------------------------------------------------------------------
//###########################################################################
//###########################################################################
void __fastcall TCtrlPPal::FormCloseQuery(TObject *Sender, bool &CanClose)
{
 // Esperamos a que se cierren los Sockets...
 if ( AnySocketActive > 0 )
 {
  if ( Application->MessageBox("La aplicación sigue intentando comunicarse\ncon algún terminal.\nPor favor, espere...\n(Cancelar el proceso dejará la aplicación\nen un estado Altamente INESTABLE)", AnsiString("¡¡¡ " + AnsiString( AnySocketActive ) + "  Alerta(s) !!!").c_str(), MB_OKCANCEL + MB_DEFBUTTON1) != ID_CANCEL )
  {
     CanClose = false;
  }
 }
}
//---------------------------------------------------------------------------
void __fastcall TCtrlPPal::ActualizarEstado1Click(TObject *Sender)
{
 if ( ServerHook )
 {
   ServerHookCode = 5661;   ServerHookElement = ( (TElemento *)(mElementoCFG->PopupComponent) )->NumElemento;
   serverHook -> Active = true;
 } else {
     ( (TElemento *)(mElementoCFG->PopupComponent) ) -> RefreshElement();
 }
}
//---------------------------------------------------------------------------

void __fastcall TCtrlPPal::SinTIEMPO1Click(TObject *Sender)
{
 TElemento *Elemento = (TElemento *)(mElementoCFG->PopupComponent);

 if ( MessageBox( NULL, "¿ Realmente quiere QUITAR EL TIEMPO al equipo ?", AnsiString("Equipo n: -- " + AnsiString( Elemento->NumElemento ) + " --"+"  Nombre: \""+Elemento->GiveMyName()+"\"").c_str() , MB_OKCANCEL ) == IDOK )
 {
     // Actualizamos el historial
     TbHistorial -> InsertRecord( ARRAYOFCONST(( Elemento->NumElemento,
                                      (Variant)TDateTime::CurrentDateTime(),
                                      (Variant)Elemento->TiempoRestante(), 0, 998, 0 )) );
     TbHistorial -> FlushBuffers();
     if ( ServerHook )
     {
       ServerHookCode = 5668; ServerHookElement = Elemento->NumElemento;
       serverHook -> Active = true;
     } else
       Elemento -> ForcedTimeOut();

 }
}
//---------------------------------------------------------------------------

void __fastcall TCtrlPPal::TbHistorialBeforeOpen(TDataSet *DataSet)
{
   // Si la tabla no existe, la creamos
 if ( access( (TbHistorial -> TableName).c_str(), 0 ) != 0 )
 {
	 // Usamos la propiedad FielDefs para definir
	 // las columnas que contendrá la tabla
     TbHistorial -> FieldDefs -> Clear();

	 TbHistorial -> FieldDefs -> Add("NumElement",  ftInteger,  0, false );
	 TbHistorial -> FieldDefs -> Add("FComienzo",   ftDateTime, 0, false );
	 TbHistorial -> FieldDefs -> Add("Tiempo",      ftTime,     0, false );
	 TbHistorial -> FieldDefs -> Add("idc",         ftInteger,  0, false );
	 TbHistorial -> FieldDefs -> Add("idtc",        ftInteger,  0, false );
	 TbHistorial -> FieldDefs -> Add("precio",      ftCurrency,  0, false );

     TbHistorial -> IndexDefs -> Clear();
	 TbHistorial -> IndexDefs -> Add("Primary", "NumElement;FComienzo", TIndexOptions() << ixPrimary << ixUnique );

	 // Creamos la base...
	 TbHistorial -> CreateTable();
 }

}
//---------------------------------------------------------------------------

void __fastcall TCtrlPPal::AsignarHora1Click(TObject *Sender)
{
/*
 iAnclada = GetNumElement( Sender );
 if ( iAnclada != -1 )
 {
  Elementos[ iAnclada ]-> EnviarListasAppl();
 }
*/
}
//---------------------------------------------------------------------------


void __fastcall TCtrlPPal::RemoteStartClick(TObject *Sender)
{
  // Remote Start...
  if ( AnySocketActive > 0 )
  {
    ShowMessage( "Imposible enganche remoto,\nhasta que todos los terminales\nacaben su comunicación" );
    return;
  }
  if ( ClientHook )
  {
    ShowMessage( "Alguien nos tiene enganchados.\nImposible realizar enganche remoto.\n(Pruebe en otro orden)" );
    return;
  }

  RemoteStart -> Visible = false;
  ServerHook = true;

  remoteBack->Visible = true;
  remoteLog->Visible = true;
  remoteClose->Visible = true;


  remoteLog->Caption= "Inicializando sistema remoto...";

  serverHook->Address = InputBox("Conexión Control Remoto", "IP Destino:", "0.0.0.0");


  remoteLog->Caption= "Eliminando terminales actuales" ;
      Elementos->Pack();
      for( int i=0; i < Elementos->Count; i++ )
      {
       Pizarra->RemoveControl( (TElemento *)Elementos->Items[i] );
       delete (TElemento *)Elementos->Items[i];
      }
      Elementos->Clear();

  remoteLog->Caption= "Accediendo a los terminales remotos" ;
  ServerHookCode = 5650;  ServerHookElement = 5650;
  serverHook->Active = true;

}
//---------------------------------------------------------------------------

void __fastcall TCtrlPPal::remoteCloseDblClick(TObject *Sender)
{
  if ( ClientHook )
  {
    ShowMessage( "Alguien nos tiene enganchados.\nImposible des-enganche remoto.\nRiesgo de incomunicación parcial" );
    return;
  }

  remoteLog->Caption= "Eliminando terminales actuales" ;
      Elementos->Pack();
      for( int i=0; i < Elementos->Count; i++ )
      {
       Pizarra->RemoveControl( (TElemento *)Elementos->Items[i] );
       delete (TElemento *)Elementos->Items[i];
      }
      Elementos->Clear();

  ServerHook = false;

  remoteLog->Caption= "Cargando Terminales Locales" ;
  TbElementosCFGAfterOpen(0);

  RemoteStart -> Visible = true;

  remoteBack->Visible = false;
  remoteLog->Visible = false;
  remoteClose->Visible = false;
}
//---------------------------------------------------------------------------

void __fastcall TCtrlPPal::clientHookClientConnect(TObject *Sender,
      TCustomWinSocket *Socket)
{
  Memo1->Lines->Insert( 0, (Now()).DateTimeString() + " :: Nos han enganchado :: " + Socket->LocalAddress );
  ClientHook = true;
}
//---------------------------------------------------------------------------

void __fastcall TCtrlPPal::clientHookClientDisconnect(TObject *Sender,
      TCustomWinSocket *Socket)
{
  Memo1->Lines->Insert( 0, (Now()).DateTimeString() + " :: Desenganche " );
  ClientHook = false;
}
//---------------------------------------------------------------------------

void __fastcall TCtrlPPal::clientHookClientError(TObject *Sender,
      TCustomWinSocket *Socket, TErrorEvent ErrorEvent, int &ErrorCode)
{
   Memo1->Lines->Insert( 0, (Now()).DateTimeString() + " :: Cliente ¡ ERROR ! " + AnsiString( ErrorCode ) + "::" + Socket->LocalAddress  );
}
//---------------------------------------------------------------------------
void __fastcall TCtrlPPal::SetActiveTimeElement( TElemento *Elemento, TDateTime Tiempo, int L_idc, int L_idtc, Currency L_Precio )
{
 if ( ServerHook )
 {
   ServerHookCode = 5669; ServerHookElement = Elemento->NumElemento;
   ServerTiempo = Tiempo;  ServerL_idc = L_idc; ServerL_idtc = L_idtc; ServerL_Precio = (double)L_Precio;
   serverHook -> Active = true;
 } else
   Elemento->SetActiveTime( Tiempo, L_idc, L_idtc, L_Precio );
}
//---------------------------------------------------------------------------
TElemento * __fastcall TCtrlPPal::SearchElement( int NumEl )
{
    for (int i = Elementos->Count - 1; i >= 0; i--)
    {
      if ( ((TElemento *)(Elementos->Items[i]))->NumElemento == NumEl )
       return (TElemento *)(Elementos->Items[i]);
    }

 return NULL;
}
//---------------------------------------------------------------------------
void __fastcall TCtrlPPal::clientHookAccept(TObject *Sender,
      TCustomWinSocket *Socket)
{
 int CodOp, dev;
 double Tiempo;
 TElemento *Elemento;
 TWinSocketStream *pStream;

 Memo1->Lines->Insert( 0, "Conexión aceptada de " + Socket->RemoteAddress );

 try {
 pStream = new TWinSocketStream( Socket, 60000 );
 try{
// Socket->ReceiveBuf( &CodOp, sizeof(int) );
      pStream->WaitForData(30000);      pStream->Read( &CodOp, sizeof(int) );

 if ( CodOp != 5650 )
 {
  dev = ( Elemento = SearchElement( CodOp ) ) == NULL ?  1 : 0;
//  Socket->SendBuf( &dev, sizeof(int) );
  pStream->Write( &dev, sizeof(int) );
  if ( dev ) return;
 }

 ClientHook = true;

// Socket->ReceiveBuf( &CodOp, sizeof(int) );
      pStream->WaitForData(30000);      pStream->Read( &CodOp, sizeof(int) );

 switch( CodOp )
 {
  // On
  case 5669:
    int L_idc, L_idtc;
    float L_Precio;
/*
    Socket->ReceiveBuf( &Tiempo, sizeof(double) );
    Socket->ReceiveBuf( &L_idc, sizeof(int) );
    Socket->ReceiveBuf( &L_idtc, sizeof(int) );
    Socket->ReceiveBuf( &L_Precio, sizeof(float) );
*/
      pStream->WaitForData(30000);      pStream->Read( &Tiempo, sizeof(double) );
      pStream->WaitForData(30000);      pStream->Read( &L_idc, sizeof(int) );
      pStream->WaitForData(30000);      pStream->Read( &L_idtc, sizeof(int) );
      pStream->WaitForData(30000);      pStream->Read( &L_Precio, sizeof(float) );

    SetActiveTimeElement( Elemento, Tiempo, L_idc, L_idtc, (Currency)L_Precio );
    break;
  // Off
  case 5668:
    Elemento -> ForcedTimeOut();
    break;
  // CERRAR WINDOWS
  case 5660:
    Elemento->CerrarWindows();
    break;
  // Query TIME (Refresh)
  case 5661:
    Elemento -> RefreshElement();
    Tiempo = Elemento->iTiempoPedido();
//    Socket->SendBuf( &Tiempo, sizeof(double) );
      pStream->WaitForData(30000);      pStream->Read( &Tiempo, sizeof(double) );
    Tiempo = Elemento->RTiempoRestante;
//    Socket->SendBuf( &Tiempo, sizeof(double) );
      pStream->WaitForData(30000);      pStream->Read( &Tiempo, sizeof(double) );
    break;
  // Lista de elementos...
  case 5650:
    dev = Elementos->Count;
//    Socket->SendBuf( &dev, sizeof(int) );
    pStream->Write( &dev, sizeof(int) );

    for (int i = Elementos->Count - 1; i >= 0; i--)
    {
      Elemento = (TElemento *)(Elementos->Items[i]);
    //void __fastcall TCtrlPPal::NewElementAt(int X, int Y, int NumEl, AnsiString IP, AnsiString Name )
/*
      Socket->SendBuf( &(Elemento->Left), sizeof(int) );
      Socket->SendBuf( &(Elemento->Top), sizeof(int) );
      Socket->SendBuf( &(Elemento->NumElemento), sizeof(int) );
      Socket->SendBuf( Elemento->GiveMyIP().c_str(), 70 );
      Socket->SendBuf( Elemento->GiveMyName().c_str(), 70 );

      Tiempo = Elemento->iTiempoPedido();    Socket->SendBuf( &Tiempo, sizeof(double) );
      Tiempo = Elemento->RTiempoRestante;    Socket->SendBuf( &Tiempo, sizeof(double) );

*/
      pStream->Write( &(Elemento->Left), sizeof(int) );
      pStream->Write( &(Elemento->Top), sizeof(int) );
      pStream->Write( &(Elemento->NumElemento), sizeof(int) );
      pStream->Write( Elemento->GiveMyIP().c_str(), 70 );
      pStream->Write( Elemento->GiveMyName().c_str(), 70 );

      Tiempo = Elemento->iTiempoPedido();    pStream->Write( &Tiempo, sizeof(double) );
      Tiempo = Elemento->RTiempoRestante;    pStream->Write( &Tiempo, sizeof(double) );

      Elemento -> RefreshElement();
    }
    break;
  default:
    Memo1->Lines->Insert( 0, "Mensaje desconocido ::" + Socket->RemoteAddress );
 }
  }
  catch (Exception &E)
      {
        if (!E.ClassNameIs("EAbort"))
        {
             Memo1->Lines->Insert( 0, "ERROR en la comunicación ::" + Socket->RemoteAddress );
        }
      }
  }
  __finally
  {
    delete pStream;
    Socket->Close();
  }
 Memo1->Lines->Insert( 0, "Tramites Finalizados ::" + Socket->RemoteAddress );

}
//---------------------------------------------------------------------------
void __fastcall TCtrlPPal::serverHookConnect(TObject *Sender,
      TCustomWinSocket *Socket)
{
  double TiempoPedido, TiempoRestante;
  TWinSocketStream *pStream;
  int Data;
  // create a TWinSocketStream for reading and writing
  try {
  pStream = new TWinSocketStream( Socket, 60000 );

  try
  {
    pStream->Write( &ServerHookElement, sizeof(int) );

    if ( ServerHookCode != 5650 )
    {
      pStream->WaitForData(30000);
      pStream->Read( &Data, sizeof(int) );
      if ( Data == 1 )
      {
          Socket->Close();
          return;
      }
    }

    pStream->Write( &ServerHookCode, sizeof(int) );

    // Comunicamos según código en ServerHookCode
    switch ( ServerHookCode )
    {
      // On
      case 5669:
        pStream->Write( &ServerTiempo, sizeof(double) );
        pStream->Write( &ServerL_idc, sizeof(int) );
        pStream->Write( &ServerL_idtc, sizeof(int) );
        pStream->Write( &ServerL_Precio, sizeof(float) );
        break;
      // Off
      case 5668:
        // Nada mas
        break;
      // CERRAR WINDOWS
      case 5660:
        // Nada mas
        break;
      // Lista de elementos...
      case 5650:
        pStream->WaitForData(30000);  // Inicio
        pStream->Read( &Data, sizeof(int) );
        int X,Y, NumEl; char IP[80], Name[80];
        for (int i = Data - 1; i >= 0; i--)
        {
          pStream->WaitForData(30000);      pStream->Read( &X, sizeof(int) );
          pStream->WaitForData(30000);      pStream->Read( &Y, sizeof(int) );
          pStream->WaitForData(30000);      pStream->Read( &NumEl, sizeof(int) );
          pStream->WaitForData(30000);      pStream->Read( &IP, 70 );
          pStream->WaitForData(30000);      pStream->Read( &Name, 70 );

          NewElementAt( X, Y, NumEl, IP, Name );

          pStream->WaitForData(30000);      pStream->Read( &TiempoPedido, sizeof(double) );
          pStream->WaitForData(30000);      pStream->Read( &TiempoRestante, sizeof(double) );

          SearchElement( NumEl ) -> ClientTimeIs( TiempoPedido, TiempoRestante );
        }
        break;
      // Query TIME (Refresh)
      case 5661:
        pStream->WaitForData(30000);  // Inicio
        pStream->Read( &TiempoPedido, sizeof(double) );

        pStream->WaitForData(30000);  // Restante
        pStream->Read( &TiempoRestante, sizeof(double) );

        SearchElement( ServerHookElement ) -> ClientTimeIs( TiempoPedido, TiempoRestante );
        break;
  default:
    Memo1->Lines->Insert( 0, "Mensaje desconocido ::" + Socket->RemoteAddress );
    }
  }
  catch (Exception &E)
      {
        if (!E.ClassNameIs("EAbort"))
        {
             Memo1->Lines->Insert( 0, "ERROR en la comunicación ::" + Socket->RemoteAddress );
        }
      }
  }
  __finally
  {
    delete pStream;
    Socket->Close();
  }

}
//---------------------------------------------------------------------------
void __fastcall TCtrlPPal::ActiveImage3Click(TObject *Sender)
{
  clientHook -> Active = !clientHook -> Active;
}
//---------------------------------------------------------------------------


void __fastcall TCtrlPPal::Image1Click(TObject *Sender)
{
  char zFileName[80], zParams[80], zDir[80];
  ShellExecute(Application->MainForm->Handle, 0, StrPCopy(zFileName, "http:\\\\www.infdj.com"),
                         StrPCopy(zParams, ""), StrPCopy(zDir, ""), SW_SHOWNOACTIVATE > 32);
}
//---------------------------------------------------------------------------

void __fastcall TCtrlPPal::TbPersonasNewRecord(TDataSet *DataSet)
{
 TbPersonas->FieldByName( "FAlta" )->AsDateTime = TDateTime::CurrentDateTime();
 TbPersonas->FieldByName( "FModif" )->AsDateTime = TDateTime::CurrentDateTime();
}
//---------------------------------------------------------------------------

