#!/usr/bin/perl

use DBI;
use strict;
use POSIX;
#use ESL;
use Switch;
use Time::HiRes;
use WWW::Curl::Easy;
use JSON;
use Config::Tiny;
use Data::Dumper;
use Cwd;
use URI::Encode qw(uri_encode uri_decode);
use threads;
use Thread::Semaphore;
use threads::shared;
use POSIX qw(strftime);
use Net::Ping;
use Dinstar;
use Email::Send;   
use Email::Simple::Creator; # or other Email::

# ----------------------------------------
# Need to Install Config-Tiny Perl Module
# ----------------------------------------
my $app_folder = getcwd;
chdir "/var/www/html/PortalSMS";
my $filename = "./SmsStatus.ini";
my $config = Config::Tiny->read( $filename, 'utf8' );
my $daemon = 0;
my $dbh;
my $logfile = "./SmsStatus.log";
my $threadCount = 10;
my $site = 1;
my $debug = 7;
my $firstRun = 1;

# --------------------------------
# Variables
# --------------------------------
my $sth;
my $forever = 1;
my $dbConnect = 1;
my $i;
my @thr;
my @Used:shared;
my $globalThreadCount:shared = 0;
my $semaphore = Thread::Semaphore->new();
my $coding = 0;

my $ip = "";
my $port = 0;
my $id = 0;
my $auth = "";
my @jsessionid;
my $countRegister = 4;
my $tac = "";
my $imeiChange = 0;

use constant {
    CONSOLE => 0,
    ALERT => 1,
    CRIT  => 2,
    ERROR  => 3,
    WARNING  => 4,
    NOTICE  => 5,
    INFO => 6,
    DEBUG  => 7
};


if( $config->{core}{daemon} eq "Yes" ) {
   $daemon = 1;
}

# ---------------------------
# Is program already running
# ---------------------------
writeToLog( DEBUG, $logfile, "", 1 );
my $progname = "SmsStatus.pl";
my $pidx = `ps -C $progname -o pid=`;
#my $pidx = `ps -C $progname -o command=`;
if( $pidx != "" ) {
   if( $pidx != getpid() ) {
      writeToLog( INFO, $logfile, sprintf( "SmsStatus PID: %d is ALREADY RUNNING", $pidx ) ,0 );
      exit( 0 );
   }
   else {
      writeToLog( INFO, $logfile, sprintf( "SmsStatus.pl daemon PID: %d IS NOT RUNNING", $pidx ),0 ); 
   }
}
else {
   writeToLog( INFO, $logfile, sprintf( "SmsStatus.pl daemon PID: %d IS NOT RUNNING", $pidx ),0 ); 
}

if( $daemon == 1 ) {
   fork and exit;
   POSIX::setsid();
   fork and exit;
   umask 0;

   writeToLog( INFO, $logfile, sprintf( "Start 'SmsStatus' daemon PID: %d", getpid() ),0 );
   if( open(my $fp, '>', "./SmsStatus.pid") ) {
      printf $fp "%d", getpid();    
      close $fp;
   }

   close STDIN;
   close STDOUT;
   close STDERR;
}
else {
   writeToLog( INFO, $logfile, sprintf( "Start 'SmsStatus' as Foreground" ) ,0 );
}   
writeToLog( INFO, $logfile, "", 1 );


$SIG{INT} = sub { 
   print("\nControl-C pressed, terminating process. Please wait...\n\n");
   $forever = 1;
   exit;
};

$SIG{TERM} = sub {
   $forever = 1;
   exit;
};

END {
  while( $globalThreadCount > 0 ) {
     Time::HiRes::sleep(1);
  }
  if( $dbh ) {
     $dbh->disconnect();
  }   
  writeToLog( DEBUG, $logfile, "", 1 );
  writeToLog( DEBUG, $logfile, sprintf( "Terminated 'SmsStatus' daemon PID: %d", getpid() ) ,0 );
  writeToLog( DEBUG, $logfile, "", 1 );
  unlink("./SmsStatus.pid");
}

# --------------------------------
# MariaDB
# --------------------------------
my $driver = "mysql"; 
my $database = "TestSMS-2";
my $dsn = "DBI:$driver:database=smpp:127.0.0.1";
my $userid = "root";
my $password = "dialer19";
my $dbhost = "10.0.66.119";
my $datatable = "outbound_request";
my $error = "";


# --------------------------------
# MariaDB Configuration
# --------------------------------
if( $config->{database}{name} ne "" ) {
   $database = $config->{database}{name};
}
if( $config->{database}{host} ne "" ) {
   $dbhost = $config->{database}{host};
}
if( $config->{database}{host} ne "" ) {
   $userid = $config->{database}{user};
}
if( $config->{database}{password} ne "" ) {
   $password = $config->{database}{password};
}
if( $config->{database}{datatable} ne "" ) {
   $datatable = $config->{database}{datatable};
}

$dsn = "DBI:$driver:database=$database:$dbhost";

if( $config->{core}{debug} ne "" ) {
   $debug = $config->{core}{debug}; 
}

if( $config->{core}{threads} ne "" ) {
   $threadCount = $config->{core}{threads}; 
}

if( $config->{core}{site} ne "" ) {
   $site = $config->{core}{site}; 
}

if( $config->{core}{TAC} ne "" ) {
   $tac = $config->{core}{TAC}; 
}

if( $config->{core}{codigg} ne "" ) {
   $coding = $config->{core}{coding}; 
}

if( $config->{core}{IMEI} ne "" ) {
   $imeiChange = $config->{core}{IMEI}; 
}

writeToLog( DEBUG, $logfile, sprintf( "DataTable: %s", $datatable) );
writeToLog( DEBUG, $logfile, sprintf( "Debug Level: %d", $debug ) );
writeToLog( DEBUG, $logfile, sprintf( "Max Threads: %d", $threadCount ) );


# --------------------------------
# Connect to MariaDB
# --------------------------------
while( $dbConnect ) {

   if( ( $dbh = DBI->connect($dsn, $userid, $password ) ) == 0 ) {
      writeToLog( DEBUG, $logfile, sprintf( "Cannot connect to MariaDB: $DBI::errstr", 0 ) );
      Time::HiRes::sleep(10);
   }
   else {
      $dbConnect = 0;
      writeToLog( DEBUG, $logfile, sprintf( "Connected to MariaDB @%s", $dbhost ) );
      last;
   }
}

for( $i= 0; $i < $threadCount; $i++ ) {
   $Used[$i] = 0;
}
writeToLog( DEBUG, $logfile, "", 1 );

while( $forever ) {

   my $foundThread = 0;

   if ( not $dbh->ping ) {
      if( ( $dbh = DBI->connect($dsn, $userid, $password ) ) == 0 ) {
         writeToLog( DEBUG, $logfile, sprintf( "Cannot connect to MariaDB $DBI::errstr", 0 ) );
         Time::HiRes::sleep(10);
         next;
      }
   }

   my $auth = "";
   my $sql = "";
   my $resultSms;
   my $resultUpdate;
   my $resultDelivery;
   my $result;
   my $sn = "";

   # --------------------------------------------------------
   # Veo que puertos estan registrados cada 15"
   #
   # Si no estaba registrado y ahora si verifico el IMEI y
   # lo cambio o Genero uno nuevo
   # --------------------------------------------------------
   QueryPorts_Registration( $dbh );        

   # -------------------------------------------------------------------
   # Verifico si debo cambiar puertos por cantidad de mensajes enviados
   # -------------------------------------------------------------------
   if( $dbh ) {
#      SlotAvailable($dbh,@jsessionid); 
      SlotAvailable_Active($dbh,@jsessionid); 
   }
   
=begin
   if( ++$countRegister >= 4 ) {
      # ---------------------------------------
      # Verifico si algun GW cambio su estado 
      # ---------------------------------------
      $sql = sprintf( "select sql_no_cache id, descripcion, active, ip, status_change, api_user, api_password from gateways where status_change=1;" );
      my $resultUpdate = $dbh->prepare($sql);
      if ( !$resultUpdate->err ) {
         if( $resultUpdate->execute() ) {

            my $changeCount = 0;
            while (my @rowUpdate = $resultUpdate->fetchrow_array()) {
               ++$changeCount;
               my ($id, $descripcion,$active,$ip,$status_change,$user,$gw_password) = @rowUpdate;

               my $status = sprintf( "%s: (%s) %s", $descripcion, $ip, $active == 1 ? "ACTIVE" : "INACTIVE" );
               writeToLog( WARNING, $logfile, $status, 0 );
               $sql = sprintf( "update gateways set status_change=0 where id=%d;", $id );
               my $resultChange = $dbh->prepare($sql);
               if ( !$resultChange->err ) {
                  $resultChange->execute();
               }
            }
            if( $changeCount > 0 ) {
               writeToLog( WARNING, $logfile, "", 1 );
            }
         }
      }
      $resultUpdate->finish();
      $countRegister = 0;
      $firstRun = 0;
   }
=cut
   
   # -----------------------------------------------------------
   # Busco mensajes que se enviaron para obtener el resultado
   # Status:   201 NO SE OBTUVO STATUS, SIGO INTENTANDO 
   #           202
   #           101 ENVIO NUEVAMENTE?
   #           400 NO SE OBTUVO STATUS, SIGO INTENTANDO
   #           401 CANCELADO, NO SE OBTUVO STATUS
   #             1 PENDIENTE DE ENVIO
   # -----------------------------------------------------------
   my $found = 0;
#   $sql = sprintf( "select sql_no_cache outbound_request.gw as gw, outbound_request.port as port, outbound_request.slot as slot, sent_count, empty_count, pending, customer_id, outbound_request.id as user_id, gateways.ip as gwip, outbound_request.port as send_port, api_user, api_password, date_sub(forwarded,interval 1 second) as cuando, recipient, user, password, sn, status_change, descripcion, active from outbound_request left join gateways on gateways.id=outbound_request.gw where (pending=202 or pending = 201 or pending = 400 or pending=101) order by outbound_request.id;" );
#   $sql = sprintf( "select sql_no_cache outbound_request_test.gw as gw, outbound_request_test.port as port, outbound_request_test.slot as slot, sent_count, empty_count, pending, customer_id, outbound_request_test.id as user_id, gateways.ip as gwip, outbound_request_test.port as send_port, api_user, api_password, date_sub(forwarded,interval 1 second) as cuando, recipient, user, password, sn, status_change, descripcion, active from outbound_request_test left join gateways on gateways.id=outbound_request_test.gw where (pending=202 or pending = 201 or pending = 400 or pending=101) order by outbound_request_test.id;" );
   $sql = sprintf( "select sql_no_cache %s.gw as gw, %s.port as port, %s.slot as slot, sent_count, empty_count, pending, customer_id, %s.id as user_id, gateways.ip as gwip, %s.port as send_port, api_user, api_password, date_sub(forwarded,interval 1 second) as cuando, recipient, user, password, sn, status_change, descripcion, active, canales from %s left join gateways on gateways.id=%s.gw where (pending=202 or pending = 201 or pending = 400 or pending=101) order by %s.id;",
                   $datatable,$datatable,$datatable,$datatable,$datatable,$datatable,$datatable,$datatable );

#   printf( "%s\n", $sql);
   $resultSms = $dbh->prepare($sql);
   if ( $resultSms->err ) {
      db_Error( DEBUG, $resultSms->err, $resultSms->errstr );
      Time::HiRes::sleep(1);
      next;
   }

   if( $resultSms->execute() ) {

      while (my @rowSms = $resultSms->fetchrow_array()) {
         my ($gw, $port, $slot, $send_count, $empty_count, $pending, $customer_id, $id, $ip, $port1, $api_user, $api_password, $fecha, $recipient,$user,$gw_password,$serial,$status_change,$descripcion,$active, $channels ) = @rowSms;
         $auth = $api_user . ":" . $api_password;

         if( $gw eq "" || $port eq "" || $slot eq "" || $ip eq "" ) {
            next;
         }

         if( !defined($jsessionid[$id]) ) {
            my $session = loginGateway( $ip, $user, $gw_password ); 
            $jsessionid[$id] = $session;
         }
         $sn = $serial;

         $semaphore->down();
         $foundThread = 0;
         for( $i = 0; $i < $threadCount; $i++ ) {
            if( $Used[$i] == 0 ) {
               $Used[$i] = 1;
               $foundThread = 1;
               last;
            }
         }

         # -----------------------------
         # Actualizo Thread en Uso
         # -----------------------------
         UsedThreads();
         $semaphore->up();

         if( $foundThread == 1 ) {
            $thr[$i] = threads->create(\&queryResultThread, $ip, $port, $auth, $id, $fecha, $recipient, $database, $dbhost, $userid, $password, $i, $empty_count, $send_count, $slot, $gw, $sn, $jsessionid[$gw], $datatable );
 #           $thr[$i] = threads->create(\&queryMultipleResultThread, $ip, $port, $auth, $id, $fecha, $recipient, $database, $dbhost, $userid, $password, $i, $empty_count, $send_count, $slot, $gw, $sn, $jsessionid[$gw], $datatable, $channels );
         }

         while( $globalThreadCount >= $threadCount ) {
            UsedThreads();
            Time::HiRes::sleep(1);
         }
      }
   }
   $resultSms->finish();
   $firstRun = 0;
   sleep( 15 );
}
$dbh->disconnect();


writeToLog( DEBUG, $logfile, sprintf( "End 'SmsStatus' daemon PID: %d", getpid() ),0 );
print ( "-------------------------------------------------------------------------------------------------------------------------------------------------------------------\n" );


   # ------------------------------------
   # THREAD
   # ------------------------------------

   sub queryResultThread
   {
      my $LocalCopy;
      my $dbh;
      my $resultUpdate;
      my $resultDelivery;
      my $sql;
      my $ip = $_[0];
      my $port = $_[1];
      my $auth = $_[2];
      my $id = $_[3];
      my $fecha = $_[4]; 
      my $recipient = $_[5];
      my $database = $_[6];
      my $dbhost = $_[7];
      my $userid = $_[8];
      my $password = $_[9];
      my $index = $_[10];
      my $empty_count = $_[11];
      my $send_count = $_[12];
      my $slot = $_[13];
      my $gw = $_[14];
      my $sn = $_[15];
      my $jsessionid = $_[16];
      my $datatable = $_[17];

      threads->detach();
      my $dsn = "DBI:$driver:database=$database:$dbhost";
      if( ( $dbh = DBI->connect($dsn, $userid, $password ) ) == 0 ) {
         $Used[$index] = 0;
         $semaphore->up();
         return;
      }

      $LocalCopy = $globalThreadCount; 
      $Used[$index] = 1;
      $LocalCopy++;
      $globalThreadCount = $LocalCopy; 
      $semaphore->up();

      # -------------------------------------------
      # Query resultado de envio de Sms del puerto
      # -------------------------------------------
#     try { 
#     eval { 

#        my $rd = '{"error_code":200,"sn":"xxxx-xxxx-xxxx-xxxx","result":[{"port":"$port","user_id":"$id","number":"$recipient","time":"2025-02-26 12:06:01","status":"SENT_OK","count":1, "succ_count":1,"ref_id":"$id","imsi":"460004642148063"}]}';

#        my @ports = (0..$channels-1);
#        my $rd = querySmsResults( $ip, \@ports, $auth, $id, $fecha, $recipient );

         my $rd = querySmsResult( $ip, $port, $auth, $id, $fecha, $recipient );
         my $rc = decode_json($rd);
#        print( Dumper( $rc ) );

         if( int($rc->{error_code}) == 200 ) {
            my @resultArray = $rc->{result};
            my $len = scalar @resultArray;
   
            if( $len < 1 ) {
   
               # ---------------------------------------------
               # Sin STATUS 5 veces, cancelo con codigo 401,
               # Si no llegue al maximo de 5, codigo 400
               # y sigo esperando respuesta
               # ---------------------------------------------
               my $status = sprintf( "%s: %s, %s, Status: NO_STATUS (%d)", $recipient, $ip, $fecha, $id );
               writeToLog( DEBUG, $logfile, $status, 0 );
               if( $empty_count >= 5 ) {
                  $sql = sprintf( "update %s set pending=401, error_description='NO_STATUS', empty_count=empty_count+1 where id=%d;", $datatable, $id );
               }
               else {
                  $sql = sprintf( "update %s set pending=400, error_description='NO_STATUS', empty_count=empty_count+1 where id=%d;", $datatable, $id );
               }
               $resultUpdate = $dbh->prepare($sql);
               if ( !$resultUpdate->err ) {
                  $resultUpdate->execute();
               }
               $resultUpdate->finish();
            }
            else {
               my $errCode;
               my $user_id;
   
               $errCode = $rc->{result}[0]->{status}; 
               $user_id = $rc->{result}[0]->{user_id}; 
               if( $errCode eq "" || $user_id eq "" ) {
   
                  # ------------------------------------------------
                  # Todavia no obtuve el status probar en 1 minuto
                  # ------------------------------------------------
                  my $status = sprintf( "%s: %s, %s, Status: NO_STATUS (%d)", $recipient, $ip, $fecha, $id );
                  writeToLog( DEBUG, $logfile, $status, 0 );
   
                  # --------------------------------------------------------
                  # Si el  puerto / slot no va por ahora hay que cambiarlo
                  # --------------------------------------------------------
                  if( $empty_count >= 5 ) {
                     $sql = sprintf( "update %s set pending=401, error_description='NO_STATUS', empty_count=empty_count+1 where id=%d;", $datatable, $id );
                  }
                  else {
                     $sql = sprintf( "update %s set pending=201, error_description='NO_STATUS', empty_count=empty_count+1 where id=%d;", $datatable, $id ); 
                  }
   
                  $resultUpdate = $dbh->prepare($sql);
                  if ( $resultUpdate->err ) {
                     db_Error( DEBUG, $resultUpdate->err, $resultUpdate->errstr );
                     $resultUpdate->finish();
                     Time::HiRes::sleep(10);
                  }
                  else {
                     $resultUpdate->execute();
                     $resultUpdate->finish();
                  }
               }
               else {
   
                  # ---------------------------
                  # Hay STATUS de respuesta
                  # ---------------------------
                  my $status = sprintf( "%s: ID: %s, %s, %s, Status: %s", $recipient, $id, $ip, $fecha, $errCode );
                  writeToLog( DEBUG, $logfile, $status, 0 );
                  writeToLog( DEBUG, $logfile, "", 1 );
   
                  # -------------------------------------------
                  # Codigo Actualizado, verificar por SENT_OK
                  # -------------------------------------------
                  switch( $errCode ) {
   #                 case /^(?:SENT_OK|SENDING|FAILED)$/ {
                     case /SENT_OK|SENDING|FAILED/ {
   
                        if( $send_count > 3 ) {
   
                           # -----------------------------
                           # Busco que plan tiene el Slot
                           # -----------------------------
                           my $strSlot = convertSlot( $slot );
                           $sql = sprintf( "select sql_no_cache gateway_ports.plan as plan from gateway_ports left join planes on planes.id=gateway_ports.plan where gw=%d and port=%d and slot='%s';", $gw, $port, $strSlot );
                           $resultUpdate = $dbh->prepare($sql);
                           if ( $resultUpdate->err ) {
                              $resultUpdate->finish();
                           }
                           else {
                              $resultUpdate->execute();
                              if( $resultUpdate->rows() > 0 ) {
                                 $resultUpdate->finish();
   
                                 # ---------------------------------------------------------------------------
                                 # Test SIM port for Change por cantidad de errores a un numero ($recipient)
                                 # ---------------------------------------------------------------------------
                                 $sql = sprintf( "select sql_no_cache errorCount from delivery where gw=%d and port=%d and slot='%s' and recipient='%s';", $gw, $port, $strSlot, $recipient );
                                 $resultDelivery = $dbh->prepare($sql);
                                 if ( !$resultDelivery->err ) {
      
                                    $resultDelivery->execute();
                                    if( $resultDelivery->rows() == 0 ) {
   
                                       # ----------------------------------
                                       # Primer error, agrego registro
                                       # ----------------------------------
                                       $sql = sprintf( "insert into `delivery` (`id`,`fecha`,`gw`,`port`,`slot`,`errorCount`,`recipient`) VALUES (0,now(),%d,%d,'%s',1,'%s');", int($gw), int( $port ), $strSlot, $recipient );
                                       $resultDelivery = $dbh->prepare($sql);
                                       if ( $resultDelivery->err ) {
                                          $resultDelivery->finish();
                                          next;
                                       }
                                       $resultDelivery->execute();
                                    }
                                 }
                                 $resultDelivery->finish();
      
                                 # ----------------------------------------------------------------
                                 # Verifico si esta muerto para varios destinos lo cambio de slot
                                 # ----------------------------------------------------------------
                                 $sql = sprintf( "select sql_no_cache count(id) as total from delivery where gw=%d and port=%d and slot='%s';", $gw, $port, $strSlot );
                                 $resultDelivery = $dbh->prepare($sql);
                                 if ( $resultDelivery->err ) {
                                    $resultDelivery->finish();
                                 }
                                 else {
                                    $resultDelivery->execute();
                                    if( $resultDelivery->rows() > 0 ) {
                                    
                                       if(my @row = $resultDelivery->fetchrow_array()) {
                                    
                                          my ($delivery_count) = @row;
                                          $resultDelivery->finish();
                                    
                                          # -------------------------------------------
                                          # Hay mas de 5 numeros diferentes con error
                                          # Pongo en 0 los errores de ese nuevo puerto
                                          # Hay que matar este puerto slot
                                          # -------------------------------------------
                                          if( $delivery_count > 5 ) {
      
                                             writeToLog( DEBUG, $logfile, sprintf( "Slot Change GW because too many errors: %d, %d:%s", $gw, $port, $strSlot), 0 );
                                             writeToLog( DEBUG, $logfile, "", 1 );
   
                                             # -----------------------
                                             # Anulo este puerto/slot
                                             # -----------------------
                                             $sql = sprintf( "update gateway_ports set enabled=0, status=0, intento_registro='0000-00-00 00:00:00' where gw=%d and port=%d and slot='%s';", $gw, $port, $strSlot );
                                             $resultDelivery = $dbh->prepare($sql);
                                             if ( !$resultDelivery->err ) {
                                                $resultDelivery->execute();
                                             }
                                             $resultDelivery->finish();
   
   
                                             # --------------------------------
                                             # Traigo informacion del gateway
                                             # --------------------------------
                                             my $sql = sprintf( "select sql_no_cache ip, api_user, api_password, sn, user, password from gateways where id=%d;", $gw );
                                             my $resultGW = $dbh->prepare($sql);
                                             if ( !$resultGW->err ) {
                                                if( $resultGW->execute() ) {
                                                   if ( $resultGW->rows() > 0 ) {
                                                      if (my @rowGW = $resultGW->fetchrow_array()) {
                                             
                                                         my ($ip, $api_user, $api_password, $sn, $user, $gw_password ) = @rowGW;
                                                         my $auth = $api_user . ":" . $api_password;
                                                         my $rc = SlotAvailable_Disable($dbh,@jsessionid,$gw,$port,$strSlot,$ip,$user,$gw_password,$sn,$auth);
                                                      }
                                                   }
                                                }
                                             }
                                             $resultGW->finish();
   
      #                                      SlotChange($gw, $port, $slot, $ip, $auth, $dbh, $jsessionid[$gw], $sn, $errCode );
      #                                      SlotChange($gw, $port, $slot, $ip, $auth, $dbh, $jsessionid, $sn, $errCode );
   
                                             $sql = sprintf( "delete from delivery where gw=%d and port=%d and slot='%s';", $gw, $port, $strSlot );
                                             $resultDelivery = $dbh->prepare($sql);
                                             if ( $resultDelivery->err ) {
                                                $resultDelivery->finish();
                                             }
                                             else {
                                                $resultDelivery->execute();
                                                $resultDelivery->finish();
                                             }
                                          }
                                       }
                                    }
                                 }
                                 # ------------------------------------------------
                                 # Actualizo contador de veces enviado este mensaje
                                 # ------------------------------------------------
                                 $sql = sprintf( "update %s set pending=102, error_description='%s', sent_count=sent_count+1 where id=%d;", $datatable, $errCode, $id );
                                 $resultUpdate = $dbh->prepare($sql);
                                 if ( !$resultUpdate->err ) {
                                    $resultUpdate->execute();
                                 }
                                 $resultUpdate->finish();
                              } # rows
                           }
                        }
                        else {
                           # ------------------------------
                           # Marco para enviar nuevamente?
                           # ------------------------------
                           $sql = sprintf( "update %s set pending=101, error_description='%s', sent_count=sent_count+1 where id=%d;", $datatable, $errCode, $id );  
                           $resultUpdate = $dbh->prepare($sql);
                           if ( !$resultUpdate->err ) {
                              $resultUpdate->execute();
                           }
                           $resultUpdate->finish();
                        }
                     }
                     else {
   
                        # -------------------------------------
                        # Marco como terminado con su Status
                        # -------------------------------------
                        my $strSlot = convertSlot( $slot );
                        $sql = sprintf( "update %s set pending=100, error_description='%s' where id=%d;", $datatable, $errCode, $id );
                        $resultUpdate = $dbh->prepare($sql);
                        if ( !$resultUpdate->err ) {
                           $resultUpdate->execute();
                        }
                        $resultUpdate->finish();
   
                        $sql = sprintf( "delete from delivery where gw=%d and port=%d and slot='%s';", $gw, $port, $strSlot );
                        $resultDelivery = $dbh->prepare($sql);
                        if ( !$resultDelivery->err ) {
                           $resultDelivery->execute();
                        }
                        $resultDelivery->finish();
                     }
                  }
               }
            } 
         } #rc 
#        1;
#      } finally {
#         printf( "Eval Error\n" );
#      };

#      } or do {
#         printf( "Eval Error\n" );
#      };

      $semaphore->down();
      $LocalCopy = $globalThreadCount; 
      $LocalCopy--;
      $globalThreadCount = $LocalCopy; 
      $Used[$index] = 0;
      if( defined($resultDelivery) ) {
         $resultDelivery->finish();
      }                  
      if( defined($resultUpdate) ) {
         $resultUpdate->finish();
      }         
      $dbh->disconnect();
      $semaphore->up();
      threads->exit();
   }   


   # ------------------------------------
   # THREAD
   # ------------------------------------

   sub queryMultipleResultThread
   {
      my $LocalCopy;
      my $dbh;
      my $resultUpdate;
      my $resultDelivery;
      my $sql;
      my $ip = $_[0];
      my $port = $_[1];
      my $auth = $_[2];
      my $id = $_[3];
      my $fecha = $_[4]; 
      my $recipient = $_[5];
      my $database = $_[6];
      my $dbhost = $_[7];
      my $userid = $_[8];
      my $password = $_[9];
      my $index = $_[10];
      my $empty_count = $_[11];
      my $send_count = $_[12];
      my $slot = $_[13];
      my $gw = $_[14];
      my $sn = $_[15];
      my $jsessionid = $_[16];
      my $datatable = $_[17];
      my $channels = $_[18];

      threads->detach();
      my $dsn = "DBI:$driver:database=$database:$dbhost";
      if( ( $dbh = DBI->connect($dsn, $userid, $password ) ) == 0 ) {
         $Used[$index] = 0;
         $semaphore->up();
         return;
      }

      $LocalCopy = $globalThreadCount; 
      $Used[$index] = 1;
      $LocalCopy++;
      $globalThreadCount = $LocalCopy; 
      $semaphore->up();

      # -------------------------------------------
      # Query resultado de envio de Sms del puerto
      # -------------------------------------------
#     my $rd = '{"error_code":200,"sn":"xxxx-xxxx-xxxx-xxxx","result":[{"port":"$port","user_id":"$id","number":"$recipient","time":"2025-02-26 12:06:01","status":"SENT_OK","count":1, "succ_count":1,"ref_id":"$id","imsi":"460004642148063"}]}';

      my @ports = (0..$channels-1);
      my $rd = querySmsResults( $ip, \@ports, $auth, $id, $fecha, $recipient );
      my $rc = decode_json($rd);
#     print( Dumper( $rc ) );


      if( int($rc->{error_code}) == 200 ) {
         my @resultArray = $rc->{result};
         my $len = scalar @resultArray;

         if( $len < 1 ) {
   
=begin
            # ---------------------------------------------
            # Sin STATUS 5 veces, cancelo con codigo 401,
            # Si no llegue al maximo de 5, codigo 400
            # y sigo esperando respuesta
            # ---------------------------------------------
            my $status = sprintf( "%s: %s, %s, Status: NO_STATUS (%d)", $recipient, $ip, $fecha, $id );
            writeToLog( DEBUG, $logfile, $status, 0 );
            if( $empty_count >= 5 ) {
               $sql = sprintf( "update %s set pending=401, error_description='NO_STATUS', empty_count=empty_count+1 where id=%d;", $datatable, $id );
            }
            else {
               $sql = sprintf( "update %s set pending=400, error_description='NO_STATUS', empty_count=empty_count+1 where id=%d;", $datatable, $id );
            }
            $resultUpdate = $dbh->prepare($sql);
            if ( !$resultUpdate->err ) {
               $resultUpdate->execute();
            }
            $resultUpdate->finish();
=cut
         }
         else {
            my $errCode;
            my $user_id;
            my $imsi;
            my $port;
            my $number;
            my $fecha;
            my $status;
            my $slot;
            my $ref_id;
            my $user_id;
            my $count;
            my $succ_count;
   
            # ---------------------   
            # JSON Perl Array
            # ---------------------   
            my @resultArray = @{$rc->{result}};
            my $items = @resultArray;
            $errCode = $rc->{result}[0]->{status}; 

            for (my $i = 0; $i < $items; $i++) {

               $imsi = $rc->{result}[$i]->{imsi}; 
               $port = $rc->{result}[$i]->{port}; 
               $number = $rc->{result}[$i]->{number}; 
               $fecha = $rc->{result}[$i]->{time}; 
               $status = $rc->{result}[$i]->{status}; 
               $slot = $rc->{result}[$i]->{slot}; 
               $ref_id = $rc->{result}[$i]->{ref_id}; 
               $user_id = $rc->{result}[$i]->{user_id}; 
               $count = $rc->{result}[$i]->{count}; 
               $succ_count = $rc->{result}[$i]->{succ_count}; 

               # ---------------------------
               # Hay STATUS de respuesta
               # ---------------------------
               my $status = sprintf( "%s: ID: %s, %s, %s, Status: %s", $number, $id, $ip, $fecha, $status );
               writeToLog( DEBUG, $logfile, $status, 0 );
               writeToLog( DEBUG, $logfile, "", 1 );

               # -------------------------------------------
               # Codigo Actualizado, verificar por SENT_OK
               # -------------------------------------------
               switch( $errCode ) {
   #              case /^(?:SENT_OK|SENDING|FAILED)$/ {
                  case /SENT_OK|SENDING|FAILED/ {
   
                     if( $send_count > 3 ) {
   
                        # -----------------------------
                        # Busco que plan tiene el Slot
                        # -----------------------------
                        my $strSlot = convertSlot( $slot );
                        $sql = sprintf( "select sql_no_cache gateway_ports.plan as plan from gateway_ports left join planes on planes.id=gateway_ports.plan where gw=%d and port=%d and slot='%s';", $gw, $port, $strSlot );
                        $resultUpdate = $dbh->prepare($sql);
                        if ( $resultUpdate->err ) {
                           $resultUpdate->finish();
                        }
                        else {
                           $resultUpdate->execute();
                           if( $resultUpdate->rows() > 0 ) {
                              $resultUpdate->finish();
   
                              # ---------------------------------------------------------------------------
                              # Test SIM port for Change por cantidad de errores a un numero ($recipient)
                              # ---------------------------------------------------------------------------
                              $sql = sprintf( "select sql_no_cache errorCount from delivery where gw=%d and port=%d and slot='%s' and recipient='%s';", $gw, $port, $strSlot, $number );
                              $resultDelivery = $dbh->prepare($sql);
                              if ( !$resultDelivery->err ) {
                                 $resultDelivery->execute();
                                 if( $resultDelivery->rows() == 0 ) {
   
                                    # ----------------------------------
                                    # Primer error, agrego registro
                                    # ----------------------------------
                                    $sql = sprintf( "insert into `delivery` (`id`,`fecha`,`gw`,`port`,`slot`,`errorCount`,`recipient`) VALUES (0,now(),%d,%d,'%s',1,'%s');", int($gw), int( $port ), $strSlot, $recipient );
                                    $resultDelivery = $dbh->prepare($sql);
                                    if ( $resultDelivery->err ) {
                                       $resultDelivery->finish();
                                       next;
                                    }
                                    $resultDelivery->execute();
                                 }
                              }
                              $resultDelivery->finish();
      
                              # ----------------------------------------------------------------
                              # Verifico si esta muerto para varios destinos lo cambio de slot
                              # ----------------------------------------------------------------
                              $sql = sprintf( "select sql_no_cache count(id) as total from delivery where gw=%d and port=%d and slot='%s';", $gw, $port, $strSlot );
                              $resultDelivery = $dbh->prepare($sql);
                              if ( $resultDelivery->err ) {
                                 $resultDelivery->finish();
                              }
                              else {
                                 $resultDelivery->execute();
                                 if( $resultDelivery->rows() > 0 ) {
                                 
                                    if(my @row = $resultDelivery->fetchrow_array()) {
                                 
                                       my ($delivery_count) = @row;
                                       $resultDelivery->finish();
                                 
                                       # -------------------------------------------
                                       # Hay mas de 5 numeros diferentes con error
                                       # Pongo en 0 los errores de ese nuevo puerto
                                       # Hay que matar este puerto slot
                                       # -------------------------------------------
                                       if( $delivery_count > 5 ) {
      
                                          writeToLog( DEBUG, $logfile, sprintf( "Slot Change GW because too many errors: %d, %d:%s", $gw, $port, $strSlot), 0 );
                                          writeToLog( DEBUG, $logfile, "", 1 );
   
                                          # -----------------------
                                          # Anulo este puerto/slot
                                          # -----------------------
                                          $sql = sprintf( "update gateway_ports set enabled=0, status=0, intento_registro='0000-00-00 00:00:00' where gw=%d and port=%d and slot='%s';", $gw, $port, $strSlot );
                                          $resultDelivery = $dbh->prepare($sql);
                                          if ( !$resultDelivery->err ) {
                                             $resultDelivery->execute();
                                          }
                                          $resultDelivery->finish();
   
   
                                          # --------------------------------
                                          # Traigo informacion del gateway
                                          # --------------------------------
                                          my $sql = sprintf( "select sql_no_cache ip, api_user, api_password, sn, user, password from gateways where id=%d;", $gw );
                                          my $resultGW = $dbh->prepare($sql);
                                          if ( !$resultGW->err ) {
                                             if( $resultGW->execute() ) {
                                                if ( $resultGW->rows() > 0 ) {
                                                   if (my @rowGW = $resultGW->fetchrow_array()) {
                                          
                                                      my ($ip, $api_user, $api_password, $sn, $user, $gw_password ) = @rowGW;
                                                      my $auth = $api_user . ":" . $api_password;
                                                      my $rc = SlotAvailable_Disable($dbh,@jsessionid,$gw,$port,$strSlot,$ip,$user,$gw_password,$sn,$auth);
                                                   }
                                                }
                                             }
                                          }
                                          $resultGW->finish();
   
                                          SlotChange($gw, $port, $slot, $ip, $auth, $dbh, $jsessionid[$gw], $sn, $errCode );
                                          SlotChange($gw, $port, $slot, $ip, $auth, $dbh, $jsessionid, $sn, $errCode );
   
                                          $sql = sprintf( "delete from delivery where gw=%d and port=%d and slot='%s';", $gw, $port, $strSlot );
                                          $resultDelivery = $dbh->prepare($sql);
                                          if ( $resultDelivery->err ) {
                                             $resultDelivery->finish();
                                          }
                                          else {
                                             $resultDelivery->execute();
                                             $resultDelivery->finish();
                                          }
                                       }
                                    }
                                 }
                              }
                              # ------------------------------------------------
                              # Actualizo contador de veces enviado este mensaje
                              # ------------------------------------------------
                              $sql = sprintf( "update %s set pending=102, error_description='%s', sent_count=sent_count+1 where id=%d;", $datatable, $status, $user_id );
                              $resultUpdate = $dbh->prepare($sql);
                              if ( !$resultUpdate->err ) {
                                 $resultUpdate->execute();
                              }
                              $resultUpdate->finish();
                           } # rows
                        }
                     }
                     else {
                        # ------------------------------
                        # Marco para enviar nuevamente?
                        # ------------------------------
                        $sql = sprintf( "update %s set pending=101, error_description='%s', sent_count=sent_count+1 where id=%d;", $datatable, $status, $user_id );  
                        $resultUpdate = $dbh->prepare($sql);
                        if ( !$resultUpdate->err ) {
                           $resultUpdate->execute();
                        }
                        $resultUpdate->finish();
                     }
                  }
                  else {
   
                     # -------------------------------------
                     # Marco como terminado con su Status
                     # -------------------------------------
                     my $strSlot = convertSlot( $slot );
                     $sql = sprintf( "update %s set pending=100, error_description='%s' where id=%d;", $datatable, $errCode, $user_id );
                     $resultUpdate = $dbh->prepare($sql);
                     if ( !$resultUpdate->err ) {
                        $resultUpdate->execute();
                     }
                     $resultUpdate->finish();
   
                     $sql = sprintf( "delete from delivery where gw=%d and port=%d and slot='%s';", $gw, $port, $strSlot );
                     $resultDelivery = $dbh->prepare($sql);
                     if ( !$resultDelivery->err ) {
                        $resultDelivery->execute();
                     }
                     $resultDelivery->finish();
                  }
               }
            }
         } 
      } #rc 

      $semaphore->down();
      $LocalCopy = $globalThreadCount; 
      $LocalCopy--;
      $globalThreadCount = $LocalCopy; 
      $Used[$index] = 0;
      if( defined($resultDelivery) ) {
         $resultDelivery->finish();
      }                  
      if( defined($resultUpdate) ) {
         $resultUpdate->finish();
      }         
      $dbh->disconnect();
      $semaphore->up();
      threads->exit();
   }   


   # ----------------------------------
   # Veo que puertos estan REGISTERED
   # ----------------------------------
   sub QueryPorts_Registration {
      my $conn = $_[0];
      my $resultUpdate;
      my $gw = 0;
      my $gw_id = 0;
      my $id = 0;
      my $ip = "";
      my $api_user = "";
      my $api_password = "";
      my $tipo_gw = "";
      my $sn = "";
      my $unregister_count = 0;
      my $display_flag = 0;
      my $count = 0;

#      my ($package, $filename, $line, $subroutine) = caller(0);
#      print "Caller: $filename, linea: $line, en el sub: $subroutine\n";

      # ---------------------------------------
      # Busco los ports habilitados de los GW
      # ---------------------------------------
      my $sql = sprintf( "select sql_no_cache gateway_ports.id, gw, ip, api_user, api_password, tipo_gw, unregister_count, gateways.id, gateways.sn from gateway_ports left join gateways on gateways.id=gw where enabled=1 group by gw;" );
      my $result = $dbh->prepare($sql);
      if ( $result->err ) {
         $result->finish();
         return "";
      }
      if( $result->execute() ) {

         while (my @row = $result->fetchrow_array()) {

#           my ($id, $gw, $ip, $api_user, $api_password, $registered ) = @row;
            ($id, $gw, $ip, $api_user, $api_password, $tipo_gw, $unregister_count, $gw_id, $sn ) = @row;
            $auth = $api_user . ":" . $api_password;

            # -------------------------------------
            # Verifico que gateway este accesible 
            # -------------------------------------
            if( PingTest( $ip, 1 ) == 0 ) {
               writeToLog( WARNING, $logfile, "GATEWAY $gw IS NOT AVAILABLE", 0 );
               writeToLog( WARNING, $logfile, "", 1 );
               next;
            }

            # -----------------------------------------------------------------
            # Verifico todos los puertos de los GW si estan registrados o no
            # y actualizo la base en gateway_ports
            # -----------------------------------------------------------------
            my $data = queryPortInfo( $ip, -1, $auth );
            if( $data ne "" ) {

               my $decoded = decode_json($data); 
               if( $decoded->{error_code} == 200 ) {
              
                  my $number = 1;
                  my $valor;
                  my $info = $decoded->{info};
                  my $imsi;
                  my $imei;
                  my $iccid;
                  my @port_status;
                  my $reg = 1;
                  my $len = scalar @$info;
                  my $slotStr = "";
                  my $errors = 0;
                  my $slot = 0;
                  my $gw_id = 0;
                  my $registered = 0;
                  my $id = 0;
                  my $enabled = 0;
                  my $prev_port = 0;
                  my $actual_port = 0;

                  for( $i = 0; $i < $len; $i++ ) {

                     $display_flag = 0;
                     $reg = 1;
                     $imsi  = $decoded->{info}[$i]{imsi};                     
                     $imei  = $decoded->{info}[$i]{imei};                     
                     $iccid = $decoded->{info}[$i]{iccid};                     
                     $slot  = $decoded->{info}[$i]{slot};
                     $actual_port = int($decoded->{info}[$i]{port});
              
                     $slotStr = getSlotName( int($decoded->{info}[$i]{slot}) );
                     $port_status[$decoded->{info}[$i]{port}] = $decoded->{info}[$i]{callstate};

                     $sql = sprintf( "select sql_no_cache id, enabled, registered from gateway_ports where gw=%d and port=%d and slot='%s';", $gw, $decoded->{info}[$i]{port}, $slotStr );
                     my $resultRegistered = $dbh->prepare($sql);
                     if( !$resultRegistered->err ) {
                        if( $resultRegistered->execute() ) {
                           if( $resultRegistered->rows() > 0 ) {
                              if(my @rowRegistered = $resultRegistered->fetchrow_array()) {
                                 ($id, $enabled, $registered ) = @rowRegistered;
                              }
                           }
                        }
                     }
                     $resultRegistered->finish();
 
                     if( $decoded->{info}[$i]{reg} ne "REGISTER_OK" ) {

                        if( $registered == 1 || $firstRun) {

                           if( $slotStr ne "X" ) {
                              writeToLog( WARNING, $logfile, sprintf( "%2d%s %-8s %-15s %-23s",$decoded->{info}[$i]{port}, $slotStr, $decoded->{info}[$i]{type}, $decoded->{info}[$i]{imei}, "NOT REGISTERED" ), 0 );
#                             $sql = sprintf( "update gateway_ports set registered=0, unregister_count=0, intento_registro='0000-00-00 00:00:00' where gw=%d and port=%d and slot='%s';", $gw, $decoded->{info}[$i]{port}, $slotStr );
                              $sql = sprintf( "update gateway_ports set registered=0, unregister_count=0, intento_registro='0000-00-00 00:00:00' where gw=%d and port=%d;", $gw, $decoded->{info}[$i]{port} );
                              $resultUpdate = $dbh->prepare($sql);
                              if ( !$resultUpdate->err ) {
                                 $resultUpdate->execute();
                              }
                              $resultUpdate->finish();
                              ++$count;
                           }
                           else {
                              $sql = sprintf( "update gateway_ports set registered=0, unregister_count=0, intento_registro='0000-00-00 00:00:00' where gw=%d and port=%d;", $gw, $decoded->{info}[$i]{port} );
                              $resultUpdate = $dbh->prepare($sql);
                              if ( !$resultUpdate->err ) {
                                 $resultUpdate->execute();
                              }
                              $resultUpdate->finish();

                              if( $firstRun || $decoded->{info}[$i]{reg} ne "NO_SIM" ) {
                                writeToLog( WARNING, $logfile, sprintf( "%2d  %-8s %-15s    %23s",$decoded->{info}[$i]{port}, $decoded->{info}[$i]{type}, $decoded->{info}[$i]{imei}, $decoded->{info}[$i]{reg} ), 0 );
                                ++$count;
                              }
                           }
                        }
                     }
                     else {

                        # ------------------------------------------
                        # Si no estaba registrado anteriormente
                        # verifico el IMEI y el ANI
                        # ------------------------------------------
                        if( $registered == 0 || $firstRun ) {

                           if( $count == 0 && !$firstRun ) {
#                              writeToLog( WARNING, $logfile, "", 1 );
                           }
                           my $port = int($decoded->{info}[$i]{port});

                           $sql = sprintf( "update gateway_ports set registered=1, unregister_count=0, intento_registro='0000-00-00 00:00:00' where gw=%d and port=%d and slot='%s';", $gw, $decoded->{info}[$i]{port}, $slotStr );
                           $resultUpdate = $dbh->prepare($sql);
                           if ( !$resultUpdate->err ) {
                              $resultUpdate->execute();
                           }
                           $resultUpdate->finish();
  
                           $display_flag = 1;

                           if( $firstRun == 0 ) {
                              QueryANI($ip, $port, $auth, $id, $tipo_gw );
                              IMEI( $dbh, $ip, int($decoded->{info}[$i]{port}), $auth, $imsi, $imei, $iccid );
                           }
            
                           # ---------------------------
                           # Saco registro de los demas
                           # ---------------------------
                           $sql = sprintf( "update gateway_ports set registered=0 where gw=%d and port=%d and slot <> '%s';", $gw, $decoded->{info}[$i]{port}, $slotStr );
                           $resultUpdate = $dbh->prepare($sql);
                           if ( !$resultUpdate->err ) {
                              $resultUpdate->execute();
                           }
                           $resultUpdate->finish();
                        }

                        if( $display_flag ) {
                           writeToLog( WARNING, $logfile, sprintf( "%2d%s %-8s %-15s %3s(dBm) %-10s %-23s", int($decoded->{info}[$i]{port}), $slotStr, $decoded->{info}[$i]{type}, $decoded->{info}[$i]{imei}, $decoded->{info}[$i]{signal}, $decoded->{info}[$i]{callstate}, $decoded->{info}[$i]{reg} ), 0 );
                           ++$count;
                        }
                     }
                     $number++;
                  } # for

                  if( $count > 0 ) {
                     writeToLog( WARNING, $logfile, "", 1 );
                  }
               } # error_code == 200
            }
            else {
               writeToLog( WARNING, $logfile, "GATEWAY $gw NOT AVAILABLE", 0 );
               writeToLog( WARNING, $logfile, "", 1 );
            }               
         } # while
      }
      $result->finish();
   }





   # -----------------------------------------------------------------------------------------------
   # Port Change Verify or Update IMEI
   #
   # Veo en el gw que sims tiene intalados. Si ya estuvo ese IMSI le pongo siempre el mismo IMEI
   # Si no estuvo nunca genero un nuevo IMEI y lo guardo en la tabla
   # -----------------------------------------------------------------------------------------------

   sub PortChangeStatus {
      my $dbh = $_[0];
      my $gw = $_[1];
      my $port = $_[2];
      my $imei;

      writeToLog( DEBUG, $logfile, sprintf( "PortChangeStatus( %d, %d , '%s' )", $gw, $port, $imei ), 0 );
      my $sql = sprintf( "select sql_no_cache ip, api_user, api_password from gateways where id=%d;", int($gw) );
      my $result = $dbh->prepare($sql);
      if ( $result->err ) {
         db_Error( DEBUG, $result->err, $result->errstr );
         Time::HiRes::sleep(10);
         return "";
      }
      
      if( $result->execute() ) {
         while (my @row = $result->fetchrow_array()) {

            my ($ip, $api_user, $api_password ) = @row;
            $auth = $api_user . ":" . $api_password;

            my $data = queryPortInfo( $ip, $port, $auth );
            my $decoded = decode_json($data); 

            if( $decoded->{error_code} == 200 ) {

               my $valor;
               my $info = $decoded->{info};
               my $imsi;
               my $imei;
               my $iccid;
               my @port_status;
               my $reg = 1;
               my $len = scalar @$info;
               my $slotStr = "";

               for( $i = 0; $i < $len; $i++ ) {
                  $reg = 1;
                  my $imsi  = $decoded->{info}[$i]{imsi};                     
                  my $iccid = $decoded->{info}[$i]{iccid};                     
                  my $slot = $decoded->{info}[$i]{slot};                     
                  $imei  = $decoded->{info}[$i]{imei};                     

                  $imei = IMEI( $dbh, $ip, $port, $auth, $imsi, $imei, $iccid );
               }
            }
 
         }
      }
      $result->finish();
  }



   # --------------------------------------
   # writeToLog
   # --------------------------------------

   sub writeToLog 
   {  
      my $level = $_[0];
      my $filename = $_[1];
      my $text = $_[2];
      my $mode = $_[3];

      if( $debug == DEBUG || $level <= $debug ) {

         if( open(FH, '>>', $filename) ) {
            if( $mode == 1 ) {
               $text = "+--------------------------------------------------------------------------------------------------+";
            }
            my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
            my $hoy = sprintf( "%02d.%02d.%04d %02d:%02d:%02d", $mday, $mon + 1, $year + 1900, $hour, $min, $sec );
            printf( FH sprintf( "%s: %s\n", $hoy, $text ) );
            printf( sprintf( "%s: %s\n", $hoy, $text ) );
            close(FH);
         }      
      }         
   }

   # ---------------------------
   # Cuantos Thread hay en uso
   # ---------------------------

   sub UsedThreads
   {
      my $str = "";   
      for( my $x = 0; $x < $threadCount; $x++ ) {
         if( $x == 0 ) {
            if( $Used[$x] == 0 ) {
               $str .= "0";
            }
            else {
               $str .= "1";
            }
         }
         else {
            if( $Used[$x] == 0 ) {
               $str .= ", 0";
            }
            else {
               $str .= ", 1";
            }
         }

      }
#      writeToLog( DEBUG, $logfile, sprintf( "Threads %d: (%s)", $globalThreadCount, $str ), 0 );
#      writeToLog( DEBUG, $logfile, "", 1 );
   }



   # ----------------------------------------------------------------
   # Disable All Slot Except
   # ----------------------------------------------------------------

   sub SlotAvailable_SendEmail {
      my $body = $_[0];

      my $to = 'ag@interactivos.net.ar';
#     my $cc = 'efgh@mail.com';
      my $from = 'soporte@interactivos.net.ar';
      my $subject = 'Sms Gateway Notification';
      my $message = $body;


      my $mailer = Email::Send->new( {
          mailer => 'SMTP::TLS',
          mailer_args => [
              Host => 'box.interactivos.net.ar',
              Port => 587,
              User => 'soporte@interactivos.net.ar',
              Password => 'Dialer1959',
              Hello => 'interactivos.net.ar',
          ]
      } );

      my $email = Email::Simple->create(
         header => [
           From    => $from,
           To      => $to,
           Subject => $subject,
         ],
         body => $message,
      );
      eval { $mailer->send($email) };
   }

   # --------------------------
   # Disable All Slot Except
   # --------------------------

   sub SlotAvailable_DisableAllSlots {
      my $gw = $_[0];
      my $port = $_[1];
      my $jsessionid = $_[2];
      my $ip = $_[3];
      my $sn = $_[4];
      my $slot = $_[5];
      my $auth = $_[6];

      if( !defined($jsessionid) ) {
         return 0;
      }

      if( $slot ne "A" ) {
         disableSlot( $ip, $port, "A", $auth, $jsessionid, $sn );
      }
      if( $slot ne "B" ) {
         disableSlot( $ip, $port, "B", $auth, $jsessionid, $sn );
      }
      if( $slot ne "C" ) {
         disableSlot( $ip, $port, "C", $auth, $jsessionid, $sn );
      }
      if( $slot ne "D" ) {
         disableSlot( $ip, $port, "D", $auth, $jsessionid, $sn );
      }
      return 1;
   }

   # --------------------------------------------------
   # Disable Slot por NO REGISTRO y AVISO
   #
   # 0: ERROR. NO PUDE INHABILITAR
   # 1: SE INHABILITO
   # --------------------------------------------------

   sub SlotAvailable_Disable {
      my $dbh = $_[0];
      my @jsessionid = $_[1];
      my $gw = $_[2];
      my $port = $_[3];
      my $slot = $_[4];
      my $ip = $_[5];
      my $user = $_[6];
      my $password = $_[7];
      my $sn = $_[8];
      my $auth = $_[9];

      if( !defined($jsessionid[$gw]) ) {
      
         my $session = loginGateway( $ip, $user, $password ); 
         $jsessionid[$gw] = $session;
      
         if( !defined($jsessionid[$gw]) ) {
            writeToLog( WARNING, $logfile, sprintf( "Invalid JSESSIONID GW: %d, %d%s", $gw, $port, $slot ), 0 );
         }
         else {
            disableSlot( $ip, $port, $slot, $auth, $jsessionid[$gw], $sn );

#           my $sql = sprintf( "update gateway_ports set status=0, enabled=0, intento_registro='0000-00-00 00:00:00' where gw=%d and port=%d and slot='%s';", $gw, $port, $slot );
            my $sql = sprintf( "update gateway_ports set status=0, intento_registro='0000-00-00 00:00:00' where gw=%d and port=%d and slot='%s';", $gw, $port, $slot );
            my $resultUpdate = $dbh->prepare($sql);
            if ( !$resultUpdate->err ) {
               $resultUpdate->execute();
            }
            $resultUpdate->finish();
            # -------------------------------------------------
            # Habilito un slot de ese puerto si hay disponible 
            # -------------------------------------------------
            return 1;
         }
      }
      return 0;
   }

   # -----------------
   # Process a Port
   # -----------------

   sub SlotAvailable_Ok {
      my $dbh = $_[0];
      my @jsessionid = $_[1];
      my $gw = $_[2];
      my $port = $_[3];

      my $my_user = "";
      my $my_password = "";
      my $my_sn;
      my $my_ip = "";
      my $my_api_user = "";
      my $my_api_password = "";
      my $my_auth = "";
      my ($ultimo, $enviados, $status, $plan ) = "", 0, 0, 0;

      # --------------------------------
      # Traigo informacion del gateway
      # --------------------------------
      my $sql = sprintf( "select sql_no_cache ip, api_user, api_password, sn, user, password from gateways where id=%d;", $gw );
      my $resultGW = $dbh->prepare($sql);
      if ( !$resultGW->err ) {
         if( $resultGW->execute() ) {
            if ( $resultGW->rows() > 0 ) {
               if (my @rowGW = $resultGW->fetchrow_array()) {
      
                  my ($ip, $api_user, $api_password, $sn, $user, $gw_password ) = @rowGW;
                  $auth = sprintf( "%s:%s", $api_user, $api_password );
                  $my_user = $user;
                  $my_password = $gw_password;
                  $my_sn = $sn;
                  $my_ip = $ip;
                  $my_api_user = $api_user;
                  $my_api_password = $api_password;
                  $my_auth = $auth;
               }
            }
         }
      }
      else {
         $resultGW->finish();
         return( 0 );
      }
      $resultGW->finish();

      # -------------------------------------
      # Verifico que gateway este accesible 
      # -------------------------------------
      if( PingTest( $my_ip, 1 ) == 0 ) {
         writeToLog( WARNING, $logfile, "GATEWAY $gw IS NOT AVAILABLE", 0 );
         writeToLog( WARNING, $logfile, "", 1 );
         return 1;
      }


      # ----------------------------------------------------------------------------
      # Busco cuantos mensajes diarios tiene disponibles cada slot de ese puerto
      # de los slots que estan activos. Empiezo con cual esta registrado.
      # ----------------------------------------------------------------------------
      $sql = sprintf( "select sql_no_cache gateway_ports.id, slot, date(fecha_ultimo), gateway_ports.plan, maximo_diarios, enabled, gateway_ports.status, registered from gateway_ports left join planes on planes.id=gateway_ports.plan where enabled=1 and gw=%d and port=%d order by registered desc;", $gw, $port );
      my $resultEnabled = $dbh->prepare($sql);
      if ( !$resultEnabled->err ) {
         if( $resultEnabled->execute() ) {
            while (my @row = $resultEnabled->fetchrow_array()) {

               my ($id, $slot, $ultimo, $plan, $maximo_diarios, $enabled, $port_status, $registered ) = @row;

               # ----------------------------------------------
               # Busco mensajes enviados de este slot
               # ----------------------------------------------
               $sql = sprintf( "select sql_no_cache fecha, enviados, status, plan from port_statistics where gateway=%d and port=%d and slot='%s' and date(fecha)=date(now());", $gw, $port, $slot );
               my $resultSend = $dbh->prepare($sql);
               if ( !$resultSend->err ) {
                  if( $resultSend->execute() ) {
                     if ( $resultSend->rows() > 0 ) {
                        if (my @rowSend = $resultSend->fetchrow_array()) {
                           ($ultimo, $enviados, $status, $plan ) = @rowSend;
                        }
                     }
                     else {
                        $sql = sprintf( "insert into `port_statistics` (`id`,`fecha`,`gateway`,`port`,`slot`,`enviados`,`plan`,`status`) VALUES (0,now(),%d,%d,'%s',0,%d,1);", int($gw), int( $port ), $slot, int($plan) );
                        my $resultStat = $dbh->prepare($sql);
                        if ( !$resultStat->err ) {
                            $resultStat->execute();
                        }
                        $resultStat->finish();
                     }
                  }
               }


               # ------------------------------------------
               # Si el slot registrado pero no habilitado
               # ------------------------------------------
               if( $port_status == 0 && $registered == 1 ) {

                  if( $enviados >= $maximo_diarios ) {

                     writeToLog( DEBUG, $logfile, sprintf( "SlotAvailable_Ok: GW %d, Port: %2d%s, Registered: %d (NO TIENE MAS MENSAJES)", $gw, $port, $slot, $registered ), 0 );
                  
                     # --------------------------------------------------------------
                     # Activo, no tiene mensajes, lo desactivo y deshabilito slot.
                     # --------------------------------------------------------------
                     $sql = sprintf( "update gateway_ports set status=0 where gw=%d and port=%d and slot='%s';", $gw, $port, $slot );
                     my $resultUpdate = $dbh->prepare($sql);
                     if ( !$resultUpdate->err ) {
                        $resultUpdate->execute();
                     }
                     $resultUpdate->finish();

                     # ------------------------------------
                     # Disable Slot no tiene mas mensajes
                     # ------------------------------------
                     my $rc = SlotAvailable_Disable($dbh,@jsessionid,$gw,$port,$slot,$my_ip,$my_user,$my_password,$my_sn,$my_auth);
                     $resultSend->finish();
                     return( $rc );
                  }
                  else {
                     # -----------------------------
                     # Tiene mensajes, sigue igual
                     # -----------------------------
                     $resultSend->finish();

                     writeToLog( DEBUG, $logfile, sprintf( "SlotAvailable_Ok: GW %d, Port: %d%s (REGISTRADO, NO HABILITADO)", $gw, $port, $slot ), 0 );
                     # --------------------------------------------------------------
                     # Activo, no tiene mensajes, lo desactivo y deshabilito slot.
                     # --------------------------------------------------------------
                     $sql = sprintf( "update gateway_ports set status=1 where gw=%d and port=%d and slot='%s';", $gw, $port, $slot );
                     my $resultUpdate = $dbh->prepare($sql);
                     if ( !$resultUpdate->err ) {
                        $resultUpdate->execute();
                     }
                     $resultUpdate->finish();
#                     enableSlot( $my_ip, $port, $slot, $my_auth, $jsessionid[$gw], $my_sn );

                     $sql = sprintf( "update gateway_ports set status=0 where gw=%d and port=%d and slot<>'%s';", $gw, $port, $slot );
                     my $resultUpdate = $dbh->prepare($sql);
                     if ( !$resultUpdate->err ) {
                        $resultUpdate->execute();
                     }
                     $resultUpdate->finish();
                     writeToLog( DEBUG, $logfile, sprintf( "SlotAvailable_Ok: GW %d, Port: %2d%s (REGISTRADO, LO HABILITE)", $gw, $port, $slot ), 0 );
                     return( 1 );
                  }
               }

               # ------------------------------------------
               # Si el slot esta habilitado y registrado
               # ------------------------------------------
               if( $port_status == 1 && $registered == 1 ) {

                  if( $enviados >= $maximo_diarios ) {

                     writeToLog( DEBUG, $logfile, sprintf( "SlotAvailable_Ok: GW %d, Port: %2d%s, Registered: %d (NO TIENE MAS MENSAJES)", $gw, $port, $slot, $registered ), 0 );
                  
                     # --------------------------------------------------------------
                     # Activo, no tiene mensajes, lo desactivo y deshabilito slot.
                     # --------------------------------------------------------------
                     $sql = sprintf( "update gateway_ports set status=0 where gw=%d and port=%d and slot='%s';", $gw, $port, $slot );
                     my $resultUpdate = $dbh->prepare($sql);
                     if ( !$resultUpdate->err ) {
                        $resultUpdate->execute();
                     }
                     $resultUpdate->finish();

                     # ------------------------------------
                     # Disable Slot no tiene mas mensajes
                     # ------------------------------------
                     my $rc = SlotAvailable_Disable($dbh,@jsessionid,$gw,$port,$slot,$my_ip,$my_user,$my_password,$my_sn,$my_auth);
                     $resultSend->finish();
                     return( $rc );
                  }
                  else {
                     # -----------------------------
                     # Tiene mensajes, sigue igual
                     # -----------------------------
                     $resultSend->finish();
#                    writeToLog( DEBUG, $logfile, sprintf( "SlotAvailable_Ok: GW %d, Port: %d%s (SIGUE TODO IGUAL)", $gw, $port, $slot ), 0 );
                     return( 0 );
                  }
               }
               else {

                  # ---------------------------------------------------------------------------------
                  # Si esta habilitado, activo, tiene mensajes y no esta registrado, habilito slot. 
                  # si hay otros habilitados y activos, los inactivo. 
                  # Espero un tiempo para verificar si se registro.
                  # ---------------------------------------------------------------------------------
                  if( $port_status == 1 && $registered == 0 ) {

#                    writeToLog( DEBUG, $logfile, sprintf( "SlotAvailable_Ok: GW %d, Port: %d%s, Registered: %d (HABILITADO, NO REGISTRADO)", $gw, $port, $slot, $registered ), 0 );

                     # --------------------------------------------------------
                     # Verifico e1 tiempo que estuve esperando que se registre
                     # --------------------------------------------------------
                     $sql = sprintf( "select sql_no_cache intento_registro, registered, ( case when DATE_ADD(intento_registro, INTERVAL 5 MINUTE) < now() then 1 else 0 end ), DATE_ADD(intento_registro, INTERVAL 5 MINUTE), now() from gateway_ports where gw=%d and port=%d and slot='%s';", $gw, $port, $slot );
                     my $resultTime = $dbh->prepare($sql);
                     if ( !$resultTime->err ) {
                        if( $resultTime->execute() ) {
                           if ( $resultTime->rows() > 0 ) {
                              if (my @rowTime = $resultTime->fetchrow_array()) {

                                 my ($intento_time, $registered, $timed, $timed_time, $actual_time ) = @rowTime;
                                 $resultTime->finish();

                                 # -------------------------------------------------------
                                 # No se registro en 5 minutos, Deshabilito slot y AVISO
                                 # -------------------------------------------------------
                                 if( $timed == 1 ) {
                                    writeToLog( DEBUG, $logfile, sprintf( "SlotAvailable_Ok: GW %d, Port: %2d%s (INHABILITO SLOT)", $gw, $port, $slot ), 0 );

                                    my $rc = SlotAvailable_Disable($dbh,@jsessionid,$gw,$port,$slot,$my_ip,$my_user,$my_password,$my_sn,$my_auth);
                                    $sql = sprintf( "update gateway_ports set registered=0, status=0 where gw=%d and port=%d and slot='%s';", $gw, $port, $slot );
                                    my $resultTime = $dbh->prepare($sql);
                                    if ( !$resultTime->err ) {
                                       $resultTime->execute();
                                    }
                                    $resultTime->finish();

                                    # -----------
                                    # AVISO
                                    # -----------
                                    writeToLog( DEBUG, $logfile, sprintf( "SlotAvailable_Ok: GW %d, Port: %2d%s (DEATH SIM SLOT)", $gw, $port, $slot ), 0 );
                                    my $body = sprintf( "\nGateway: %d\nPort: %d%s -IS DEATH\n", $gw, $port, $slot );
                                    SlotAvailable_SendEmail( $body );
                                    return $rc;
                                 }
                                 else {

                                    # -----------------------
                                    # Tengo que habilitarlo 
                                    # -----------------------
#                                   printf( "%s\n", $intento_time );
                                    if( $intento_time eq '0000-00-00 00:00:00' ) {

                                       if( !defined($jsessionid[$gw]) ) {
                  
                                          my $session = loginGateway( $my_ip, $my_user, $my_password ); 
                                          $jsessionid[$gw] = $session;
                                          if( !defined($jsessionid[$gw]) ) {
                                             writeToLog( WARNING, $logfile, sprintf( "Invalid JSESSIONID GW: %d, %2d%s", $gw, $port, $slot ), 0 );
                                          }
                                       }
                                       if( defined($jsessionid[$gw]) ) {

#                                         writeToLog( DEBUG, $logfile, sprintf( "SlotAvailable_Ok: GW %d, Port: %d%s, IP: %s, Session: %s, SN: %s (HABILITO SLOT)", $gw, $port, $slot, $my_ip, $jsessionid[$gw], $my_sn ), 0 );
                                          writeToLog( DEBUG, $logfile, sprintf( "SlotAvailable_Ok: GW %d, Port: %2d%s, IP: %s, SN: %s (HABILITO SLOT)", $gw, $port, $slot, $my_ip, $my_sn ), 0 );

                                          enableSlot( $my_ip, $port, $slot, $my_auth, $jsessionid[$gw], $my_sn );
                                          $sql = sprintf( "update gateway_ports set intento_registro=now() where gw=%d and port=%d and slot='%s';", $gw, $port, $slot );
                                          my $resultUpdate = $dbh->prepare($sql);
                                          if ( !$resultUpdate->err ) {
                                             $resultUpdate->execute();
                                          }
                                          $resultUpdate->finish();
                                          $resultTime->finish();
                                          return 1;
                                       }                                             
                                    }
                                    else {
                                       writeToLog( DEBUG, $logfile, sprintf( "SlotAvailable_Ok: GW %d, Port: %2d%s (HABILITADO, NO REGISTRADO, ESPERANDO REGISTRO)", $gw, $port, $slot ), 0 );
                                       $resultTime->finish();
                                       return 1;
                                    }
                                 }
                              }
                           }
                           else {
                              $resultTime->finish();
                              return 1;
                           }
                        }                  
                     }   
                     $resultTime->finish();
                  }
                  else {

                     # ----------------------------------------
                     # Habilitado. Busco Slot para Habilitar
                     # ----------------------------------------
                     if( $port_status == 0 && $registered == 0 ) {

                        writeToLog( DEBUG, $logfile, sprintf( "SlotAvailable_Ok: GW %d, Port: %2d%s (NO HABILITADO, NO REGISTRADO)", $gw, $port, $slot ), 0 );

                        #---------------------------
                        # Busco mensajes enviados
                        #---------------------------
                        $sql = sprintf( "select sql_no_cache fecha, enviados, status, plan from port_statistics where gateway=%d and port=%d and slot='%s' and date(fecha)=date(now());", $gw, $port, $slot );
                        my $resultSend = $dbh->prepare($sql);
                        if ( !$resultSend->err ) {
                           if( $resultSend->execute() ) {
                              if ( $resultSend->rows() > 0 ) {
                                 if (my @rowSend = $resultSend->fetchrow_array()) {
                                    my ($ultimo, $enviados, $status, $plan ) = @rowSend;

                                    if( $enviados < $maximo_diarios ) {

                                       if( !defined($jsessionid[$gw]) ) {
                  
                                          my $session = loginGateway( $my_ip, $my_user, $my_password ); 
                                          $jsessionid[$gw] = $session;
                                          if( !defined($jsessionid[$gw]) ) {
                                             writeToLog( WARNING, $logfile, sprintf( "Invalid JSESSIONID GW: %d, %2d%s", $gw, $port, $slot ), 0 );
                                          }
                                       }
                                       if( defined($jsessionid[$gw]) ) {
#                                          writeToLog( DEBUG, $logfile, sprintf( "SlotAvailable_Ok: GW %d, Port: %d%s, IP: %s, Session: %s, SN: %s (HABILITO SLOT,STATUS)", $gw, $port, $slot, $my_ip, $jsessionid[$gw], $my_sn ), 0 );
                                          writeToLog( DEBUG, $logfile, sprintf( "SlotAvailable_Ok: GW %d, Port: %2d%s, IP: %s, SN: %s (HABILITO SLOT,STATUS)", $gw, $port, $slot, $my_ip, $my_sn ), 0 );

                                          my $rc = SlotAvailable_DisableAllSlots( $gw, $port, $jsessionid[$gw], $my_ip, $my_sn, $slot, $my_auth );
                                          if( $rc == 1 ) {

                                             $sql = sprintf( "update gateway_ports set registered=0 where gw=%d and port=%d;", $gw, $port );
                                             my $resultUpdate = $dbh->prepare($sql);
                                             if ( !$resultUpdate->err ) {
                                                $resultUpdate->execute();
                                             }
                                             $resultUpdate->finish();
 
                                             enableSlot( $my_ip, $port, $slot, $my_auth, $jsessionid[$gw], $my_sn );
                                             $sql = sprintf( "update gateway_ports set status=1, intento_registro=now() where gw=%d and port=%d and slot='%s';", $gw, $port, $slot );
                                             my $resultUpdate = $dbh->prepare($sql);
                                             if ( !$resultUpdate->err ) {
                                                $resultUpdate->execute();
                                             }
                                             $resultUpdate->finish();
                                             $resultSend->finish();
                                             return 1;
                                          }
                                          else {
                                             writeToLog( DEBUG, $logfile, sprintf( "SlotAvailable_Ok: GW %d, Port: %2d%s, IP: %s, Session: %s, SN: %s (CANNOT DISABLE SLOTS)", $gw, $port, $slot, $my_ip, $jsessionid[$gw], $my_sn ), 0 );
                                          }
                                       }
                                    }
                                 }
                              }
                           }
                        }
                        $resultSend->finish();
                     }
                  }
               }
            } # while
         }
      }
      $resultEnabled->finish();
      return 0;
   }


   # --------------------------------------------------------------------------------------------
   # Verifico si hay puertos deshabilitados y existe algun slot que puede ser habilitado
   # --------------------------------------------------------------------------------------------
   sub SlotAvailable_Active {
      my $dbh = $_[0];
      my @jsessionid = $_[1];
      my $display = 0;

      # -------------------------------------------------------
      # Busco los Puertos/Slot habilitados de cada Gateway
      #
      # Enabled     = 1   Esta con sim
      # Status      = 1   Es que esta en uso
      # Registered  = 1   Es que esta registrado
      # -------------------------------------------------------
      my $sql = sprintf( "select sql_no_cache count(id) as ports, gw, port from gateway_ports where enabled=1 group by gw,port;" );
      my $resultPorts = $dbh->prepare($sql);
      if ( !$resultPorts->err ) {
         if( $resultPorts->execute() ) {
            while (my @rowPorts = $resultPorts->fetchrow_array()) {
               my ($ports, $gw, $port ) = @rowPorts;

#              writeToLog( DEBUG, $logfile, sprintf( "SlotAvailable_Active: GW %d, Port: %d", $gw, $port ), 0 );
               my $rc = SlotAvailable_Ok($dbh,@jsessionid,$gw,$port);
               if( $rc == 1 ) {
                  $display = 1;
               }
            }
         }
      }
      $resultPorts->finish();
      if( $display == 1 ) {
         writeToLog( DEBUG, $logfile, "", 1 );
      }
   }


   # ---------------------------
   # Cambio IMEI en el Puerto
   # ---------------------------
   sub IMEI {
      my $dbh = $_[0];
      my $ip = $_[1];
      my $port = $_[2];
      my $auth = $_[3];
      my $imsi = $_[4];
      my $imei = $_[5];
      my $iccid = $_[6];

      if( $imeiChange == 0 ) {
         return $imei;
      }

#      my ($package, $filename, $line, $subroutine) = caller(0);
#      print "Caller: $filename, linea: $line, en el sub: $subroutine\n";

      if( $imsi ne "" ) {
         my $sql = sprintf( "select sql_no_cache imei, actual_port from imsi where imsi='%s';", $imsi );
         my $resultUpdate = $dbh->prepare($sql);
         if ( $resultUpdate->err ) {
            $resultUpdate->finish();
            return "";
         }
        
         if( $resultUpdate->execute() ) {
            if (my @rowUpdate = $resultUpdate->fetchrow_array()) {
               my ($dbimei,$actual_port) = @rowUpdate;

               if( $imei ne $dbimei ) {
                  writeToLog( DEBUG, $logfile, sprintf( "IMEI: IMSI = %s, IMEI = %s UPDATE Port: %d", $imsi, $dbimei, $port ), 0 );
                  $resultUpdate->finish();
                  $sql = sprintf( "update imsi set actual_port=%d where imsi='%s';", $port, $imsi );
                  $resultUpdate = $dbh->prepare($sql);
                  if ( !$resultUpdate->err ) {
                     $resultUpdate->execute();
                  }  
                  $imei = changeIMEI( $ip, $port, $auth, $dbimei );
               }   
            }
            else {
               if( $tac ne "" ) {
                  my $serial = 111111 + int(rand(999999 - 111111));
                  $imei = sprintf( "%s%6d", $tac, $serial );
               }
               $imei = calculateIMEI( $imei );
               my $ani = "";   
               $resultUpdate->finish();

               $sql = sprintf( "insert into `imsi` (`id`,`fecha`,`imsi`,`imei`,`ani`,`iccid`,`actual_port`) VALUES (0,now(),'%s','%s','%s','%s',%d);", $imsi, $imei, $ani, $iccid, $port );
               $resultUpdate = $dbh->prepare($sql);
               if ( $resultUpdate->err ) {
                  $resultUpdate->finish();
                  return "";
               }
               $resultUpdate->execute();
               $resultUpdate->finish();
              
               # --------------
               # Set NewIMEI
               # --------------
               writeToLog( DEBUG, $logfile, sprintf( "IMEI: IP %s, Port: %d, IMEI: %s", $ip, $port, $imei ), 0 );
               $imei = changeIMEI( $ip, $port, $auth, $imei );
            }
         }
         $resultUpdate->finish();
      }
      return( $imei );
   }      
     

   # ---------------------
   # Envio Mensaje x ANI
   # ---------------------
   sub QueryANI {
      my $ip = $_[0];
      my $port = $_[1];
      my $auth = $_[2];
      my $id= $_[3];
      my $tipo_gw = $_[4];

      my $sendCode = sendSms( $ip, "321", "num", $port, $auth, $id, $tipo_gw, $coding );
      my $errCode = $sendCode->{error_code};
      if( $errCode == 202 ) {
         my $smsInQueue = $sendCode->{sms_in_queue};
#         printf( "ANI Message sended\n" );
         return 1;
      }
      else {
#         printf( "ANI Message error %d\n", $errCode );
         return 0;
      }
   }

   # -------------------
   # db_Error
   # -------------------
   sub db_Error {
      my $level = $_[0];
      my $err = $_[1];
      my $errStr = $_[2];

      writeToLog( $level, $logfile, sprintf( "DBI Error: $err : $errStr" ), 0 );
   }

   # ---------------
   # Test for ping
   # ---------------

   sub PingTest {
      my $my_addr = "10.0.66.119";
      my $host = $_[0];
      my $rc = 0;
   
      my $p = Net::Ping->new("icmp");
      $p->hires();
      $p->bind($my_addr); # Specify source interface of pings
      $rc = $p->ping($host,500);
      $p->close();
      return $rc;
   }
















=begin
   # -------------------------------------------------------
   # Cambio Puerto por que no esta entregando mas Mensajes
   # -------------------------------------------------------

   sub SlotChange {
#      global $conn;
#      global $jsessionid;

      my $gw = $_[0];
      my $port = $_[1];
      my $slot = $_[2];
      my $ip = $_[3];
      my $auth = $_[4];
      my $dbh = $_[5];
      my $jsessionid = $_[6];
      my $sn = $_[7];
      my $errCode = $_[8];


      writeToLog( DEBUG, $logfile, sprintf( "Disabling Port (%s) %d: %d:%s (jsessionid: %s)\n", $gw, $port, $slot, $errCode, $jsessionid ), 0 );

      # ----------------------------------------------------------------------------------
      # Lo deshabilito tengo que modificar para poner status de no usar hasta el otro dia
      # ----------------------------------------------------------------------------------
      my $slotStr = getSlotName( int($slot) );

      my $sql = sprintf( "update gateway_ports set status=0 where gw=%d and port=%d and slot='%s';", $gw, $port, $slotStr );
      my $resultUpdate = $dbh->prepare($sql);
      if ( $resultUpdate->err ) {
         db_Error( DEBUG, $resultUpdate->err, $resultUpdate->errstr );
         Time::HiRes::sleep(1);
         $resultUpdate->finish();
         return "";
      }
      $resultUpdate->execute();
      $resultUpdate->finish();

      $sql = sprintf( "update port_statistics set status=0, disabled_day=1 where gateway=%d and port=%d and slot='%s' and date(fecha)=date(now());", $gw, $port, $slotStr );
      $resultUpdate = $dbh->prepare($sql);
      if ( $resultUpdate->err ) {
         db_Error( DEBUG, $resultUpdate->err, $resultUpdate->errstr );
         Time::HiRes::sleep(1);
         $resultUpdate->finish();
         return "";
      }
      $resultUpdate->execute();
      $resultUpdate->finish();

#      printf( "disabledSlot(%s, %d, %d, %s, %s, %s)\n", $ip, $port, $slot, $auth, $jsessionid, $sn ); 
      disableSlot( $ip, $port, $slot, $auth, $jsessionid, $sn );

      # -----------------------------------------------------
      # Verifico si hay algun slot disponible en el puerto
      # -----------------------------------------------------
      if( ( my $rc = QueryPortSlotEnabled( $gw, $port, $dbh, $jsessionid, $sn ) ) != -1 ) {

         $sql = sprintf( "select sql_no_cache slot, maximo_diarios, api_user, api_password, ip, gw, gateway_ports.port, count(gateway_ports.id) as total_ports, sum(enabled) as enabled_ports, sum(status) as total_status from gateway_ports left join planes on planes.id=gateway_ports.plan left join gateways on gateways.id=gateway_ports.gw where enabled=1 group by gw,port;" );
         my $resultSms = $dbh->prepare($sql);
         if ( $resultSms->err ) {
            db_Error( DEBUG, $resultSms->err, $resultSms->errstr );
            Time::HiRes::sleep(1);
            next;
         }
      
         if( $resultSms->execute() ) {
            while (my @row = $resultSms->fetchrow_array()) {

               my ($slot, $max_daily, $api_user, $api_password, $ip, $gw, $port, $total_ports, $enabled_ports, $total_status ) = @row;
               $auth = $api_user . ":" . $api_password;

               if( $total_ports > 0 && $enabled_ports > 0 && $total_status  == 0 ) {
   
                  my $sql = sprintf( "select sql_no_cache gateway, port, slot from port_statistics where gateway=%d and port=%d and enviados < %d and date(fecha)=date(now()) and enabled=1 and disabled_day=0 order by enviados limit 1;", $gw, $port, $max_daily );
                  my $resultEnable = $dbh->prepare($sql);
                  if ( $resultEnable->err ) {
                     db_Error( DEBUG, $resultEnable->err, $resultEnable->errstr );
                     Time::HiRes::sleep(1);
                     next;
                  }
               
                  if( $resultEnable->execute() ) {
                     if (my @rowEnable = $resultEnable->fetchrow_array()) {
                        my ($gw, $port, $slot ) = @rowEnable;
   
                        writeToLog( DEBUG, $logfile, sprintf("Try to enable GW %d, Port %d, Slot: %s", $gw, $port, $slot ), 0 );

                        $sql = sprintf( "update gateway_ports set status=1, status_check=1 where gw=%d and port=%d and slot ='%s';", $gw, $port, $slot );
                        $resultUpdate = $dbh->prepare($sql);
                        if ( $resultUpdate->err ) {
                           db_Error( DEBUG, $resultUpdate->err, $resultUpdate->errstr );
                           Time::HiRes::sleep(1);
                           $resultUpdate->finish();
                           return "";
                        }
                        $resultUpdate->execute();
                        $resultUpdate->finish();

                        $sql = sprintf( "update ports_statistics status=1 where gw=%d and port=%d and slot ='%s';", $gw, $port, $slot );
                        $resultUpdate = $dbh->prepare($sql);
                        if ( $resultUpdate->err ) {
                           db_Error( DEBUG, $resultUpdate->err, $resultUpdate->errstr );
                           Time::HiRes::sleep(1);
                           $resultUpdate->finish();
                           return "";
                        }
                        $resultUpdate->execute();
                        $resultUpdate->finish();
   
                        enableSlot( $ip, $port, $slot, $auth, $jsessionid, $sn );
                        PortChangeStatus( $dbh, $gw, $port );
                     }
                  }
                  $resultEnable->finish();
               }
            }
         }
         $resultSms->finish();
      }
   }


   # ----------------------------------------------------------------
   # Busco Slot disponible en el GW/Port y lo habilito
   #
   # returns: enabledSlot or -1 if no slot possible in port
   # ----------------------------------------------------------------

   sub QueryPortSlotEnabled {
      my $gw = $_[0];
      my $port = $_[1];
      my $dbh = $_[2];
      my $jsessionid = $_[3];
      my $sn = $_[4];
      my $enabledSlot = -1;
      my $selectable = 0;

      # ---------------------------------------------------------------------------
      # Busco los slots de este puerto que esten habilitados y con sms disponibles
      #
      # enabled     0 - No disponible    1 - Con Sms
      # status      0 - No esta en uso   1 - Esta en uso
      # registered  0 - No               1 - Registrado
      # ---------------------------------------------------------------------------
      writeToLog( DEBUG, $logfile, sprintf( "QueryPorLotEnabled: GW/Port (%s) %d: (jsessionid: %s)\n", $gw, $port, $jsessionid ), 0 );

#      my $sql = sprintf( "select sql_no_cache * from port_statistics where gateway=%d and port=%d slot='%s' and date(fecha)=date(now());", $planEnabled, $gw, $port, $slotEnabled );

      my $sql = sprintf( "select sql_no_cache slot, plan from gateway_ports where gw=%d and port=%d and enabled = 1;", $gw, $port );
#     printf( "%s\n", $sql );
      my $resultEnabled = $dbh->prepare($sql);
      if ( $resultEnabled->err ) {
         db_Error( DEBUG, $resultEnabled->err, $resultEnabled->errstr );
         Time::HiRes::sleep(1);
         next;
      }
      
      if( $resultEnabled->execute() ) {
         while (my @row = $resultEnabled->fetchrow_array()) {

            my ($slotEnabled, $planEnabled ) = @row;
            $selectable = 1;
      
            # ---------------------------------------------
            # Verifico que pueda utilizar este puerto/slot
            # ---------------------------------------------
            $sql = sprintf( "select sql_no_cache enviados, maximo_diarios, disabled_day from port_statistics inner join planes on planes.id=%d where gateway=%d and port=%d and slot='%s' and date(fecha)=date(now()) and disabled_day=0 order by enviados;", $planEnabled, $gw, $port, $slotEnabled );
            my $resultPossible = $dbh->prepare($sql);
            if ( $resultPossible->err ) {
               db_Error( DEBUG, $resultPossible->err, $resultPossible->errstr );
               Time::HiRes::sleep(1);
               next;
            }
      
            my ($enviadosPossible, $maximosPossible,$disabled_day );
            if( $resultPossible->execute() ) {
               if (my @rowPossible = $resultPossible->fetchrow_array()) {
                  ($enviadosPossible, $maximosPossible,$disabled_day ) = @rowPossible;
                  if( $enviadosPossible >= $maximosPossible || $disabled_day == 1 ) {
                     $selectable = 0;
                  }
               }
               $resultPossible->finish();
               if( $selectable ) {

                     if( !defined($jsessionid) ) {
                        last;
                     }

                     if( !defined($sn)) {
                        $sql = sprintf( "select sql_no_cache sn, from gateways where id=%d;", $gw );
                        my $resultGateways = $dbh->prepare($sql);
                        if ( $resultGateways->err ) {
                           db_Error( DEBUG, $resultPossible->err, $resultPossible->errstr );
                           $resultGateways->finish();
                           next;
                        }
                        if( $resultGateways->execute() ) {
                           if (my @rowGateways = $resultGateways->fetchrow_array()) {
                              ($sn) = @rowGateways;
                           }
                           else {
                              $resultGateways->finish();
                              next;
                           }
                        }
                        else {
                           $resultGateways->finish();
                           next;
                        }
                        $resultGateways->finish();
                     }

      
                     # ------------------------
                     # Enable gw, port, slot 
                     # ------------------------
#                    printf( "Habilito Puerto:Slot >>>> GW: Puerto: %d:%d, %s, %d -> %d\n", $gw, $port, $slotEnabled, $enviadosPossible, $maximosPossible );
                     writeToLog( DEBUG, $logfile, sprintf( "QueryPortSlotEnabled: Habilito Puerto:Slot >>>> GW: Puerto: %d:%d, %s, %d -> %d", $gw, $port, $slotEnabled, $enviadosPossible, $maximosPossible ), 0 ); 

                     $sql = sprintf( "update gateway_ports set status=1, status_check=1 where gw=%d and port=%d and slot='%s';", $gw, $port, $slotEnabled );
                     $resultPossible = $dbh->prepare($sql);
                     if ( $resultPossible->err ) {
                        db_Error( DEBUG, $resultPossible->err, $resultPossible->errstr );
                        $resultPossible->finish();
                        Time::HiRes::sleep(1);
                        next;
                     }
                     $resultPossible->execute();
                     $resultPossible->finish();

                     $sql = sprintf( "update port_statistics set status=1, disabled_day=0 where gateway=%d and port=%d and slot='%s';", $gw, $port, $slotEnabled );
                     $resultPossible = $dbh->prepare($sql);
                     if ( $resultPossible->err ) {
                        db_Error( DEBUG, $resultPossible->err, $resultPossible->errstr );
                        $resultPossible->finish();
                        Time::HiRes::sleep(1);
                        next;
                     }
                     $resultPossible->execute();
                     $resultPossible->finish();

                     enableSlot( $ip, $port, $slotEnabled, $auth, $jsessionid, $sn );
                     switch( $slotEnabled ) {
                        case 'A' {
                              disableSlot( $ip, $port, "B", $auth, $jsessionid, $sn );
                              disableSlot( $ip, $port, "C", $auth, $jsessionid, $sn );
                              disableSlot( $ip, $port, "D", $auth, $jsessionid, $sn );
                           }
      
                        case 'B' {
                              disableSlot( $ip, $port, "A", $auth, $jsessionid, $sn );
                              disableSlot( $ip, $port, "C", $auth, $jsessionid, $sn );
                              disableSlot( $ip, $port, "D", $auth, $jsessionid, $sn );
                           }
      
                        case 'C' {
                              disableSlot( $ip, $port, "A", $auth, $jsessionid, $sn );
                              disableSlot( $ip, $port, "B", $auth, $jsessionid, $sn );
                              disableSlot( $ip, $port, "D", $auth, $jsessionid, $sn );
                           }
      
                        case 'D' {
                              disableSlot( $ip, $port, "A", $auth, $jsessionid, $sn );
                              disableSlot( $ip, $port, "B", $auth, $jsessionid, $sn );
                              disableSlot( $ip, $port, "C", $auth, $jsessionid, $sn );
                           }
                     }
                     PortChangeStatus( $dbh, $gw, $port );
                     $enabledSlot = $slotEnabled;
                     last;
               }
            }
            $resultPossible->finish();
         }
      }
      $resultEnabled->finish();
      return( $enabledSlot );

   }



   # ----------------------------------------------------------------
   #
   # ----------------------------------------------------------------

   sub DisableAllSlots {
      my $gw = $_[0];
      my $port = $_[1];
      my $dbh = $_[2];
      my $jsessionid = $_[3];
      my $ip = $_[4];
      my $sn = $_[5];

      if( !defined($jsessionid) ) {
         return;
      }
      disableSlot( $ip, $port, "A", $auth, $jsessionid, $sn );
      disableSlot( $ip, $port, "B", $auth, $jsessionid, $sn );
      disableSlot( $ip, $port, "C", $auth, $jsessionid, $sn );
      disableSlot( $ip, $port, "D", $auth, $jsessionid, $sn );
#     PortChangeStatus( $dbh, $gw, $port );
      return;
   }
=cut

