#!/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;
use threads;
use Thread::Semaphore;
use threads::shared;
use POSIX qw(strftime);
use Net::Ping;
use Dinstar;

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

use constant {
    DINSTAR => 0,
    SYNWAY => 2
};

use constant {
    GSM7BIT => 0,
    UTF8 => 1
};



# ----------------------------------------
# Need to Install Config-Tiny Perl Module
# ----------------------------------------
my $app_folder = getcwd;
#chdir "/var/www/html/PortalSMS";
#my $filename = "./SmsInterface.ini";
chdir $app_folder;
my $filename = sprintf("%s/SmsInterface.ini", $app_folder );

my $config = Config::Tiny->read( $filename, 'utf8' );
my $daemon = 0;
my $dbh;
#my $logfile = "./SmsInterface.log";
my $logfile = sprintf("%s/SmsInterface.log", $app_folder );
my $threadCount = 10;
my $site = 1;
my $stop_at = -1;
my $last_line = 0;

# --------------------------------
# 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 $semaphoreCount:shared = 0;
my $coding = 0;
my $app_ended = 0;

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

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

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

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

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

$SIG{INT} = sub { 
   $forever = 0;
   AppEnd();
   print(" pressed, terminating process. Please wait...\n\n");
   exit;
};

$SIG{TERM} = sub {
   $forever = 0;
   AppEnd();
   print("Terminating process. Please wait...\n\n");
   exit;
};

sub AppEnd {
   $forever = 0;
   while( $globalThreadCount > 0 ) {
      Time::HiRes::sleep(1);
   }
#  writeToLog( $logfile, "", 1 );
   writeToLog( $logfile, sprintf( "Terminated 'SmsInterface' daemon PID: %d", getpid() ) ,0 );
   writeToLog( $logfile, "", 1 );
   my $filename = sprintf("%s/SmsInterface.pid", $app_folder );
   unlink($filename);

#   if( $dbh ) {
#      $dbh->disconnect();
#   }   
}

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

# --------------------------------
# MariaDB
# --------------------------------
my $driver = "mysql"; 
my $database = "PortalSMS";
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 $errorCount = 300;
my $debug = 0;
my $dialerName = "";
my $error = "";
my $my_address = "10.0.66.119";
my $autotest_timer = 0;
my $portability = 0;


# --------------------------------
# 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} eq "Yes" ) {
   $debug = 1;
}

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

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

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

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

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

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

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

writeToLog( $logfile, sprintf( "Database: %s", $database ) );
writeToLog( $logfile, sprintf( "Datatable: %s", $datatable ) );
writeToLog( $logfile, sprintf( "Max Threads: %d", $threadCount ) );

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

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

for( $i= 0; $i < $threadCount; $i++ ) {
   $Used[$i] = 0;
}
writeToLog( $logfile, "", 1 );
$last_line = 1;
my $display = 0;
my $countTest = 9;

$app_ended = 0;

while( $forever ) {

#  printf( "%d\n", $stop_at );
   if( $stop_at != -1 && --$stop_at <= 0 ) {
      $forever = 0;
   }

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

   my $message_id = 0;
   my $sql = "";
   my $idPort;
   my $descripcion;
   my $max_daily;
   my $por_hora;
   my $active;
   my $fecha;
   my $ip;
   my $port;
   my $gw;
   my $slot;
   my $auth_user;
   my $auth_pswd;
   my $tipo_gw;
   my $type;                     # type = 1 SMPP
   my $uid;
   my $plan;
   my $user_id;
   my $customer_id;
   my $noPorts = 0;
   my $sqlHandle;
   my $last_test = "";
   my $time_to_test_sim = 0;
   my $ani = "";
   my $OPERADOR = 0;

#  printf( "Semaphore Count: %d\n", $semaphoreCount );

   use constant {
      PENDING  => 1,
      RESEND  => 102,
      PROCESSING => 103,
      NO_PORTS => 550,
   };

   use constant {
      ACCEPTED => 202,                 # 202    Mensaje aceptado y sera procesado
      INVALID_FORMAT => 400,           # 400    Formato de envio no valido
      INVALID_PHONE_FORMAT => 413,     # 413    Formato de numeros de telefono > 128 bytes de largo
      OTHER_ERRORS => 500,             # 500    Otros Errores
      NO_PORTS_AVAILABLE => 550,       # 550    Sin puertos disponibles para envio
   };      

   # -------------------------------
   # Hay mensajes para enviar?
   #
   # pending = 1      PENDIENTE
   # pending = 102    RESEND
   # pending = 103    EN PROCESO
   # pending = 550    NO PORTS
   # -------------------------------
   $semaphore->down();
   ++$semaphoreCount;
   $sql = sprintf( "select id, received, sender_id, recipient, message, customer_id, type, customer_id, uid, operador from %s where pending=1 or pending=550 or pending=102 order by received limit 1;", $datatable );
   printf( "%s\n", $sql );
   $sth = $dbh->prepare($sql);
   if ( $sth->err ) {
      $semaphore->up();
      --$semaphoreCount;
      writeToLog( $logfile, sprintf( "DBI prepare Error: Count: $errorCount => $sth->err : $sth->errstr" ), 0 );
      Time::HiRes::sleep(10);
      next;
   }
   my $foundSms = 0;
   my $foundThread = 0;

   if( $sth->execute() ) {

      if( $sth->rows() <= 0 ) {
         $sth->finish();
         $semaphore->up();
         --$semaphoreCount;
         Time::HiRes::sleep(1);
         next;
      }

      if( $sth->rows() > 0 ) {
         while (my @row = $sth->fetchrow_array()) {

            my ($id, $received_date, $sender_id, $recipient, $message, $outbound_customer_id, $type_connection, $outbound_user_id, $smpp_uid, $code_operador ) = @row;
            $foundSms = 1;
            $user_id = $id;
            $customer_id = $outbound_customer_id;
            $type = $type_connection;
            $uid = $smpp_uid;
            $OPERADOR = int($code_operador);
   
            my $message_text = URI->new($message);
            my $message_text = $message;
            my $auth = "";
   
            # ---------------------
            # Verifico Numeracion
            # ---------------------
=begin            
            if( $portability ) {
               $code_operador = Portabilidad( $dbh, $recipient );
               $sql = sprintf( "select gateway_ports.id as id_port, descripcion, maximo_diarios, mensajes_por_hora, fecha_ultimo, ip, gateway_ports.port as gwport,gw,slot,api_user,api_password,planes.id as plan_id, tipo_gw, ( case when DATE_ADD(last_auto_test, INTERVAL %d MINUTE) < now() then 1 else 0 end ), ani from gateway_ports left join planes on planes.id=gateway_ports.plan left join gateways on gateways.id=gateway_ports.gw where gateways.active=1 and now() > date_add( fecha_ultimo, interval 3600/mensajes_por_hora second ) and gateway_ports.status=1 and registered=1 and planes.code_operator='%s' and in_use=0 order by fecha_ultimo;", $autotest_timer, $code_operador );
               $sqlHandle = $dbh->prepare($sql);
               if( !$sqlHandle->err ) {
                  if( $sqlHandle->execute() ) {
                     if( $sqlHandle->rows() == 0 ) {
                        $sql = sprintf( "select gateway_ports.id as id_port, descripcion, maximo_diarios, mensajes_por_hora, fecha_ultimo, ip, gateway_ports.port as gwport,gw,slot,api_user,api_password,planes.id as plan_id, tipo_gw, ( case when DATE_ADD(last_auto_test, INTERVAL %d MINUTE) < now() then 1 else 0 end ), ani from gateway_ports left join planes on planes.id=gateway_ports.plan left join gateways on gateways.id=gateway_ports.gw where gateways.active=1 and now() > date_add( fecha_ultimo, interval 3600/mensajes_por_hora second ) and gateway_ports.status=1 and registered=1 and in_use=0 order by fecha_ultimo;", $autotest_timer );
                     }   
                  }
               }
               if( defined($sqlHandle ) ) {
                  $sqlHandle->finish();
               }   
            }
            else {
               $sql = sprintf( "select gateway_ports.id as id_port, descripcion, maximo_diarios, mensajes_por_hora, fecha_ultimo, ip, gateway_ports.port as gwport,gw,slot,api_user,api_password,planes.id as plan_id, tipo_gw, ( case when DATE_ADD(last_auto_test, INTERVAL %d MINUTE) < now() then 1 else 0 end ), ani from gateway_ports left join planes on planes.id=gateway_ports.plan left join gateways on gateways.id=gateway_ports.gw where gateways.active=1 and now() > date_add( fecha_ultimo, interval 3600/mensajes_por_hora second ) and gateway_ports.status=1 and registered=1 and in_use=0 order by fecha_ultimo;", $autotest_timer );
            }
#            printf( "$sql\n" );
=cut
   
            # -----------------------------------
            # Hay puertos activos disponibles?
            # -----------------------------------
            my $testFlag = 0;
            my $found = 0;
#            $sql = sprintf( "select gateway_ports.id as id_port, descripcion, maximo_diarios, mensajes_por_hora, fecha_ultimo, ip, gateway_ports.port as gwport,gw,slot,api_user,api_password,planes.id as plan_id, tipo_gw, ( case when DATE_ADD(last_auto_test, INTERVAL %d MINUTE) < now() then 1 else 0 end ), ani from gateway_ports left join planes on planes.id=gateway_ports.plan left join gateways on gateways.id=gateway_ports.gw where gateways.active=1 and now() > date_add( fecha_ultimo, interval 3600/mensajes_por_hora second ) and gateway_ports.status=1 and registered=1 and planes.code_operator='%s' and in_use=0 order by fecha_ultimo;", $autotest_timer, $code_operador );
            $sql = sprintf( "select
                        gateway_ports.id as id_port,
                        gateway_ports.id as id_port,    gateway_ports.descripcion,
                        gateway_ports.maximo_diarios,
                        gateway_ports.mensajes_por_hora,
                        gateway_ports.fecha_ultimo,
                        gateway_ports.ip,
                        gateway_ports.port as gwport,
                        gateway_ports.gw,
                        gateway_ports.slot,
                        gateway_ports.api_user,
                        gateway_ports.api_password,
                        planes.id as plan_id,
                        gateway_ports.tipo_gw,
                        case
                            when date_add(gateway_ports.last_auto_test, interval %d minute) < now()
                            then 1
                            else 0
                        end as test_vencido,
                        gateway_ports.ani
                     from gateway_ports
                        inner join planes   on planes.id = gateway_ports.plan
                        inner join gateways on gateways.id = gateway_ports.gw
                     where gateways.active = 1
                        and gateway_ports.mensajes_por_hora > 0
                        and now() > date_add(gateway_ports.fecha_ultimo, interval 3600 / gateway_ports.mensajes_por_hora second)
                        and gateway_ports.status = 1
                        and gateway_ports.registered = 1
                        and planes.code_operator = %d
                        and gateway_ports.in_use = 0
                     order by gateway_ports.fecha_ultimo;", $autotest_timer, $code_operador );

      printf( "%s\n", $sql );
            $sqlHandle = $dbh->prepare($sql);
            if ( $sqlHandle->err ) {
               writeToLog( $logfile, sprintf( "DBI prepare Error: $sqlHandle->err : $sqlHandle->errstr" ), 0 );
               Time::HiRes::sleep(2);
               $semaphore->up();
               --$semaphoreCount;
               next;
            }
   
            if( $sqlHandle->execute() ) {
               while (my @portRow = $sqlHandle->fetchrow_array()) {
   
                  ($idPort, $descripcion, $max_daily, $por_hora, $fecha, $ip, $port, $gw, $slot, $auth_user, $auth_pswd, $plan, $tipo_gw, $time_to_test_sim, $ani ) = @portRow;
                  $auth = $auth_user . ":" . $auth_pswd;
   
                  switch( $slot ) {
                     case "A"  { $slot = "0" }
                     case "B"  { $slot = "1" }   
                     case "C"  { $slot = "2" } 
                     case "D"  { $slot = "3" } 
                  }
   
                  # -------------------------------------
                  # Verifico que gateway este accesible 
                  # -------------------------------------
                  if( PingTest( $ip, $my_address ) == 0 ) {
                     writeToLog( WARNING, $logfile, "GATEWAY $gw IS NOT AVAILABLE", 0 );
                     writeToLog( WARNING, $logfile, "", 1 );
                     if( defined($sqlHandle ) ) {
                        $sqlHandle->finish();
                     }   
                     sleep(5); 
                     next;
                  }
   
                  # -------------------------
                  # Mensaje vino por SMPP?
                  # -------------------------
                  if( $type == 1 ) {
                     $sql = sprintf( "select id from customers where smpp_uid='%s';", $uid );
                     my $sqlUser = $dbh->prepare($sql);
                     if ( !$sqlUser->err ) {
                        if( $sqlUser->execute() ) {
                           if(my @userRow = $sqlUser->fetchrow_array()) {
                              ($customer_id) = @userRow;
                           }
                        }
                     }
                     if( defined($sqlUser ) ) {
                        $sqlUser->finish();
                     }
                  }
   
                  # -----------
                  # TESTING
                  # -----------
=begin                  
                  my $testing = 0;
                  if( ($autotest_timer > 0 && $time_to_test_sim == 1) || $testing == 1 ) {
   
                     if( $testing != 1 ) {
                        if( $ani ne "" ) {
                           $recipient = $ani;
                        }
                        else {
                           # ------------------------------------
                           # Busco puerto activado para testear
                           # ------------------------------------
                           $sql = sprintf( "select ani from gateway_ports where enabled=1 and status=1 and registered=1 order by last_auto_test;", $autotest_timer );
                            my $ack = $dbh->prepare($sql);
   
                           $recipient = "1144255139";
                           if ( !$ack->err ) {
                              if( $ack->execute() ) {
                                 if(my @ackRow = $ack->fetchrow_array()) {
                                    ($recipient) = @ackRow;
                                 }
                              }
                           }
                           if( defined($ack ) ) {
                              $ack->finish();
                           }
      
                           $recipient = "1144255139";
                        }
                        my $slotStr = convertSlot( $slot );
                        $message = sprintf( "Autotest %2d%2d%s", $gw, $port, $slotStr );
                        writeToLog( $logfile, "",1 );
                        writeToLog( $logfile, sprintf( "Test SIM: %d, %d%s", $gw, $port, $slotStr ), 0 );
                        writeToLog( $logfile, "", 1 );
                        $testFlag = 1;
                     }
                     else {
                        if( $countTest >= 9 ) {
                           $active = 1;
                           $ip = "10.0.66.104";
                           $port = 1;
                           $gw = 1;
                           $slot = 3;
                           $auth = "admin:pepito20";
                           $found = 0;
                           $plan = 1;     # Movi
                           $user_id = 0;
                           $descripcion = "Dinstar-1 Claro 1D";
                           $message = "Test: " . $message_text;
                           $tipo_gw = 0;

                           if( $countTest == 9 ) {
                             $recipient = "541154080199";
                              writeToLog( $logfile, "",1 );
                              writeToLog( $logfile, "Test to CARLOS", 0 );
                           }
                           if( $countTest == 10 ) {
                              $recipient = "541144255139";
                              writeToLog( $logfile, "",1 );
                              writeToLog( $logfile, "Test to AG", 0 );
                           }
                           $testFlag = 1;
                           writeToLog( $logfile, "",1 );
                        }
                        if( ++$countTest > 10 ) {
                           $countTest = 0;
                        }
                     }
                  }
=cut                  
                  # --------------
                  # TESTING END
                  # --------------

                  # ---------------------------------------------
                  # Tengo estadisticas del puerto/slot activo?
                  # ---------------------------------------------
                  my $slotStr = convertSlot( $slot );
                  $sql = sprintf( "select enviados, disabled_day from port_statistics where gateway=%d and port=%s and slot='%s' and date(fecha)=date(now());", $gw, $port, $slotStr );
                  my $sqlPort = $dbh->prepare($sql);
                  if ( $sqlPort->err ) {
                     Time::HiRes::sleep(2);
                     $semaphore->up();
                     --$semaphoreCount;
                     next;
                  }
                  if( $sqlPort->execute() ) {
                     if( $sqlPort->rows() > 0 ) {
   
                        # -----------------------------------------------
                        # Tengo mensajes diarios o por dia para enviar?
                        # -----------------------------------------------
                        if (my @statistics = $sqlPort->fetchrow_array()) {
                           my ($enviados, $disabled_day ) = @statistics;
   
                           if( $enviados < $max_daily and $disabled_day == 0 ) {
                              $found = 1;
                              $semaphore->up();
                              --$semaphoreCount;
                              last;
                           }
                        }
                     }                                                                                                                                                              
                     else {
   
                        # ---------------------------------------
                        # Cargo nuevo registro de estadisticas
                        # ---------------------------------------
                        $sqlPort->finish();
                        my $slotStr = convertSlot( $slot );
                        $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 ), $slotStr, int($plan) );
                        $sqlPort = $dbh->prepare($sql);
                        if ( $sqlPort->err ) {
                           Time::HiRes::sleep(2);
                           $semaphore->up();
                           --$semaphoreCount;
                           next;
                        }
                        if( $sqlPort->execute() ) {
                           $found = 1;
                           last;
                        }
                     }
                  }
                  $sqlPort->finish();
               }
   

               # --------------------------------------------------
               # Hay mensajes y puertos disponibles envio mensaje
               # --------------------------------------------------
               if( $found ) {
   
                  $semaphore->down();
                  ++$semaphoreCount;
                  $foundThread = 0;
                  for( $i = 0; $i < $threadCount; $i++ ) {
                     if( $Used[$i] == 0 ) {
                        $Used[$i] = 1;
                        $foundThread = 1;
                        last;
                     }
                  }
   
                  # -----------------------------
                  # Actualizo Thread en Uso
                  # -----------------------------
                  UsedThreads();
   
                  # ------------------------------
                  # Bloqueo Puerto como en USO
                  # ------------------------------
                  my $slotStr = convertSlot( $slot );
   
                  if( $foundThread == 1 ) {
   
                     if( $time_to_test_sim == 1 ) {
                        $sql = sprintf( "update gateway_ports set in_use=1, last_auto_test=now() where gw=%d and port=%s and slot='%s';", $gw, $port, $slotStr );
                     }
                     else {
                        $sql = sprintf( "update gateway_ports set in_use=1 where gw=%d and port=%s and slot='%s';", $gw, $port, $slotStr );
                     }                     
                     my $sqlStat = $dbh->prepare($sql);
                     if ( $sqlStat->err ) {
                        $semaphore->up();
                        --$semaphoreCount;
                        next;
                     }
                     $sqlStat->execute();
                     $sqlStat->finish();
                     $semaphore->up();
                     --$semaphoreCount;
                  
   
                     my $short_message = $message;
                     if( length( $message ) > 30 ) {
                        $short_message = substr( $message, 0, 30 );
                     }
                     my $str = sprintf( "%s, %s, %s, %s%s, %s, %s", $descripcion, $ip, $recipient, $port, $slotStr, $user_id, $short_message ); 
                     writeToLog( $logfile, $str, 0 ); 
                  
                     my $sqlt = sprintf( "update config set used_threads=%d where id=%d", $globalThreadCount +1, $site );
                     my $stdt = $dbh->prepare($sqlt);
                     if ( !$stdt->err ) {
                        $stdt->execute();
                        $stdt->finish();
                     }             
   
                     if( $code_operador ne "" ) {
                        writeToLog( $logfile, "", 1 );
                        writeToLog( $logfile, sprintf( "OPERADOR: %s", $code_operador ), 0 );
                        writeToLog( $logfile, "", 1 );
                     }
                  
                     # ---------------
                     # Ejecuto thread 
                     # ---------------
                     $display = 1;
                     $thr[$i] = threads->create(\&sendSmsThread, $ip, $recipient, $message, $port, $auth, $user_id, $i, $testFlag, $id, $gw, $slot, $customer_id, $idPort, $tipo_gw, $datatable );
                  }
                  else {
                     # ------------------------------
                     # Desboqueo Puerto como en USO
                     # ------------------------------
                     $semaphore->down();
                     ++$semaphoreCount;
   
                     my $slotStr = convertSlot( $slot );
                     $sql = sprintf( "update gateway_ports set in_use=0 where gw=%d and port=%s and slot='%s';", $gw, $port, $slotStr );
                     my $sqlStat = $dbh->prepare($sql);
                     if ( $sqlStat->err ) {
                        $semaphore->up();
                        --$semaphoreCount;
   
                        last;
                     }
                     $sqlStat->execute();
                     $sqlStat->finish();
                     $semaphore->up();
                     --$semaphoreCount;
                  }
                  $noPorts = 0;
               }  
               else {
                  $semaphore->up(); 
                  --$semaphoreCount;
                  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
   
                  if( $display == 1 ) {
                     writeToLog( $logfile, "",1 );
                     writeToLog( $logfile, sprintf( "SIN PUERTOS DISPONIBLES (ESPERANDO)"  ), 0 );
                     writeToLog( $logfile, "",1 );
                     $display = 0;
                  }
                  $noPorts = 1;
   
                  Time::HiRes::sleep(3);
                  $sql = sprintf( "select * from config where id=%d and stop=1;", $site );
                  my $result = $dbh->prepare($sql);
                  if ( $result->err ) {
                     writeToLog( $logfile, sprintf( "DBI prepare Error: $result->err : $result->errstr" ), 0 );
                     Time::HiRes::sleep(2);
                     next;
                  }
                  $result->execute();
                  my $rows = $result->rows;
                  if( $rows > 0 ) {
                     $forever = 0;
                     $result->finish();
                     last;
                  }
                  $result->finish();
               }
            }
            else {
               $semaphore->up(); 
               --$semaphoreCount;
   
            }            

            while( $globalThreadCount >= $threadCount ) {
               printf( "waiting...\n" );
               Time::HiRes::sleep(1);
            }
         }           # while
      }
      if( defined($sqlHandle ) ) {
         $sqlHandle->finish();
      }         
#     Time::HiRes::sleep(2);
   }
   else {
      $semaphore->up();
      --$semaphoreCount;
   }
   $sth->finish();         # Mensaje a enviar
}  
$app_ended = 1;
writeToLog( $logfile, sprintf( "End 'SmsInterface' daemon PID: %d", getpid() ),0 );
    

print ( "-------------------------------------------------------------------------------------------------------------------------------------------------------------------\n" );
$dbh->disconnect();

   # ------------------------------------
   # sendSms - THREAD
   # ------------------------------------

   sub sendSmsThread
   {
      my $LocalCopy;
      my $dbh;
      my $ip = $_[0];
      my $recipient = $_[1];
      my $message = $_[2];
      my $port = $_[3];
      my $auth = $_[4];
      my $user_id = $_[5];
      my $index = $_[6];
      my $testFlag = $_[7];
      my $id = $_[8];
      my $gw = $_[9];
      my $slot = $_[10];
      my $customer_id = $_[11];
      my $idPort = $_[12];
      my $tipo_gw = $_[13];
      my $datatable = $_[14];

      threads->detach();

      $semaphore->down();
      ++$semaphoreCount;

      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; 

      # -------------------------
      # Marco como en proceso
      # -------------------------
      my $sql = sprintf( "update %s set pending=%d, customer_id=%d where id=%d", $datatable, PENDING, $customer_id, $user_id );
      if( $testFlag == 0 ) {
         my $stdx = $dbh->prepare($sql);
         if ( !$stdx->err ) {
            $stdx->execute();
         }             
         $stdx->finish();
      }
      else {
         $user_id = 1;
      }
      $semaphore->up();

#     printf( "%s, %s, %s, %d\n", $ip, $recipient, $message, $port );
#     my $sendCode = sendSms( $ip, $recipient, $message, $port, $auth, $user_id, $tipo_gw, $coding );
      my $sendCode = gw_SendSms( $ip, $recipient, $message, $port, $auth, $user_id, $tipo_gw, $coding );
      my $errCode = $sendCode->{error_code};
      my $resultUpdate;

      # -------------------------------------------------------------
      # 202    Mensaje aceptado y sera procesado
      # 400    Formato de envio no valido
      # 413    Formato de numeros de telefono > 128 bytes de largo
      # 500    Otros Errores
      # 550    Sin puertos disponibles para envio
      # -------------------------------------------------------------
      if( $errCode == ACCEPTED ) {

         $semaphore->down();
#        my $smsInQueue = $sendCode->{sms_in_queue};

         if( $testFlag == 0 ) {
            $sql = sprintf( "update %s set pending=%d, gw=%d, port=%d, slot='%s', forwarded=now() where id=%d;", $datatable, $errCode, $gw, $port, $slot, $user_id );
            $resultUpdate = $dbh->prepare($sql);
            if ( !$resultUpdate->err ) {
               $resultUpdate->execute();
            }
            $resultUpdate->finish();
         }

         my $slotStr = convertSlot( $slot );
         $sql = sprintf( "update port_statistics set enviados=enviados+1 where gateway=%d and port=%s and slot='%s' and date(fecha)=date(now());", $gw, $port, $slotStr );
         my $sqlStat = $dbh->prepare($sql);
         if ( !$sqlStat->err ) {
            $sqlStat->execute();
         }
         $sqlStat->finish();

         $sql = sprintf( "update gateway_ports set in_use=0 where gw=%d and port=%s and slot='%s';", $gw, $port, $slotStr );
         my $sqlStat = $dbh->prepare($sql);
         $sqlStat->execute();
         $sqlStat->finish();
            
         # ------------------------
         # Actualizo Estadisticas
         # ------------------------
         $sql = sprintf( "update statistics set sended_count=sended_count+1 where actual_date=date(now());" );
         $resultUpdate = $dbh->prepare($sql);
         if ( !$resultUpdate->err ) {
            $resultUpdate->execute();
         }
         $resultUpdate->finish();
 
         # --------------------
         # Actualizo Customer
         # --------------------
         if( $testFlag == 0 ) {
            $sql = sprintf( "update customers set credit_limit=credit_limit-1 where id=%d;", $customer_id );
            $resultUpdate = $dbh->prepare($sql);
            if ( !$resultUpdate->err ) {
               $resultUpdate->execute();
            }
            $resultUpdate->finish();
         }
         else {
            $sql = sprintf( "insert into `autotest` (`id`,`fecha`,`gw`,`port`,`slot`,`destination`) VALUES (0,now(),%d,%d,'%s','%s');", int($gw), int( $port ), $slotStr, $recipient );
            $resultUpdate = $dbh->prepare($sql);
            if ( !$resultUpdate->err ) {
               $resultUpdate->execute();
            }
            $resultUpdate->finish();
         }
         $semaphore->up();
      }
      else {
         if( $testFlag == 0 ) {
            $semaphore->down();

            # --------------------------
            # Error del Dinstar-Synway
            # --------------------------
            $sql = sprintf( "update %s set pending=%d, port=%d, slot='%s', forwarded=now()  where id=%d;", $datatable, $errCode, $port, $slot, $user_id );
            $resultUpdate = $dbh->prepare($sql);
            if ( !$resultUpdate->err ) {
               $resultUpdate->execute();
            }
            $resultUpdate->finish();
            $semaphore->up();
         }
      }

      $semaphore->down();
      $sql = sprintf( "update gateway_ports set fecha_ultimo=now(), in_use=0 where id=%d;", $idPort );
      my $sqlStat = $dbh->prepare($sql);
      if ( $sqlStat->err ) {
         writeToLog( $logfile, sprintf( "DBI prepare Error: $sqlStat->err : $sqlStat->errstr" ), 0 );
         Time::HiRes::sleep(2);
         next;
      }
      $sqlStat->execute();
      $sqlStat->finish();
      
      $LocalCopy = $globalThreadCount; 
      $LocalCopy--;
      $globalThreadCount = $LocalCopy; 
      $Used[$index] = 0;
      $dbh->disconnect();
      $semaphore->up();
      threads->exit();
   }   

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

   sub writeToLog 
   {  
      my $filename = $_[0];
      my $text = $_[1];
      my $mode = $_[2];
   
      if( open(FH, '>>', $filename) ) {
         if( $mode == 1 ) {
            if( $last_line == 1 ) {
               close(FH);
               return;
            }
            $text = "+--------------------------------------------------------------------------------------------------+";
            $last_line = 1;
         }
         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);
         if( $mode == 0 ) {
            $last_line = 0;
         }
      }      
   }


   # ---------------------------
   # 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( $logfile, sprintf( "Threads %d: (%s)", $globalThreadCount +1, $str ), 0 );
#      writeToLog( $logfile, "", 1 );
   }


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

   sub PingTest {
#     my $my_addr = "10.0.66.119";
      my $host = $_[0];
      my $my_addr = $_[1];
      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;
   }


   # ----------------------------
   # Busco Operador s/el numero
   # ----------------------------

   sub Portabilidad {
      my $dbh = $_[0];
      my $number = $_[1];

      my $sql = sprintf( "select Operador, Servicio, Modalidad, Localidad, Indicativo, Bloque, CODE_OPERADOR from numeracion where concat(indicativo,bloque) =  left('%s',length(concat(indicativo,bloque)));", $number );
      my $result = $dbh->prepare($sql);
      if ( !$result->err ) {
         if( $result->execute() ) {
            if( $result->rows() > 0 ) {
               if (my @portabilidadRow = $result->fetchrow_array()) {
                  my ($operador, $servicio, $modalidad, $localidad, $indicativo, $bloque, $code ) = @portabilidadRow;
                  $result->finish();
                  return( $code );
               }
            }
         }
      }
      $result->finish();
      return( "" );
   }

=begin
   /////////////////////////////////////////////////////////////////////
   // sql_TestDirectMS - Verifico si tengo mensajes
   /////////////////////////////////////////////////////////////////////

   int sql_FindModalidad( AG_CONTEXT *cx, char *Numero, NUMERACION *Numeracion )
{
   int      rc;
   int      error = 0;
   char     *query;
   RED24_DATA *RED24 = cUSERDATA( cx );
   MYSQL **db;
   
   if( cx == NULL || RED24 == NULL ) return FALSE;
   memset( Numeracion, 0, sizeof( NUMERACION ) );
   db  = &RED24->db;
   query = RED24->query;
   if( db_check_connected( cx, db, &RED24->connected ) ) {
      sprintf( query, "select Operador, Servicio, Modalidad, Localidad, Indicativo, Bloque from numeracion where concat(indicativo,bloque) =  left('%s',length(concat(indicativo,bloque)))", Numero );
      if( ( rc = mysql_query( *db, query ) ) == 0 )  {
         MYSQL_RES   *res;
         MYSQL_ROW   row;
         unsigned    long *lengths;

         if( ( res = mysql_store_result( *db ) ) != NULL ) {
            if( ( row = mysql_fetch_row( res ) ) ) {
               lengths = mysql_fetch_lengths( res ); 

               dbdata( res, row, lengths, 1, Numeracion->Operador );  
               dbdata( res, row, lengths, 2, Numeracion->Servicio );  
               dbdata( res, row, lengths, 3, Numeracion->Modalidad );  
               dbdata( res, row, lengths, 4, Numeracion->Localidad );  
               dbdata( res, row, lengths, 5, Numeracion->Indicativo );  
               dbdata( res, row, lengths, 6, Numeracion->Bloque );  
            }             
            mysql_free_result( res );
         }            
      }
   }      
   return( error );
}
=cut


