#!/usr/bin/perl
# Copyright 2008 House Internet S.R.L.
# This program is not redistributable.
# http://www.asternic.org
# Contact Nicolas Gudino for more information <nicolas@house.com.ar>
use FindBin;
use lib $FindBin::Bin;
use POSIX;
use DBI;
use Time::Local;
use Getopt::Long qw(:config no_ignore_case);
use Tail;
use Data::Dumper;

my %config;
my %event_hash = ();
my %queuecache;
my %agentcache;
my %didhash;
my %urlhash;
my $dbh;
my $conectado     = 0;
my $last_event_ts = 0;
my $daemon        = 0;
my $triggerscript = '';
my $skip          = 0;
my $convertlocal  = 0;
my $reparse       = 0;
my $destructivereparse = 0;
my $offset_seconds = 10;
my %nombreagente;
my $pidfile = "/var/run/asterniclog.pid";
my $logdir        = '';
my $purge;
my $repair;
my $skiprepair = 0;
my @plugins;
my $pluginstring = '';
my $directorio   = $FindBin::Bin;
my @queuelog_transform;

$SIG{ALRM} = 'reconecta';
$SIG{INT} =  'close';
$SIG{TERM} = 'close';

sub close
{
    if ( -f $pidfile ) {
        unlink $pidfile;
    }

    print "Exiting...\n";

    exit(0);
}

sub END {

    open my $fh, "<", $pidfile or exit;
    my $storedpid = <$fh>;
    close $fh;

    if($storedpid == $$) {
        if(!$daemon) {
            if(-f $pidfile) {
                unlink $pidfile;
            }
            print "Exiting...!\n";
        }
    }
}

sub daemonize
{

    if ( $logdir ne "" ) {
        open( STDOUT, q{>>}, "$logdir/asterniclog.log" ) or die "Can't open output log $logdir/asterniclog.log";
        open( STDERR, q{>>}, "$logdir/asterniclog.log" ) or die "Can't open output log $logdir/asterniclog.log";
    } 

    defined( my $pid = fork ) or die "Can't Fork: $!";
    exit if $pid;
    setsid or die "Can't start a new session: $!";
    open my $mypidfile, q{>}, $pidfile or die "Failed to open PID file $pidfile for writing.";
    print $mypidfile $$;
    close $mypidfile;

    if ($logdir eq "") {
        close STDOUT;
        close STDERR;
    }
    close STDIN;
}

GetOptions(
    "u|user=s"       => \$config{'dbuser'},
    "p|password=s"   => \$config{'dbpass'},
    "h|host=s"       => \$config{'dbhost'},
    "d|dbname=s"     => \$config{'dbname'},
    "l|logfile=s"    => \$config{'logfile'},
    "c|convertlocal" => \$convertlocal,
    "r|reparse"      => \$reparse,
    "z|destructivereparse"      => \$destructivereparse,
    "g|logdir=s"     => \$logdir,
    "o|offset=s"     => \$offset_seconds,
    "s|skip"         => \$skip,
    "nr|norepair"    => \$skiprepair,
    "pl|plugins=s"   => \$pluginstring,
    "daemon"         => \$daemon,
    "P|pidfile=s"    => \$pidfile,
    "help|?"         => \$help,
    "purge"          => \$purge,
    "repair"         => \$repair,
    "t|trigger=s"    => \$triggerscript,
    "w|write"        => \$write
);

usage() if $help;

load_config('/etc/asterniclog.conf');
load_config("$ENV{HOME}/.asterniclog") if defined $ENV{HOME};

if($reparse || $destructivereparse) {
    # Do not daemonize if we need to reparse queue_log
    $daemon=0;
}

$config{'dbname'}  = $config{'dbname'}  ? $config{'dbname'}  : "qstats";
$config{'dbhost'}  = $config{'dbhost'}  ? $config{'dbhost'}  : "localhost";
$config{'dbpass'}  = $config{'dbpass'}  ? $config{'dbpass'}  : "";
$config{'dbuser'}  = $config{'dbuser'}  ? $config{'dbuser'}  : "root";
$config{'logfile'} = $config{'logfile'} ? $config{'logfile'} : "/var/log/asterisk/queue_log";

@plugins = split(/,/,$pluginstring);

foreach my $file (@plugins) {
    if(-f "$directorio/plugins/$file") {
        loadPluginFile("$directorio/plugins/$file");
    } else {
        print "$directorio/plugins/$file does not exists\n";
    }
}

if ( $purge && defined( $config{'dbuser'} ) ) {
    print "Purge all data from tables.\n";
    print "Are you sure? (yes|no)\n";
    $answer = lc(<>);
    chop($answer);
    if ( $answer eq "y" || $answer eq "yes" ) {
        &purgedb();
    }
    exit;
}

if ( $repair && defined ($config{'dbuser'} ) ) {
    &repairdb();
    exit;
}

if ( !-f $config{'logfile'} ) {
    print "File " . $config{'logfile'} . " not found\n";
    exit 1;
}

if ($write) {
    if ( -d $ENV{HOME} ) {
        open DEFAULT, ">$ENV{HOME}/.asterniclog";
        print DEFAULT "dbuser=$config{'dbuser'}\n"   if $config{'dbuser'};
        print DEFAULT "dbpass=$config{'dbpass'}\n"   if $config{'dbpass'};
        print DEFAULT "dbhost=$config{'dbhost'}\n"   if $config{'dbhost'};
        print DEFAULT "logfile=$config{'logfile'}\n" if $config{'logfile'};
        close DEFAULT;
    }
}

sub loadPluginFile {
    my $file     = shift;

    my $document = do {
        local $/ = undef;
        open my $fh, "<", $file
          or die "could not open $file: $!";
        <$fh>;
    };

    print "Load plugin $file\n";

    eval $document or warn "$@ in $name";
    warn "$@ in $name" if $@;
}

sub repairdb() {
    print "Purging data\n";
    my $return = connect_db();
    if ($return) {
        print "" . $DBI::errstr . "\n";
        exit;
    }
    else {
        print "Repairing table qevent...\n";
        $query = "REPAIR TABLE qevent";
        $dbh->do($query);
        print "Done\n";
        print "Repairing table queue_stats...\n";
        $query = "REPAIR TABLE queue_stats";
        $dbh->do($query);
        print "Done\n";
        print "Repairing table queue_stats_mv...\n";
        $query = "REPAIR TABLE queue_stats_mv";
        $dbh->do($query);
        print "Done\n";
        print "Repairing table recordings...\n";
        $query = "REPAIR TABLE recordings";
        $dbh->do($query);
        print "Done\n";
    }
}
 
sub purgedb() {
    print "Purging data\n";
    my $return = connect_db();
    if ($return) {
        print "" . $DBI::errstr . "\n";
        exit;
    }
    else {
        $query = "DELETE FROM qname";
        $dbh->do($query);
        print $query. "\n";
        $query = "ALTER TABLE qname AUTO_INCREMENT = 1";
        $dbh->do($query);
        print $query. "\n";
        $query = "INSERT INTO qname VALUES (-1,'ALL')";
        $dbh->do($query);
        print $query. "\n";
        $query = "DELETE FROM qagent";
        $dbh->do($query);
        print $query. "\n";
        $query = "ALTER TABLE qagent AUTO_INCREMENT = 1";
        $dbh->do($query);
        print $query. "\n";
        $query = "INSERT INTO qagent VALUES (-1,'ALL',0)";
        $dbh->do($query);
        print $query. "\n";
        $query = "TRUNCATE TABLE queue_stats";
        $dbh->do($query);
        print $query. "\n";
        $query = "ALTER TABLE queue_stats AUTO_INCREMENT = 1";
        $dbh->do($query);
        print $query. "\n";
        $query = "TRUNCATE TABLE queue_stats_mv";
        $dbh->do($query);
        print $query. "\n";
        $query = "TRUNCATE TABLE agent_activity";
        $dbh->do($query);
        print $query. "\n";
        $query = "TRUNCATE TABLE debug";
        $dbh->do($query);
        print $query. "\n";
        print $query. "\n";
        print "Done...\n";
    }
}

sub load_config() {
    $file = shift;
    return unless ( -r $file );
    open( CFG, "<$file" ) or return;
    while (<CFG>) {
        chomp;
        my ( $var, $val ) = split(/\s*\=\s*/);
        $val =~ s/'([^']*)';/$1/g;
        $var = lc($var);
        $config{$var} = $val;
    }
    close(CFG);
}

sub reconecta() {
    my $return = connect_db();

    if ($return) {
        print "" . $DBI::errstr . "\n";
        alarm(5);
    }
    else {
        print "Connected to MySQL!\n";
        $conectado = 1;
        open( LOSTEVENTS, "</var/log/asterisk/queue_log_failed" );
        while (<LOSTEVENTS>) {
            chomp;
            print "Processing lost line: $_\n";
            procesa($_);
        }
        close(LOSTEVENTS);
        open( LOSTEVENTS, ">/var/log/asterisk/queue_log_failed" );
        close(LOSTEVENTS);
        print "Reseting /var/log/asterisk/queue_log_failed\n";
        &set_events();
    }
}

sub populate_helper_tables() {
    # for speeding up agent_activity materialization
    $query = "DROP TABLE IF EXISTS agent_activity_pause";
    $dbh->do($query);

    $query = "CREATE TABLE IF NOT EXISTS `agent_activity_pause` (
      `agent` varchar(250) NOT NULL,
      `datetime` timestamp,
      `state` varchar(15) DEFAULT '',
      `queue` varchar(250) DEFAULT '',
      `data` varchar(150) DEFAULT '',
      `computed` tinyint unsigned default 1,
      `pauseid` int(11) default 0,
      PRIMARY KEY (`agent`)
    ) ENGINE=memory DEFAULT CHARSET=utf8";
    $dbh->do($query);

    # subselects do not work well on older MySQL
    # $query = "SELECT agent,datetime,event AS state,queue,data,computed,id FROM agent_activity WHERE id IN (select max(id) FROM agent_activity WHERE event in ('START PAUSE','END PAUSE') AND computed=0 GROUP BY agent)";

    $query = "CREATE TEMPORARY TABLE pauses SELECT MAX(id) AS id FROM agent_activity WHERE event in ('START PAUSE','END PAUSE') AND computed=0 GROUP BY agent";
    $sth   = $dbh->prepare($query);
    $sth->execute;

    $query = "SELECT agent,datetime,event AS state,queue,data,computed,a.id FROM pauses a LEFT JOIN agent_activity b ON a.id=b.id";
    $sth   = $dbh->prepare($query);
    $sth->execute;

    while (@row = $sth->fetchrow_array) {

        my $stj = $dbh->prepare(qq{
            INSERT INTO agent_activity_pause VALUES (?,?,?,?,?,?,?);
        });
        $stj->execute(@row) or handle_error( $dbh->err(), $dbh->errstr(), $linea );
        $stj->finish;
    }
    $sth->finish;

    $query = "DROP TABLE IF EXISTS pauses";
    $dbh->do($query);

    $query = "DROP TABLE IF EXISTS agent_activity_session";
    $dbh->do($query);

    $query = "CREATE TABLE IF NOT EXISTS `agent_activity_session` (
      `agent` varchar(250) NOT NULL,
      `datetime` timestamp,
      `state` varchar(15) DEFAULT '',
      `queue` varchar(250) DEFAULT '',
      `data` varchar(150) DEFAULT '',
      `incall` tinyint DEFAULT 0,
      `sessionid` int(11) default 0,
      `sessioncount` int(11) default 0,
      `computed` int(11) default 0,
      PRIMARY KEY (`agent`)
    ) ENGINE=memory DEFAULT CHARSET=utf8";
    $dbh->do($query);

    # old mysql does not like subselects
    #$query = "SELECT agent,datetime,event AS state,queue,data,0,id,IF(event='START SESSION',lastedforseconds,0) FROM agent_activity WHERE id IN (SELECT max(id) FROM agent_activity WHERE event IN ('START SESSION','END SESSION') AND computed=0 group by agent)";

    $query = "CREATE TEMPORARY TABLE sessions SELECT max(id) FROM agent_activity WHERE event IN ('START SESSION','END SESSION') AND computed=0 GROUP BY agent";
    $sth   = $dbh->prepare($query);
    $sth->execute;

    $query = "SELECT agent,datetime,event AS state,queue,data,0,a.id,IF(event='START SESSION',lastedforseconds,0),0 FROM sessions a LEFT JOIN agent_activity b ON a.id=b.id";
    $sth   = $dbh->prepare($query);
    $sth->execute;

    while (@row = $sth->fetchrow_array) {
        my $agent = $row[0];
        my $datetime = $row[1];
        $query = "SELECT IF(event='START CALL',1,0) AS incall FROM agent_activity WHERE agent=? AND event IN ('START CALL','END CALL') AND datetime>? ORDER BY datetime DESC LIMIT 1";
        $stk   = $dbh->prepare($query);
        $stk->bind_param( 1, $agent );
        $stk->bind_param( 2, $datetime );
        $stk->execute;
        my ($incall) = $stk->fetchrow_array and $stk->finish();
        if(!defined($incall)) { $incall=0; }
        $row[5]=$incall;
        my $stj = $dbh->prepare(qq{
            INSERT INTO agent_activity_session VALUES (?,?,?,?,?,?,?,?,?);
        });
        $stj->execute(@row) or handle_error( $dbh->err(), $dbh->errstr(), $linea );
        $stj->finish;
    }
    $sth->finish;

    $query = "DROP TABLE IF EXISTS sessions";
    $dbh->do($query);

    $query = "DROP TABLE IF EXISTS agent_activity_deferpause";
    $dbh->do($query);
    $query = "CREATE TABLE IF NOT EXISTS `agent_activity_deferpause` (
      `agent` varchar(250) NOT NULL,
      `reason` varchar(250) DEFAULT '',
      `datetime` timestamp,
      PRIMARY KEY (`agent`)
    ) ENGINE=memory DEFAULT CHARSET=utf8";

    $dbh->do($query);


}

sub check_tables() {

    print "Checking tables,indexes and triggers...\n";

    my %create_table;
    my %help_text;

    $query = "SET character_set_client = utf8";
    $sth = $dbh->prepare($query);
    $sth->execute();

    $help_text{'000_aatempactivity'}    = "Setting helper session table";
    $create_table{'000_aaatempactivity'} = "DROP TABLE IF EXISTS `agent_activity_session`";
    $create_table{'000_aatempactivity'} = "CREATE TABLE IF NOT EXISTS `agent_activity_session` (
      `agent` varchar(250) NOT NULL,
      `datetime` timestamp,
      `state` varchar(15) DEFAULT '',
      `queue` varchar(250) DEFAULT '',
      `data` varchar(150) DEFAULT '',
      `incall` tinyint DEFAULT 0,
      `sessionid` int(11) default 0,
      `sessioncount` int(11) default 0,
      `computed` int(11) default 0,
      PRIMARY KEY (`agent`)
    ) ENGINE=memory DEFAULT CHARSET=utf8";
    $help_text{'000_abtempactivity'}    = "Resetting helper session table";
    $create_table{'000_abtempactivity'} = "TRUNCATE TABLE agent_activity_session";

    $help_text{'000_actempactivity'}    = "Setting helper pause table";
    $create_table{'000_aactempactivity'} = "DROP TABLE IF EXISTS `agent_activity_pause`";
    $create_table{'000_actempactivity'} = "CREATE TABLE IF NOT EXISTS `agent_activity_pause` (
      `agent` varchar(250) NOT NULL,
      `datetime` timestamp,
      `state` varchar(15) DEFAULT '',
      `queue` varchar(250) DEFAULT '',
      `data` varchar(150) DEFAULT '',
      `computed` tinyint unsigned default 1,
      `pauseid` int(11) default 0,
      PRIMARY KEY (`agent`)
    ) ENGINE=memory DEFAULT CHARSET=utf8";
    $help_text{'000_adtempactivity'}    = "Resetting helper pause table";
    $create_table{'000_adtempactivity'} = "TRUNCATE TABLE agent_activity_pause";

    $help_text{'000_aetempactivity'}    = "Setting helper defer pause table";
    $create_table{'000_aaetempactivity'} = "DROP TABLE IF EXISTS `agent_activity_deferpause`";
    $create_table{'000_aetempactivity'} = "CREATE TABLE IF NOT EXISTS `agent_activity_deferpause` (
      `agent` varchar(250) NOT NULL,
      `reason` varchar(250) DEFAULT '',
      `datetime` timestamp,
      PRIMARY KEY (`agent`)
    ) ENGINE=memory DEFAULT CHARSET=utf8";
    $help_text{'000_aftempactivity'}    = "Resetting helper pause table";
    $create_table{'000_aftempactivity'} = "TRUNCATE TABLE agent_activity_deferpause";


    $help_text{'001_queue_stats_mv'} = "Creating table queue_stats_mv";
    $create_table{'001_queue_stats_mv'} = "
        CREATE TABLE IF NOT EXISTS `queue_stats_mv` (
          `id` int(11) unsigned NOT NULL auto_increment,
          `datetime` timestamp,
          `datetimeconnect` timestamp DEFAULT '1971-01-01 00:00:00',
          `datetimeend` timestamp DEFAULT '1971-01-01 00:00:00',
          `queue` varchar(100) NOT NULL DEFAULT '',
          `agent` varchar(100) NOT NULL DEFAULT '',
          `event` varchar(40) NOT NULL DEFAULT '',
          `uniqueid` varchar(50) NOT NULL DEFAULT '',
          `real_uniqueid` varchar(50) NOT NULL,
          `clid` varchar(50) NOT NULL default '',
          `url` varchar(100) NOT NULL default '',
          `did` varchar(100) NOT NULL default '',
          `position` int(6) unsigned NOT NULL default '1',
          `info1` varchar(50) NOT NULL default '',
          `info2` varchar(50) NOT NULL default '',
          `info3` varchar(50) NOT NULL default '',
          `info4` varchar(50) NOT NULL default '',
          `info5` varchar(50) NOT NULL default '',
          `overflow` int(6) unsigned NOT NULL default '1',
          `combined_waittime` int(11) unsigned NOT NULL default 0,
          `waittime` int(11) unsigned NOT NULL default 0,
          `talktime` int(11) unsigned NOT NULL default 0,
          `ringtime` int(11) unsigned NOT NULL default 0,
          PRIMARY KEY (`id`),
          KEY `fecha` (`datetime`),
          KEY `ev` (`event`),
          KEY `pidx` (`real_uniqueid`,`id`),
          KEY `uni` (`uniqueid`),
          KEY `runi` (`real_uniqueid`),
          KEY `idx_queue_datetime_event` (`queue`, `datetime`, `event`),
          KEY `idx_datetimeconnect_queue` (`datetimeconnect`, `queue`)
        ) DEFAULT CHARSET=utf8";

$materialized_trigger = <<'END_TRIGGER';

CREATE TRIGGER queue_stats_ins 
AFTER INSERT ON queue_stats 
FOR EACH ROW
BEGIN

DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @errorCode = 1;
SET @event_name = ''; SET @queue_name = ''; SET @agent_name = ''; SET @enterdate  = '';
SET @connectdate= ''; SET @clid       = ''; SET @position   = ''; SET @url        = '';
SET @overflow   = ''; SET @firstenter = ''; SET @lastenter  = ''; SET @did        = '';
SET @waittime   = ''; SET @combined_waittime = '0'; SET @talktime = '0'; SET @ringtime = '0';
SET @previoustransfer = '0'; SET @info1=''; SET @info2=''; SET @info3=''; SET @info4=''; 
SET @info5 = ''; SET @info6 = ''; SET @info7 = ''; SET @info8 = '';  SET @info9=''; SET @info10=''; SET @errorCode=0;

SELECT event FROM qevent WHERE event_id = NEW.qevent INTO @event_name;
SELECT agent FROM qagent WHERE agent_id = NEW.qagent INTO @agent_name;
SELECT queue FROM qname  WHERE queue_id = NEW.qname  INTO @queue_name;

IF @event_name LIKE 'COMPLETE%' THEN

    /*answered calls*/

    /* Elige el ultimo evento ENTERQUEUE */
    SELECT datetime,info1,info2,info3,info4,info5 FROM queue_stats JOIN qevent ON qevent=event_id WHERE event='ENTERQUEUE' AND uniqueid=NEW.uniqueid ORDER BY datetime DESC LIMIT 1 INTO @enterdate,@url,@clid,@position,@did,@info5;

    /* Elige el ultimo evento CONNECT */
    SELECT datetime,info3 FROM queue_stats JOIN qevent ON qevent=event_id WHERE event='CONNECT' AND uniqueid=NEW.uniqueid ORDER BY datetime DESC LIMIT 1 INTO @connectdate,@ringtime;

    /* Calcula overflow */
    SELECT count(uniqueid) FROM queue_stats JOIN qevent ON qevent=event_id WHERE event='ENTERQUEUE' AND uniqueid=NEW.uniqueid INTO @overflow;

    SELECT UNIX_TIMESTAMP(@connectdate)-UNIX_TIMESTAMP(@enterdate),UNIX_TIMESTAMP(@connectdate)-UNIX_TIMESTAMP(@enterdate) INTO @waittime,@combined_waittime;

    SELECT UNIX_TIMESTAMP(NEW.datetime)-UNIX_TIMESTAMP(@connectdate) INTO @talktime;

    IF @overflow > 1 THEN
        SELECT SUM(waittime)+@waittime FROM queue_stats_mv WHERE real_uniqueid=NEW.uniqueid INTO @combined_waittime;
    END IF;

    SELECT count(*) FROM queue_stats_mv WHERE event='TRANSFER' AND datetime=@enterdate AND agent=@agent_name AND queue=@queue_name INTO @previoustransfer;

    IF @connectdate > 0 AND @previoustransfer = 0 THEN
        /* skip insertion of complete events with no CONNECT, when attendedtransfers are logged, asterisk might add a complete before or after, and we want to discard those */
        INSERT INTO queue_stats_mv (uniqueid,real_uniqueid,event,agent,queue,datetime,datetimeconnect,datetimeend,clid,position,url,did,overflow,info1,info2,info3,info4,info5,waittime,combined_waittime,talktime,ringtime) 
        VALUES (CONCAT(NEW.uniqueid,'^',@overflow),NEW.uniqueid,@event_name,@agent_name,@queue_name,@enterdate,@connectdate,NEW.datetime,@clid,IF(NEW.info3='',1,IFNULL(NEW.info3,1)),IFNULL(@url,''),IFNULL(@did,''),@overflow,IFNULL(NEW.info1,''),IFNULL(NEW.info2,''),IFNULL(NEW.info3,''),IFNULL(NEW.info4,''),IFNULL(@info5,''),IFNULL(@waittime,0),IFNULL(@combined_waittime,0),IFNULL(@talktime,0),IF(@ringtime='',1,IFNULL(@ringtime,1)));

        /* agent activity */
        INSERT INTO agent_activity (datetime,queue,agent,event,data,lastedforseconds,uniqueid,computed,info1) VALUES (NEW.datetime,@queue_name,@agent_name,'END CALL',@clid,IFNULL(@talktime,0),NEW.uniqueid,0,@event_name);

        /* computed repause if paused before making a call, that inserts a computed end pause just before */
        SELECT state,datetime,data,queue FROM agent_activity_pause WHERE state = 'END PAUSE' AND agent=@agent_name AND computed=1 INTO @info8,@info9,@info10,@info3;
        IF @info8 <> '' THEN
            INSERT INTO agent_activity (datetime,queue,agent,event,data,lastedforseconds,uniqueid,computed) VALUES (NEW.datetime,@info3,@agent_name,'START PAUSE',@info10,0,NEW.uniqueid,1);
            INSERT INTO agent_activity_pause (agent,state,datetime,queue,data,computed,pauseid) VALUES (@agent_name,'START PAUSE',NEW.datetime,@info3,@info10,1,LAST_INSERT_ID()) 
                ON DUPLICATE KEY update state='START PAUSE',datetime=NEW.datetime,queue=@info3,data=@info10,computed=1,pauseid=LAST_INSERT_ID();
        END IF;

        /* deferred pause if we skipped paused because it came during a call */
        SET @deferdate='';
        SELECT reason,datetime,UNIX_TIMESTAMP(NEW.datetime)-UNIX_TIMESTAMP(datetime) AS duration FROM agent_activity_deferpause WHERE agent = @agent_name INTO @info1,@deferdate,@holdduration;
        if @deferdate <> '' THEN
            if @info1 = 'Hold' THEN
                /* If unhold comes after complete, insert it *before* -1 seconds of complete time. Seems PJSIP timing makes the unhold come after the complete, and we do not want to
                drag the in call pause when it is a hold */
                INSERT INTO agent_activity (datetime,queue,agent,event,data,lastedforseconds,uniqueid,computed) VALUES (@deferdate,@queue_name,@agent_name,'START PAUSE',@info1,0,NEW.uniqueid,1);
                INSERT INTO agent_activity (datetime,queue,agent,event,data,lastedforseconds,uniqueid,computed) VALUES (DATE_SUB(NEW.datetime,INTERVAL 1 SECOND),@queue_name,@agent_name,'END PAUSE',@info1,@holdduration,NEW.uniqueid,1);
                /* hold deferred pauses should not carry on on following calls, but other reason pauses like "outbound", should */
                DELETE FROM agent_activity_deferpause WHERE agent = @agent_name;

            ELSE
                INSERT INTO agent_activity (datetime,queue,agent,event,data,lastedforseconds,uniqueid,computed) VALUES (NEW.datetime,@queue_name,@agent_name,'START PAUSE',@info1,0,NEW.uniqueid,1);
                INSERT INTO agent_activity_pause (agent,state,datetime,queue,data,computed,pauseid) VALUES (@agent_name,'START PAUSE',NEW.datetime,@queue_name,@info1,1,LAST_INSERT_ID()) 
                    ON DUPLICATE KEY update state='START PAUSE',datetime=NEW.datetime,queue=@queue_name,data=@info1,computed=1,pauseid=LAST_INSERT_ID();
            END IF;
        END IF;

    END IF;

    UPDATE agent_activity_session SET datetime=datetime,incall=0 WHERE agent=@agent_name;

ELSEIF @event_name='ADDMEMBER' OR @event_name='AGENTLOGIN' OR @event_name='AGENTCALLBACKLOGIN'  THEN

    /* materialized insert */

    INSERT INTO queue_stats_mv (uniqueid,real_uniqueid,event,agent,queue,datetime,datetimeconnect,datetimeend,info1,info2,info3,info4,info5) 
    VALUES (CONCAT_WS('.','x',UNIX_TIMESTAMP(NEW.datetime),'agent',NEW.queue_stats_id),CONCAT_WS('.',UNIX_TIMESTAMP(NEW.datetime),NEW.queue_stats_id),@event_name,@agent_name,@queue_name,NEW.datetime,NEW.datetime,NEW.datetime,IFNULL(NEW.info1,0),IFNULL(NEW.info2,0),IFNULL(NEW.info3,''),IFNULL(NEW.info4,''),IFNULL(NEW.info5,''));

    /* agent activity start session */

    SET @event=''; SET @sessionid='';

    SELECT state,sessionid FROM agent_activity_session WHERE agent=@agent_name AND UNIX_TIMESTAMP(datetime)>=UNIX_TIMESTAMP(NEW.datetime)-86400 INTO @event,@sessionid;
    if @event = '' OR @event = 'END SESSION' THEN
        /* no open session in the last 24 hours, insert real start session/*

        /* computed end pause */ 
        SET @datetime=''; SET @data=''; SET @queue=''; SET @eventpause='';
        SELECT datetime,data,queue,state FROM agent_activity_pause WHERE agent=@agent_name INTO @datetime,@data,@queue,@eventpause;
        IF @eventpause = 'START PAUSE' THEN
            INSERT INTO agent_activity (datetime,queue,agent,event,data,lastedforseconds,uniqueid,computed) VALUES (NEW.datetime,@queue,@agent_name,'END PAUSE',@data,UNIX_TIMESTAMP(NEW.datetime)-UNIX_TIMESTAMP(@datetime),NEW.uniqueid,1);
            INSERT INTO agent_activity_pause (agent,state,datetime,queue,data,computed,pauseid) VALUES (@agent_name,'END PAUSE',NEW.datetime,@queue,@data,1,LAST_INSERT_ID()) 
                ON DUPLICATE KEY update state='END PAUSE', queue=@queue, data=@data, datetime=NEW.datetime, computed=1,pauseid=LAST_INSERT_ID();
        END IF;
        /* end computed en pause */

        INSERT INTO agent_activity (datetime,queue,agent,event,data,lastedforseconds,uniqueid,computed) VALUES (NEW.datetime,@queue_name,@agent_name,'START SESSION','',1,NEW.uniqueid,0) ON DUPLICATE KEY UPDATE queue=CONCAT_WS(',',queue,@queue_name);
        INSERT INTO agent_activity_session (agent,state,queue,datetime,sessionid,sessioncount) VALUES (@agent_name,'START SESSION',@queue_name,NEW.datetime,LAST_INSERT_ID(),1) 
            ON DUPLICATE KEY update state='START SESSION',datetime=NEW.datetime,sessionid=LAST_INSERT_ID(),sessioncount=1,queue=@queue_name;
    ELSE
        /* it has an open session in past 24hs , just update queue on that event instead of adding a new record */
        SELECT FIND_IN_SET(@queue_name,queue) FROM agent_activity WHERE id=@sessionid INTO @info1;
        IF @info1 = 0 THEN
            UPDATE agent_activity SET queue=CONCAT_WS(',',queue,@queue_name),lastedforseconds=lastedforseconds+1 WHERE id=@sessionid;
            UPDATE agent_activity_session SET datetime=datetime,sessioncount=sessioncount+1,queue=CONCAT_WS(',',queue,@queue_name) WHERE agent=@agent_name;
        END IF;
    END IF;

ELSEIF @event_name='REMOVEMEMBER' OR @event_name='AGENTCALLBACKLOGOFF' OR @event_name='AGENTLOGOFF' THEN

    /* materialized insert */

    INSERT INTO queue_stats_mv (uniqueid,real_uniqueid,event,agent,queue,datetime,datetimeconnect,datetimeend,info1,info2,info3,info4,info5) 
    VALUES (CONCAT_WS('.','x',UNIX_TIMESTAMP(NEW.datetime),'agent',NEW.queue_stats_id),CONCAT_WS('.',UNIX_TIMESTAMP(NEW.datetime),NEW.queue_stats_id),@event_name,@agent_name,@queue_name,NEW.datetime,NEW.datetime,NEW.datetime,IFNULL(NEW.info1,0),IFNULL(NEW.info2,0),IFNULL(NEW.info3,''),IFNULL(NEW.info4,''),IFNULL(NEW.info5,''));

    /* agent activity end session */

    SET @event=''; SET @sessionid=''; SET @sessioncount=''; SET @sessionstarttime='';
    /*SELECT state,sessionid,sessioncount,datetime,queue FROM agent_activity_session WHERE agent=@agent_name AND UNIX_TIMESTAMP(datetime)>=UNIX_TIMESTAMP(NEW.datetime)-86400 INTO @event,@sessionid,@sessioncount,@sessionstarttime,@sessionqueues;*/
    SELECT state,sessionid,sessioncount,datetime,queue FROM agent_activity_session WHERE agent=@agent_name INTO @event,@sessionid,@sessioncount,@sessionstarttime,@sessionqueues;

    IF @event = 'START SESSION' AND @sessioncount = 1 THEN
        /* computed end pause */ 
        SET @datetime=''; SET @data=''; SET @queue=''; SET @eventpause='';
        SELECT datetime,data,queue,state FROM agent_activity_pause WHERE agent=@agent_name INTO @datetime,@data,@queue,@eventpause;
        IF @eventpause = 'START PAUSE' THEN
            INSERT INTO agent_activity (datetime,queue,agent,event,data,lastedforseconds,uniqueid,computed) VALUES (NEW.datetime,@queue,@agent_name,'END PAUSE',@data,UNIX_TIMESTAMP(NEW.datetime)-UNIX_TIMESTAMP(@datetime),NEW.uniqueid,1);
            INSERT INTO agent_activity_pause (agent,state,datetime,queue,data,computed,pauseid) VALUES (@agent_name,'END PAUSE',NEW.datetime,@queue,@data,1,LAST_INSERT_ID()) ON DUPLICATE KEY update state='END PAUSE', queue=@queue, data=@data, datetime=NEW.datetime, computed=1,pauseid=LAST_INSERT_ID();
        END IF;
        /* end computed en pause */

        /* habia un solo start, inserto el END */
        INSERT INTO agent_activity (datetime,queue,agent,event,data,lastedforseconds,uniqueid,computed) VALUES (NEW.datetime,@sessionqueues,@agent_name,'END SESSION',@sessionstarttime,UNIX_TIMESTAMP(NEW.datetime)-UNIX_TIMESTAMP(@sessionstarttime),NEW.uniqueid,0);
        INSERT INTO agent_activity_session (agent,state,datetime) VALUES (@agent_name,'END SESSION',NEW.datetime) ON DUPLICATE KEY update state='END SESSION',datetime=NEW.datetime;
        /* remove any pauses from session temp table for that agent */
        DELETE FROM agent_activity_pause WHERE agent=@agent_name;
        DELETE FROM agent_activity_deferpause WHERE agent=@agent_name;

    ELSEIF @event = 'START SESSION' AND @sessioncount > 1 THEN
        UPDATE agent_activity_session SET datetime=datetime,sessioncount=sessioncount-1 WHERE agent=@agent_name;
        UPDATE agent_activity SET lastedforseconds=lastedforseconds-1 WHERE id=@sessionid;
    END IF;

ELSEIF @event_name='RINGNOANSWER' THEN

    SET @eventsession = '';
    SELECT datetime,state,sessionid FROM agent_activity_session WHERE agent=@agent_name INTO @eventdatetime,@eventsession,@sessid;
    IF @eventsession = 'END SESSION' OR @eventsession = '' THEN
        IF UNIX_TIMESTAMP(NEW.datetime)-UNIX_TIMESTAMP(@eventdatetime) > 30 THEN

            /* computed end pause */ 
            SET @datetime=''; SET @data=''; SET @queue=''; SET @eventpause='';
            SELECT datetime,data,queue,state FROM agent_activity_pause WHERE agent=@agent_name INTO @datetime,@data,@queue,@eventpause;
            IF @eventpause = 'START PAUSE' THEN
                INSERT INTO agent_activity (datetime,queue,agent,event,data,lastedforseconds,uniqueid,computed) VALUES (NEW.datetime,@queue,@agent_name,'END PAUSE',@data,UNIX_TIMESTAMP(NEW.datetime)-UNIX_TIMESTAMP(@datetime),NEW.uniqueid,1);
                INSERT INTO agent_activity_pause (agent,state,datetime,queue,data,computed,pauseid) VALUES (@agent_name,'END PAUSE',NEW.datetime,@queue,@data,1,LAST_INSERT_ID()) ON DUPLICATE KEY update state='END PAUSE', queue=@queue, data=@data, datetime=NEW.datetime, computed=1,pauseid=LAST_INSERT_ID();
            END IF;
            /* end computed en pause */

            /* computed start session */
            SET @eventsession = '';
            SELECT state FROM agent_activity_session WHERE agent=@agent_name INTO @eventsession;
            IF @eventsession = 'END SESSION' OR @eventsession = '' THEN
                INSERT INTO agent_activity (datetime,queue,agent,event,data,lastedforseconds,uniqueid,computed) VALUES (NEW.datetime,@queue_name,@agent_name,'START SESSION','',0,NEW.uniqueid,1);
                INSERT INTO agent_activity_session (agent,state,datetime,sessionid,sessioncount,queue,computed) VALUES (@agent_name,'START SESSION',NEW.datetime,LAST_INSERT_ID(),1,@queue_name,1) ON DUPLICATE KEY update state='START SESSION',datetime=NEW.datetime,sessionid=LAST_INSERT_ID(),sessioncount=1,queue=@queue_name,computed=1;
            END IF;
            /* end computed start session */
        END IF;
    END IF;

    INSERT IGNORE INTO agent_activity (datetime,queue,agent,event,data,lastedforseconds,uniqueid,computed) VALUES (NEW.datetime,@queue_name,@agent_name,'FAILED','',NEW.info1/1000,NEW.uniqueid,0);

ELSEIF @event_name='PAUSE' THEN

    /* computed start session */
    SET @eventsession = '';
    SELECT state FROM agent_activity_session WHERE agent=@agent_name INTO @eventsession;
    IF @eventsession = 'END SESSION' OR @eventsession = '' THEN
        INSERT INTO agent_activity (datetime,queue,agent,event,data,lastedforseconds,uniqueid,computed) VALUES (NEW.datetime,@queue_name,@agent_name,'START SESSION','',0,NEW.uniqueid,1);
        INSERT INTO agent_activity_session (agent,state,datetime,sessionid,sessioncount,queue,computed) VALUES (@agent_name,'START SESSION',NEW.datetime,LAST_INSERT_ID(),1,@queue_name,1) 
            ON DUPLICATE KEY update state='START SESSION',datetime=NEW.datetime,sessionid=LAST_INSERT_ID(),sessioncount=1,queue=@queue_name,computed=1;
    END IF;
    /* end computed start session */

    SET @lastpause=''; 
    SET @pausedtime=''; SET @incall=0; SET @pausereason=''; SET @pauseid=''; SET @pausequeue='';
    SELECT state,datetime,data,pauseid,queue FROM agent_activity_pause WHERE agent=@agent_name into @lastpause,@pausedtime,@pausereason,@pauseid,@pausequeue;
    SELECT incall FROM agent_activity_session WHERE agent=@agent_name into @incall;

    IF (@lastpause = 'END PAUSE' OR @lastpause = '') AND @incall=0 THEN
        /* regular start pause, no need to compute */
        INSERT INTO agent_activity (datetime,queue,agent,event,data,lastedforseconds,uniqueid,computed) VALUES (NEW.datetime,@queue_name,@agent_name,'START PAUSE',NEW.info1,0,NEW.uniqueid,0);
        INSERT INTO agent_activity_pause (agent,state,datetime,queue,data,computed,pauseid) VALUES (@agent_name,'START PAUSE',NEW.datetime,@queue_name,NEW.info1,0,LAST_INSERT_ID()) 
            ON DUPLICATE KEY update state='START PAUSE',datetime=NEW.datetime,queue=@queue_name,data=NEW.info1,computed=0,pauseid=LAST_INSERT_ID();
    ELSEIF @incall = 1 THEN
        /* got PAUSE when on a call, defer pause by inserting something into info1 */
        INSERT INTO agent_activity_deferpause (agent,reason,datetime) VALUES (@agent_name,NEW.info1,NEW.datetime);
    ELSEIF @lastpause = 'START PAUSE' THEN
        /* previous was another start pause */
        IF UNIX_TIMESTAMP(NEW.datetime)-UNIX_TIMESTAMP(@pausedtime) < 30 THEN
            IF(FIND_IN_SET(@queue_name,@pausequeue)=0) THEN
                UPDATE agent_activity SET queue=CONCAT_WS(',',queue,@queue_name) WHERE id=@pauseid;
                UPDATE agent_activity_pause SET datetime=datetime,queue=CONCAT_WS(',',queue,@queue_name) WHERE agent=@agent_name AND state='START PAUSE';
            END IF;
            UPDATE agent_activity SET data=NEW.info1 WHERE id=@pauseid;
            UPDATE agent_activity_pause SET datetime=datetime,data=NEW.info1 WHERE agent=@agent_name AND state='START PAUSE';
        ELSE 
            INSERT INTO agent_activity (datetime,queue,agent,event,data,lastedforseconds,uniqueid,computed) VALUES (NEW.datetime,@pausequeue,@agent_name,'END PAUSE',@pausereason,UNIX_TIMESTAMP(NEW.datetime)-UNIX_TIMESTAMP(@pausedtime),NEW.uniqueid,1);
            INSERT INTO agent_activity (datetime,queue,agent,event,data,lastedforseconds,uniqueid,computed) VALUES (NEW.datetime,@queue_name,@agent_name,'START PAUSE',NEW.info1,0,NEW.uniqueid,0);
            INSERT INTO agent_activity_pause (agent,state,datetime,queue,data,computed,pauseid) VALUES (@agent_name,'START PAUSE',NEW.datetime,@queue_name,NEW.info1,1,LAST_INSERT_ID()) ON DUPLICATE KEY update state='START PAUSE',datetime=NEW.datetime,queue=@queue_name,data=NEW.info1,computed=1,pauseid=LAST_INSERT_ID();
        END IF;
    END IF;

ELSEIF @event_name='UNPAUSE' THEN

     /* computed start session */
    SET @eventsession = '';
    SELECT datetime,state,sessionid FROM agent_activity_session WHERE agent=@agent_name INTO @eventdatetime,@eventsession,@sessid;
    IF @eventsession = 'END SESSION' OR @eventsession = '' THEN
        IF UNIX_TIMESTAMP(NEW.datetime)-UNIX_TIMESTAMP(@eventdatetime) > 30 THEN
            /* INSERT INTO debug (texto) VALUES (CONCAT_WS(' ',@event_name,NEW.datetime,'computed start session on unpause',@agent_name)); */
            INSERT INTO agent_activity (datetime,queue,agent,event,data,lastedforseconds,uniqueid,computed) VALUES (NEW.datetime,@queue_name,@agent_name,'START SESSION','',0,NEW.uniqueid,1);
            INSERT INTO agent_activity_session (agent,state,datetime,sessionid,sessioncount,queue,computed) VALUES (@agent_name,'START SESSION',NEW.datetime,LAST_INSERT_ID(),1,@queue_name,1) 
                ON DUPLICATE KEY update state='START SESSION',datetime=NEW.datetime,sessionid=LAST_INSERT_ID(),sessioncount=1,queue=@queue_name,computed=1;
        /*
        ELSE
            INSERT INTO debug (texto) VALUES (CONCAT_WS(' ',@event_name,NEW.datetime,'skip computed start session on unpause',@agent_name));
        */
        END IF;
    END IF;
    /* end computed start session */

    SET @lastpause=''; SET @sessionid='';
    SET @pausedtime=''; SET @incall=0; SET @pausereason=''; SET @pauseid=''; SET @computed='';
    SELECT state,datetime,data,pauseid,computed FROM agent_activity_pause WHERE agent=@agent_name into @lastpause,@pausedtime,@pausereason,@pauseid,@computed;
    SELECT incall,sessionid FROM agent_activity_session WHERE agent=@agent_name into @incall,@sessionid;

    IF (@lastpause = 'START PAUSE' OR @lastpause = '') AND @incall=0 THEN

        /* we had a regular start pause previously, just close the pause normally */
        /* if we get an unpause after a call with no pause before, it will be ignored */

        INSERT INTO agent_activity (datetime,queue,agent,event,data,lastedforseconds,uniqueid,computed) VALUES (NEW.datetime,@queue_name,@agent_name,'END PAUSE',@pausereason,UNIX_TIMESTAMP(NEW.datetime)-UNIX_TIMESTAMP(@pausedtime),NEW.uniqueid,0);
        INSERT INTO agent_activity_pause (agent,state,datetime,queue,data,computed,pauseid) VALUES (@agent_name,'END PAUSE',NEW.datetime,@queue_name,@pausereason,0,LAST_INSERT_ID()) 
            ON DUPLICATE KEY update state='END PAUSE', queue=@queue_name, data=@pausereason, datetime=NEW.datetime,computed=0,pauseid=LAST_INSERT_ID();

        DELETE FROM agent_activity_deferpause WHERE agent = @agent_name;
    ELSEIF @lastpause = 'END PAUSE' AND @computed=1 AND @incall=0 THEN

        /* if we had a computed unpause and then a real one, update pause data with real pause  to avoid repauses after completecalls */
        UPDATE agent_activity_pause SET datetime=NEW.datetime,data=NEW.info1,computed=0 WHERE pauseid=@pauseid;
        UPDATE agent_activity SET datetime=NEW.datetime,data=NEW.info1,computed=0 WHERE id=@pauseid;

    ELSEIF @incall = 1 THEN

        /* We probably have a delayed pause, insert it as we got the END pause during the call (pause hold) */
        SET @info1=''; SET @defertime='';
        SELECT reason,datetime FROM agent_activity_deferpause WHERE agent = @agent_name INTO @info1,@defertime;
        IF (@info1 <> '') THEN
            INSERT INTO agent_activity (datetime,queue,agent,event,data,lastedforseconds,uniqueid,computed) VALUES (@defertime,@queue_name,@agent_name,'START PAUSE',@info1,0,NEW.uniqueid,0);
            INSERT INTO agent_activity (datetime,queue,agent,event,data,lastedforseconds,uniqueid,computed) VALUES (NEW.datetime,@queue_name,@agent_name,'END PAUSE',@info1,UNIX_TIMESTAMP(NEW.datetime)-UNIX_TIMESTAMP(@defertime),NEW.uniqueid,0);
            INSERT INTO agent_activity_pause (agent,state,datetime,queue,data,computed,pauseid) VALUES (@agent_name,'END PAUSE',NEW.datetime,@queue_name,@info1,0,LAST_INSERT_ID()) 
                ON DUPLICATE KEY update state='END PAUSE',datetime=NEW.datetime,queue=@queue_name,data=@info1,computed=0,pauseid=LAST_INSERT_ID();
            DELETE FROM agent_activity_deferpause WHERE agent = @agent_name;
        END IF;

    ELSE
        IF UNIX_TIMESTAMP(NEW.datetime)-UNIX_TIMESTAMP(@pausedtime) < 10 THEN
            UPDATE agent_activity SET queue=CONCAT_WS(',',queue,@queue_name) WHERE id=@pauseid;
        END IF;
    END IF;

ELSEIF @event_name='CONNECT' THEN

    /* computed end pause */ 
    SET @datetime=''; SET @data=''; SET @queue=''; SET @eventpause='';
    SELECT datetime,data,queue,state FROM agent_activity_pause WHERE agent=@agent_name INTO @datetime,@data,@queue,@eventpause;
    IF @eventpause = 'START PAUSE' THEN
        INSERT INTO agent_activity (datetime,queue,agent,event,data,lastedforseconds,uniqueid,computed) VALUES (NEW.datetime,@queue,@agent_name,'END PAUSE',@data,UNIX_TIMESTAMP(NEW.datetime)-UNIX_TIMESTAMP(@datetime),NEW.uniqueid,1);
        INSERT INTO agent_activity_pause (agent,state,datetime,queue,data,computed,pauseid) VALUES (@agent_name,'END PAUSE',NEW.datetime,@queue,@data,1,LAST_INSERT_ID()) 
            ON DUPLICATE KEY update state='END PAUSE', queue=@queue, data=@data, datetime=NEW.datetime, computed=1,pauseid=LAST_INSERT_ID();
    END IF;
    /* end computed en pause */

    /* computed start session */
    SET @eventsession = '';
    SELECT state FROM agent_activity_session WHERE agent=@agent_name INTO @eventsession;
    IF @eventsession = 'END SESSION' OR @eventsession = '' THEN
        INSERT INTO agent_activity (datetime,queue,agent,event,data,lastedforseconds,uniqueid,computed) VALUES (NEW.datetime,@queue_name,@agent_name,'START SESSION','',0,NEW.uniqueid,1);
        INSERT INTO agent_activity_session (agent,state,datetime,sessionid,sessioncount,queue,computed) VALUES (@agent_name,'START SESSION',NEW.datetime,LAST_INSERT_ID(),1,@queue_name,1) 
            ON DUPLICATE KEY update state='START SESSION',datetime=NEW.datetime,sessionid=LAST_INSERT_ID(),sessioncount=1,computed=1;
    END IF;
    /* end computed start session */

    UPDATE agent_activity_session SET datetime=datetime,incall=1 WHERE agent=@agent_name;

    /* Elige el ultimo evento ENTERQUEUE */
    SELECT datetime,info1,info2,info3,info4 FROM queue_stats JOIN qevent ON qevent=event_id WHERE event='ENTERQUEUE' AND uniqueid=NEW.uniqueid ORDER BY datetime DESC LIMIT 1 INTO @enterdate,@url,@clid,@position,@did;
    INSERT INTO agent_activity (datetime,queue,agent,event,data,lastedforseconds,uniqueid,computed) VALUES (NEW.datetime,@queue_name,@agent_name,'START CALL',@clid,0,NEW.uniqueid,0);


ELSEIF @event_name='TRANSFER' OR @event_name='UPDATETRANSFER' THEN

    /*transferred calls*/

    SELECT datetime,info1,info2,info5,info4 FROM queue_stats JOIN qevent ON qevent=event_id WHERE event='ENTERQUEUE' AND uniqueid=NEW.uniqueid ORDER BY datetime DESC LIMIT 1 INTO @enterdate,@url,@clid,@position,@did;

    SELECT datetime,info3 FROM queue_stats JOIN qevent ON qevent=event_id WHERE event='CONNECT' AND uniqueid=NEW.uniqueid ORDER BY datetime DESC LIMIT 1 INTO @connectdate,@ringtime;

    SELECT count(uniqueid) FROM queue_stats JOIN qevent ON qevent=event_id WHERE event='ENTERQUEUE' AND uniqueid=NEW.uniqueid INTO @overflow;

    SELECT UNIX_TIMESTAMP(@connectdate)-UNIX_TIMESTAMP(@enterdate),UNIX_TIMESTAMP(@connectdate)-UNIX_TIMESTAMP(@enterdate) INTO @waittime,@combined_waittime;

    SELECT UNIX_TIMESTAMP(NEW.datetime)-UNIX_TIMESTAMP(@connectdate) INTO @talktime;

    IF @overflow > 1 THEN
        SELECT SUM(waittime)+@waittime FROM queue_stats_mv WHERE real_uniqueid=NEW.uniqueid INTO @combined_waittime;
    END IF;

    INSERT INTO queue_stats_mv (uniqueid,real_uniqueid,event,agent,queue,datetime,datetimeconnect,datetimeend,clid,position,url,did,info1,info2,overflow,info3,info4,info5,waittime,combined_waittime,talktime,ringtime) 
    VALUES (CONCAT(NEW.uniqueid,'^',@overflow),NEW.uniqueid,'TRANSFER',@agent_name,@queue_name,@enterdate,@connectdate,NEW.datetime,@clid,IF(@position='',1,IFNULL(@position,1)),IFNULL(@url,''),IFNULL(@did,''),IFNULL(NEW.info1,0),IFNULL(NEW.info2,0),@overflow,IFNULL(NEW.info3,''),IFNULL(NEW.info4,''),IFNULL(NEW.info5,''),IFNULL(@waittime,0),IFNULL(@combined_waittime,0),IFNULL(@talktime,0),IFNULL(@ringtime,0));

    DELETE FROM queue_stats_mv WHERE (event='COMPLETECALLER' OR event='COMPLETEAGENT') AND datetime=@enterdate AND agent=@agent_name AND queue=@queue_name;

    INSERT INTO agent_activity (datetime,queue,agent,event,data,lastedforseconds,uniqueid,computed,info1) VALUES (NEW.datetime,@queue_name,@agent_name,'END CALL',@clid,IFNULL(@talktime,0),NEW.uniqueid,0,@event_name);
    UPDATE agent_activity_session SET datetime=datetime,incall=0 WHERE agent=@agent_name;

    /* computed repause if paused before making a call, that inserts a computed end pause just before */
    SELECT state,datetime,data,queue FROM agent_activity_pause WHERE state = 'END PAUSE' AND agent=@agent_name AND computed=1 INTO @info8,@info9,@info10,@info3;
    IF @info8 <> '' THEN
        INSERT INTO agent_activity (datetime,queue,agent,event,data,lastedforseconds,uniqueid,computed) VALUES (NEW.datetime,@info3,@agent_name,'START PAUSE',@info10,0,NEW.uniqueid,1);
        INSERT INTO agent_activity_pause (agent,state,datetime,queue,data,computed,pauseid) VALUES (@agent_name,'START PAUSE',NEW.datetime,@info3,@info10,1,LAST_INSERT_ID()) 
            ON DUPLICATE KEY update state='START PAUSE',datetime=NEW.datetime,queue=@info3,data=@info10,computed=1,pauseid=LAST_INSERT_ID();
    END IF;


ELSEIF @event_name LIKE '%ABANDON%' OR @event_name LIKE 'EXIT%' OR @event_name='BUSY' OR @event_name='CONGESTION' OR @event_name='CHANUNAVAIL' OR @event_name='DONTCALL' OR @event_name='TORTURE' OR @event_name='INVALIDARGS' OR @event_name='CANCEL' THEN

    /*unanswered calls*/

    SELECT datetime,info1,info2,info3,info4 FROM queue_stats JOIN qevent ON qevent=event_id WHERE event='ENTERQUEUE' AND uniqueid=NEW.uniqueid ORDER BY datetime DESC LIMIT 1 INTO @enterdate,@url,@clid,@position,@did;

    SELECT count(uniqueid) FROM queue_stats JOIN qevent ON qevent=event_id WHERE event='ENTERQUEUE' AND uniqueid=NEW.uniqueid INTO @overflow;

    SELECT UNIX_TIMESTAMP(NEW.datetime)-UNIX_TIMESTAMP(@enterdate),UNIX_TIMESTAMP(NEW.datetime)-UNIX_TIMESTAMP(@enterdate) INTO @waittime,@combined_waittime;

    IF @overflow > 1 THEN
        SELECT SUM(waittime)+@waittime FROM queue_stats_mv WHERE real_uniqueid=NEW.uniqueid INTO @combined_waittime;
    END IF;

    SET @connectdate = @enterdate;


    IF (@event_name = 'ABANDON' ) THEN 
        IF(@agent_name = 'NONE') THEN
            INSERT INTO queue_stats_mv (uniqueid,real_uniqueid,event,agent,queue,datetime,datetimeconnect,datetimeend,clid,position,url,did,info1,info2,overflow,info3,info4,info5,waittime,combined_waittime,talktime) 
            VALUES (CONCAT(NEW.uniqueid,'^',@overflow),NEW.uniqueid,@event_name,@agent_name,@queue_name,@enterdate,@connectdate,NEW.datetime,IFNULL(@clid,''),IF(@position='',1,IFNULL(@position,1)),IFNULL(@url,''),IFNULL(@did,''),IFNULL(NEW.info1,0),IFNULL(NEW.info2,0),@overflow,IFNULL(NEW.info3,''),IFNULL(NEW.info4,''),IFNULL(NEW.info5,''),IFNULL(@waittime,0),IFNULL(@combined_waittime,0),0);
        END IF;
    ELSEIF (@event_name = 'NOTABANDON' ) THEN
        DELETE FROM queue_stats_mv WHERE real_uniqueid=NEW.uniqueid;
    ELSE
        INSERT INTO queue_stats_mv (uniqueid,real_uniqueid,event,agent,queue,datetime,datetimeconnect,datetimeend,clid,position,url,did,info1,info2,overflow,info3,info4,info5,waittime,combined_waittime,talktime) 
        VALUES (CONCAT(NEW.uniqueid,'^',@overflow),NEW.uniqueid,@event_name,@agent_name,@queue_name,@enterdate,@connectdate,NEW.datetime,IFNULL(@clid,''),IF(@position='',1,IFNULL(@position,1)),IFNULL(@url,''),IFNULL(@did,''),IFNULL(NEW.info1,0),IFNULL(NEW.info2,0),@overflow,IFNULL(NEW.info3,''),IFNULL(NEW.info4,''),IFNULL(NEW.info5,''),IFNULL(@waittime,0),IFNULL(@combined_waittime,0),0);
    END IF;         

    IF (@agent_name <> 'NONE') THEN

        /* computed end pause */ 
        SET @datetime=''; SET @data=''; SET @queue=''; SET @eventpause='';
        SELECT datetime,data,queue,state FROM agent_activity_pause WHERE agent=@agent_name INTO @datetime,@data,@queue,@eventpause;
        IF @eventpause = 'START PAUSE' THEN
            INSERT INTO agent_activity (datetime,queue,agent,event,data,lastedforseconds,uniqueid,computed) VALUES (@connectdate,@queue,@agent_name,'END PAUSE',@data,UNIX_TIMESTAMP(NEW.datetime)-UNIX_TIMESTAMP(@datetime),NEW.uniqueid,1);
            INSERT INTO agent_activity_pause (agent,state,datetime,queue,data,computed,pauseid) VALUES (@agent_name,'END PAUSE',@connectdate,@queue,@data,1,LAST_INSERT_ID()) 
                ON DUPLICATE KEY update state='END PAUSE', queue=@queue, data=@data, datetime=NEW.datetime, computed=1,pauseid=LAST_INSERT_ID();
        END IF;
        /* end computed en pause */

        INSERT INTO agent_activity (datetime,queue,agent,event,data,lastedforseconds,uniqueid,computed) VALUES (@connectdate,@queue_name,@agent_name,'START CALL',@clid,0,NEW.uniqueid,0);
        INSERT INTO agent_activity (datetime,queue,agent,event,data,lastedforseconds,uniqueid,computed,info1) VALUES (NEW.datetime,@queue_name,@agent_name,'FAILED OUT',@clid,UNIX_TIMESTAMP(NEW.datetime)-UNIX_TIMESTAMP(@connectdate),NEW.uniqueid,0,@event_name);

        /* computed repause aftewards */
        IF @eventpause = 'START PAUSE' THEN
            INSERT INTO agent_activity (datetime,queue,agent,event,data,lastedforseconds,uniqueid,computed) VALUES (NEW.datetime,@queue,@agent_name,'START PAUSE',@data,0,NEW.uniqueid,1);
            INSERT INTO agent_activity_pause (agent,state,datetime,queue,data,computed,pauseid) VALUES (@agent_name,'START PAUSE',NEW.datetime,@queue,@data,1,LAST_INSERT_ID()) 
                ON DUPLICATE KEY update state='START PAUSE',datetime=NEW.datetime,queue=@queue,data=@data,computed=1,pauseid=LAST_INSERT_ID();
        END IF;
    END IF;
ELSEIF @event_name LIKE 'AGENT_%' THEN
    INSERT INTO queue_stats_mv (uniqueid,real_uniqueid,event,agent,queue,datetime,datetimeconnect,datetimeend,clid,position,url,did,info1,info2,overflow,info3,info4,info5,waittime,combined_waittime,talktime)
    VALUES (CONCAT(NEW.uniqueid,'^1'),NEW.uniqueid,@event_name,@agent_name,@queue_name,NEW.datetime,NEW.datetime,NEW.datetime,IFNULL(@clid,''),IF(@position='',1,IFNULL(@position,1)),IFNULL(@url,''),IFNULL(@did,''),IFNULL(NEW.info1,0),IFNULL(NEW.info2,0),@overflow,IFNULL(NEW.info3,''),IFNULL(NEW.info4,''),IFNULL(NEW.info5,''),IFNULL(@waittime,0),IFNULL(@combined_waittime,0),0);
END IF;
END;

END_TRIGGER


    # Check if queue_stats_mv is created, if not, add queries to populate data based on queue_stats data
    if(!check_table_exists('queue_stats_mv') || !check_table_field('queue_stats_mv','real_uniqueid') || !check_table_exists('agent_activity') || !check_table_field('agent_activity','info1')) {

        $help_text{'000_aa'}    = "Starting migrate process. This might take several minutes.";
        $create_table{'000_aa'} = "INSERT INTO setup (keyword,parameter,value) VALUES ('migrating','',0)";

        $help_text{'000_drop_mv'}    = "Removing old queue_stats_mv table";
        $create_table{'000_drop_mv'} = "DROP TABLE IF EXISTS queue_stats_mv";

        $help_text{'002_drop_agent_activity'}    = "Removing old agent_activity table";
        $create_table{'002_drop_agent_activity'} = "DROP TABLE IF EXISTS agent_activity";

        $help_text{'003_agent_activity'}    = "Creating agent_activity table";
        $create_table{'003_agent_activity'} = "CREATE TABLE `agent_activity` ( `id` int(11) NOT NULL AUTO_INCREMENT, `datetime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `queue` text, `agent` varchar(100) DEFAULT NULL, `event` varchar(40) DEFAULT NULL, `data` varchar(150) DEFAULT NULL, `lastedforseconds` int(11) DEFAULT NULL, `uniqueid` varchar(100) DEFAULT NULL, `computed` tinyint(1) DEFAULT NULL, `info1` varchar(200) DEFAULT '', `info2` varchar(200) DEFAULT '', PRIMARY KEY (`id`), UNIQUE KEY `uni` (`datetime`,`agent`,`event`), KEY `unidate` (`uniqueid`,`datetime`), KEY `idx_agent_datetime` (`agent`,`datetime`),KEY `idx_agent_event_datetime` (`agent`,`event`,`datetime`), KEY `idx_event_datetime` (`event`,`datetime`),KEY `idx_datetime` (`datetime`) ) DEFAULT CHARSET=utf8mb4"; 

        $help_text{'004_queue_stats_full'}    = "Creating queue_stats_full view";
        $create_table{'004_queue_stats_full'} = "CREATE OR REPLACE VIEW queue_stats_full AS SELECT q.*,qevent.event AS event, qagent.agent AS agent, qname.queue AS queue from queue_stats q force index (ixdate) LEFT JOIN qagent ON qagent=agent_id LEFT JOIN qname ON qname=queue_id LEFT JOIN qevent ON qevent = event_id";

        $help_text{"005_dupstats"}    = "Creating temporary queue_stats_temp table to reprocess/regenerate existing data";
        $create_table{"005_dupstats"} = "CREATE TABLE queue_stats_temp LIKE queue_stats";

        $help_text{'006_trigger1'}    = "Dropping insert trigger from queue_stats_temp if exists";
        $create_table{'006_trigger1'} = "DROP TRIGGER IF EXISTS queue_stats_ins_temp";

        $help_text{'007_trigger2'}    = "Dropping insert trigger from queue_stats if exists";
        $create_table{'007_trigger2'} = "DROP TRIGGER IF EXISTS queue_stats_ins";

        $temp_trigger = $materialized_trigger;
        $temp_trigger =~ s/AFTER INSERT ON queue_stats/AFTER INSERT ON queue_stats_temp/g;
        $temp_trigger =~ s/queue_stats_ins/queue_stats_ins_temp/g;
        $temp_trigger =~ s/ queue_stats / queue_stats_temp /g;

        $help_text{'008_trigger3'}    = "Creating insert trigger on temp table";
        $create_table{'008_trigger3'} = $temp_trigger;

        $help_text{'009_migrate'}    = "Migrating data...";
        $create_table{'009_migrate'} = "INSERT INTO queue_stats_temp SELECT * FROM queue_stats";

        $help_text{'010_trigger1'}    = "Removing insert trigger from temporary queue_stats_temp table";
        $create_table{'010_trigger1'} = "DROP TRIGGER IF EXISTS queue_stats_ins_temp";

        $help_text{'011_droptemp'}    = "Removing temporary table queue_stats_temp";
        $create_table{'011_droptemp'} = "DROP TABLE queue_stats_temp";

        $help_text{'012_endmigrate'}    = "Migration finished!";
     
    }
    $create_table{'012_endmigrate'} = "DELETE FROM setup WHERE keyword='migrating'";

    $help_text{'013_trigger1'}    = "Removing main insert trigger";
    $create_table{'013_trigger1'} = "DROP TRIGGER IF EXISTS queue_stats_ins";
    $help_text{'014_trigger2'}    = "Creating main insert trigger";
    $create_table{'014_trigger2'} = $materialized_trigger;

    foreach my $table (sort keys %create_table) {

        if($table eq "009_migrate") {
            # Migration is slow, expensive, try to do it in batches instead of just one query to speed it up and have partial data available during process
            my $count = $dbh->selectrow_array('SELECT count(*) FROM queue_stats', undef);
            my $split=10000;
            if($count>$split) {
                my $iterations = ceil($count/$split);
                for($i=0;$i<$iterations;$i++) {
                    my $progress = int($i * 100 / $iterations);
                    if($progress==0) { $progress=1; }
                    print "Migrating data... Progress: $progress%\n";
                    $sth = $dbh->prepare("REPLACE INTO setup (keyword,parameter,value) VALUES ('migrating','','$progress')");
                    $sth->execute() or handle_error( $dbh->err(), $dbh->errstr(), $table );
                    my $limit_start = $i * $split;
                    my $limit_end   = $split;
                    $sth = $dbh->prepare("INSERT INTO queue_stats_temp SELECT * FROM queue_stats LIMIT $limit_start,$limit_end");
                    $sth->execute() or handle_error( $dbh->err(), $dbh->errstr(), $table );
                    $sth->finish;
                }
                next; 
            }
        }

        if(defined($help_text{$table})) { print $help_text{$table}."\n"; }
        $sth = $dbh->prepare($create_table{$table});
        $sth->execute() or handle_error( $dbh->err(), $dbh->errstr(), $table );
        $sth->finish;
    }

    # Update table structures if needed
    my %alter_field;
    $alter_field{'queue_stats_mv'}{'did'}='VARCHAR(50) NOT NULL DEFAULT \'\' AFTER url';
    $alter_field{'queue_stats_mv'}{'info3'}='VARCHAR(50) NOT NULL DEFAULT \'\' AFTER info2';
    $alter_field{'queue_stats_mv'}{'info4'}='VARCHAR(50) NOT NULL DEFAULT \'\' AFTER info3';
    $alter_field{'queue_stats_mv'}{'info5'}='VARCHAR(50) NOT NULL DEFAULT \'\' AFTER info4';
    $alter_field{'queue_stats_mv'}{'real_uniqueid'}='VARCHAR(50) NOT NULL DEFAULT \'\' AFTER uniqueid';
    $alter_field{'queue_stats_mv'}{'waittime'}='INT(11) UNSIGNED NOT NULL DEFAULT 0';
    $alter_field{'queue_stats_mv'}{'combined_waittime'}='INT(11) UNSIGNED NOT NULL DEFAULT 0';
    $alter_field{'queue_stats_mv'}{'talktime'}='INT(11) UNSIGNED NOT NULL DEFAULT 0';
    $alter_field{'queue_stats_mv'}{'ringtime'}='INT(11) UNSIGNED NOT NULL DEFAULT 0';
    $alter_field{'queue_stats'}{'info3'}='VARCHAR(50) NOT NULL DEFAULT \'\' AFTER info2';
    $alter_field{'queue_stats'}{'info4'}='VARCHAR(50) NOT NULL DEFAULT \'\' AFTER info3';
    $alter_field{'queue_stats'}{'info5'}='VARCHAR(50) NOT NULL DEFAULT \'\' AFTER info4';
    $alter_field{'sched'}{'queues'}='TEXT';

    foreach my $table (keys %alter_field) {
        foreach my $field (keys %{$alter_field{$table}}) {
            my $type = $alter_field{$table}{$field};
            if(!check_table_field($table,$field)) {
                $query = "ALTER TABLE $table ADD $field $type";
                $sth = $dbh->prepare($query);
                $sth->execute();
                $sth->finish;
            }
        }
    }

    my %alter_field_default;
#    $alter_field_default{'queue_stats_mv'}{'datetime'}{'0000-00-00 00:00:00'}{'4'}="timestamp default '1971-01-01 00:00:00'";
#    $alter_field_default{'agent_activity'}{'datetime'}{'timestamp'}{'1'}='timestamp';
    $alter_field_default{'queue_stats'}{'info2'}{''}{'4'}="varchar(50) NOT NULL default ''";
    $alter_field_default{'queue_stats'}{'info3'}{''}{'4'}="varchar(50) NOT NULL default ''";
    $alter_field_default{'queue_stats'}{'info4'}{''}{'4'}="varchar(50) NOT NULL default ''";
    $alter_field_default{'queue_stats'}{'info5'}{''}{'4'}="varchar(50) NOT NULL default ''";

    foreach my $table (keys %alter_field_default) {
        foreach my $field (keys %{$alter_field_default{$table}}) {
            foreach my $default (keys %{$alter_field_default{$table}{$field}}) {
                foreach my $rowpos (keys %{$alter_field_default{$table}{$field}{$default}}) {
                    #print "default $table $field $default $rowpos\n";
                    if(!check_table_field_default($table,$field,$default,$rowpos)) {  # 4 is the row with default value
                        $value = $alter_field_default{$table}{$field}{$default}{$rowpos};
                        $query = "ALTER TABLE $table CHANGE $field $field $value";
                        print "$query\n";

                        $sth = $dbh->prepare($query);
                        $sth->execute();
                        $sth->finish;
                    }
                }
            }
        }
    }

    my %alter_field_notnull;
    $alter_field_notnull{'queue_stats'}{'info1'}{'NO'}="varchar (50) not null";
    $alter_field_notnull{'queue_stats'}{'info2'}{'NO'}="varchar (50) not null";
    $alter_field_notnull{'queue_stats'}{'info3'}{'NO'}="varchar (50) not null";
    $alter_field_notnull{'queue_stats'}{'info4'}{'NO'}="varchar (50) not null";
    $alter_field_notnull{'queue_stats'}{'info5'}{'NO'}="varchar (50) not null";
    $alter_field_notnull{'designer'}{'parameter'}{'NO'}="VARCHAR(250) NOT NULL default ''";
    foreach my $table (keys %alter_field_notnull) {
        foreach my $field (keys %{$alter_field_notnull{$table}}) {
            foreach my $notnull (keys %{$alter_field_notnull{$table}{$field}}) {
                if(!check_table_field_default($table,$field,$notnull,2)) {  # 2 is the null/not null column definition
                    $value = $alter_field_notnull{$table}{$field}{$notnull};
                    $query = "ALTER TABLE $table CHANGE $field $field $value";
                    print "$query\n";

                    $sth = $dbh->prepare($query);
                    $sth->execute();
                    $sth->finish;
                }
            }
        }
    }

    # Update table indexes if needed

    my %check_index;

    $check_index{'queue_stats_mv'}{'ev'}{'event'}="ALTER TABLE queue_stats_mv ADD INDEX ev (event)";
    $check_index{'queue_stats_mv'}{'fecha'}{'datetime'}="ALTER TABLE queue_stats_mv ADD INDEX fecha (datetime)";
    $check_index{'queue_stats_mv'}{'uni'}{'uniqueid'}="ALTER TABLE queue_stats_mv ADD INDEX uni (uniqueid)";
    $check_index{'queue_stats_mv'}{'runi'}{'real_uniqueid'}="ALTER TABLE queue_stats_mv ADD INDEX runi (real_uniqueid)";
    $check_index{'queue_stats_mv'}{'pidx'}{'real_uniqueid,id'}="ALTER TABLE queue_stats_mv ADD INDEX pidx (real_uniqueid,id)";

    $check_index{'queue_stats'}{'unico'}{'uniqueid,datetime,qname,qagent,qevent'}="ALTER TABLE queue_stats ADD INDEX unico (uniqueid,datetime,qname,qagent,qevent)";
    $check_index{'queue_stats'}{'ixevent'}{'qevent'} = "ALTER TABLE queue_stats ADD INDEX ixevent (qevent)";
    $check_index{'queue_stats'}{'ixdate'}{'datetime'} = "ALTER TABLE queue_stats ADD INDEX ixdate (datetime)";
    $check_index{'queue_stats'}{'ixuni'}{'uniqueid'} = "ALTER TABLE queue_stats ADD INDEX ixuni (uniqueid)";
    $check_index{'queue_stats'}{'ixagent'}{'qagent'} = "ALTER TABLE queue_stats ADD INDEX ixagent (qagent)";
    $check_index{'queue_stats'}{'combieventuni'}{'qevent,uniqueid'} = "ALTER TABLE queue_stats ADD INDEX combieventuni (qevent,uniqueid)";

    #$check_index{'queue_stats'}{'combi'}{'uniqueid,datetime,queue_stats_id'} = "ALTER TABLE queue_stats ADD INDEX combi (uniqueid,datetime,queue_stats_id)";

    foreach my $table (keys %check_index) {
        foreach my $idx (keys %{$check_index{$table}}) {
            foreach my $fields (keys %{$check_index{$table}{$idx}}) {
                my $ret = check_table_index($table,$idx,$fields);
                if($ret>0) {
                     print "Index $idx for table $table needs to be recreated...\n";
                     my $query = "ALTER TABLE $table DROP INDEX $idx";
                     $sth = $dbh->prepare($query);
                     $sth->execute();
                     $sth->finish;
                     $query = $check_index{$table}{$idx}{$fields};
                     $sth = $dbh->prepare($query);
                     $sth->execute();
                     $sth->finish;
                }
            }
        }
    }
}

sub check_table_index {
    my $table  = shift;
    my $index  = shift;
    my $flds   = shift;

    my $devuelvo = 0;
    my @fldsarray = split(/,/,$flds);        

    $sth = $dbh->prepare("SHOW INDEX FROM $table");
    $sth->execute();
    my @fields_for_index;
    while ( my @inparray = $sth->fetchrow_array() ) {
        my $idxname = $inparray[2];
        my $idxfield = $inparray[4];
        if($index eq $idxname) {
            push @fields_for_index,$idxfield;
        }
    }
    my %fields = map { $_ => 1 } @fields_for_index;
    foreach my $ele (@fldsarray) {
        if(!defined($fields{$ele})) {
            print "Missing field $ele on index $index for table $table!\n";
            $devuelvo++;
        }
    }
    $sth->finish;

    return $devuelvo;

}

sub check_table_exists {
    my $table  = shift;
    my $exists = 0;
    $sth = $dbh->prepare("SHOW TABLES LIKE '$table'");
    $sth->execute();
    while($sth->fetch()) {
        $exists=1;
    }
    return $exists;
}

sub check_table_field {

    my $table  = shift;
    my $field  = shift;
    my $exists = 0;

    $sth = $dbh->prepare("SHOW COLUMNS FROM $table");
    $sth->execute();

    while ( my @inparray = $sth->fetchrow_array() ) {
        if($inparray[0] eq $field) {
            $exists=1;
        }
    }
    $sth->finish;

    return $exists;
}

sub check_table_field_default {

    my $table    = shift;
    my $field    = shift;
    my $default  = shift;
    my $rowpos   = shift;
    my $exists = 0;

    $sth = $dbh->prepare("SHOW COLUMNS FROM $table");
    $sth->execute();

    while ( my @inparray = $sth->fetchrow_array() ) {
        if(!defined($inparray[$rowpos])) {
            $inparray[$rowpos]='undef';
        }
        if($inparray[0] eq $field && $inparray[$rowpos] eq $default) {
            $exists=1;
        }
    }
    $sth->finish;
    return $exists;

}

sub initial_load() {
    print "Reading lines from ".$config{'logfile'}."\n";
    open( EVENTS, "<$config{'logfile'}" );
    while (<EVENTS>) {
        chomp;
        procesa($_);
    }
    close(EVENTS);
}

sub connect_db() {
    my $return = 0;
    my %attr   = (
        mysql_enable_utf8 => 1,
        PrintError => 0,
        RaiseError => 0,
    );
    my $dsn = "DBI:mysql:database=$config{'dbname'};host=$config{'dbhost'}";
    print "Connecting to DB $dsn\n";
    $dbh->disconnect if $dbh;
    $dbh = DBI->connect( $dsn, $config{'dbuser'}, $config{'dbpass'}, \%attr ) or $return = 1;
    return $return;
}

sub check_queue {

    $queue_name = shift;

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

    if ( exists( $queuecache{$queue_name} ) ) {
        return $queuecache{$queue_name};
    }

    if ( $conectado == 1 ) {
        $sth = $dbh->prepare("SELECT queue_id FROM qname WHERE queue=?");
        $sth->execute($queue_name);
        my @result  = $sth->fetchrow_array;
        my $cuantos = @result;
        $sth->finish;

        if ($cuantos) {
            $queue_id = $result[0];
        }
        else {
            $sth = $dbh->prepare("INSERT INTO qname (queue) VALUES (?)");
            $sth->execute($queue_name);
            $queue_id = $dbh->{q{mysql_insertid}};
        }
        $queuecache{$queue_name} = $queue_id;
        return $queue_id;
    }
}

sub set_agent_names { 
    print "Setting agent names via asterisk database show\n";
    %nombreagente = ();
    open(PS,"/usr/sbin/asterisk -rx 'database show ampuser' | ") || warn "Failed: $!\n";
    while ( <PS> ) {
        chop;
        if ( /cidname/) {
            my ($numpart,$nom) = split(/: /);
            my (undef,undef,$num) = split(/\//,$numpart);
            my $canlage = "Local/$num\@from-queue/n";
            $nom =~ s/\s+$//g;
            $nombreagente{$canlage} = $nom;
        }
    }
    close(PS);
}

sub check_event {
    $event = shift;

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

    if ( exists( $event_hash{$event} ) ) {
        $event_id = $event_hash{$event};
    }
    else {

        # Try harder to find the event
        print "No existe el evento $event, pruebo de nuevo\n";
        &set_events();

        if ( exists( $event_hash{$event} ) ) {
            print "Por suerte lo encontro\n";
            $event_id = $event_hash{$event};
        }
        else {
            $sth = $dbh->prepare("INSERT INTO qevent (event) VALUES (?)");
            $sth->execute($event);
            $event_id = $dbh->{q{mysql_insertid}};
            $event_hash{$event} = $event_id;
        }
    }
    return $event_id;
}

sub check_agent {
    $agent_name = shift;

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

    $agent_name =~ s/\s+$//;
    $agent_name =~ s/^\s+//;

    if ( $agent_name =~ /^Local/ ) {
        $agent_name =~ s/^Local\///g;
        @partes = split( /\@/, $agent_name, 2 );
        $agent_name = $partes[0];
        if(defined($nombreagente{"Local/$agent_name\@from-queue/n"})) {  
            $agent_name = $nombreagente{"Local/$agent_name\@from-queue/n"};
        }
    }

    if ( $agent_name =~ /^\d+$/ ) {
        $agent_name = "Agent/" . $agent_name;
    }

    if ( exists( $agentcache{$agent_name} ) ) {
        #print "Check Agent: agent $agent_name exists in cache = " . $agentcache{$agent_name} . "\n";
        return $agentcache{$agent_name};
    }

    #print "Check Agent: agent $agent_name is not in cache, query database\n";

    $sth = $dbh->prepare("SELECT agent_id FROM qagent WHERE agent=?");
    $sth->execute($agent_name);
    my @result  = $sth->fetchrow_array;
    my $cuantos = @result;
    $sth->finish;

    if ($cuantos) {
        $agent_id = $result[0];
        #print "Check Agent: Agent $agent_name found on database with id $agent_id\n";
    }
    else {
        $sth = $dbh->prepare("INSERT INTO qagent (agent) VALUES (?)");
        $sth->execute($agent_name);
        $agent_id = $dbh->{q{mysql_insertid}};
        #print "Check Agent: NOT found on database inserting $agent_id\n";
        #print "Check Agent: $query\n";
    }
    if ( !$dbh->err() ) {
        #print "Check Agent: Adding agent $agent_name to cache with id $agent_id\n";
        $agentcache{$agent_name} = $agent_id;
    }
    else {
        #print "Check Agent: Error doing database check, unable to set agent $agentname in cache.\n";
        $agent_id = -1;
    }
    return $agent_id;
}

sub return_timestamp {
    my $date_string = shift;
    my ( $year, $month, $day, $hour, $min, $sec ) = split( /[-: ]/, $date_string, 6 );
    $year = $year - 1900;
    $month--;
    my $u_timestamp = timelocal( $sec, $min, $hour, $day, $month, $year );
    return $u_timestamp;
}

sub set_events {
    if ( $DBI::err ne "2002" ) {

        %event_hash = ();

        # Populates an array with the EVENTS ids
        $query = "SELECT * FROM qevent ORDER BY event_id";
        $sth   = $dbh->prepare($query);
        $sth->execute;
        while ( my @row = $sth->fetchrow ) {
            $event_hash{ $row[1] } = $row[0];
        }

        %queuecache = ();
        %agentcache = ();
    }
}

sub handle_error {
    $error       = shift;
    $errorstring = shift;
    $linea       = shift;
    if ( $error == "2006" ) {
        print "Lost connection... save $linea\n";
        if ( open( LOG, ">> /var/log/asterisk/queue_log_failed" ) ) {
            print LOG "$linea\n";
            close(LOG);
        }
        &reconecta();
    }
    else {
        print "Record not inserted, error: $errorstring\n";
    }
}

sub first_queue_log_event_ts {
    open( EVENTS, "<$config{'logfile'}" );
    my $firstline = <EVENTS>;
    close(EVENTS);
    my ( @parametros) = split( /\|/, $firstline );
    $first_event_ts = $parametros[0];
    return $first_event_ts;
}

sub last_event {
    return if $reparse;
    return if $destructivereparse;
    # Select the most recent event saved
    $query = "SELECT datetime FROM queue_stats ORDER BY datetime DESC LIMIT 1";
    $sth   = $dbh->prepare($query);
    $sth->execute;
    my @result  = $sth->fetchrow_array;
    my $cuantos = @result;
    $sth->finish;

    if ( $cuantos > 0 ) {
        print "Last entry in database: $result[0]\n";
        $last_event_ts = return_timestamp( $result[0] );
        print "Last entry timestamp: $last_event_ts\n";
        $last_event_ts -= $offset_seconds;
    }
    else {
        $last_event_ts = 0;
    }
}


sub procesa {

    my $max_infos = 5;
    my @extra;

    my $linea = shift;


    my ( @parametros) = split( /\|/, $linea );

    if ($#parametros < 4 ) {
        print $linea. "\n";
        print "Skip: Invalid line. Missing fields.\n";
        return;
    }

#    print $linea."\n";

    my $date       = shift(@parametros);
    my $uniqueid   = shift(@parametros);
    my $queue_name = shift(@parametros);
    my $agent      = shift(@parametros);
    my $event      = shift(@parametros);

    if ( $date < $last_event_ts ) {
        return;
    }

    my @newparametros;

    foreach my $run (@queuelog_transform) {
        ($date,$uniqueid,$queue_name,$agent,$event,@newparametros) = $run->($date,$uniqueid,$queue_name,$agent,$event,@parametros);
        if($#parametros>=0) {
            @parametros = @newparametros;
        }
    }

    my $last_info_field = "";

    if ( $date !~ /^[0-9]/) {
        print $linea. "\n";
        print "Skip: Invalid Timestamp ($date)\n";
        return;
    }

    my $infoqr = "";
    my $repqr  = "";
    my $cuantos_infos = $#parametros + 1;

    if($cuantos_infos > $max_infos) {
        my $sacar_infos = $cuantos_infos - $max_infos;
        for($a=1;$a<=$sacar_infos;$a++) {
            pop @parametros;
        }
        $cuantos_infos = $max_infos;
    }

    for($a=1;$a<=$cuantos_infos;$a++) {
       $last_info_field="info$a";
       $infoqr.=",$last_info_field";
       $repqr.=",?";
    }


    if ( $event eq "PAUSEALL" ) {
        return;
    } elsif ( $event eq "UNPAUSEALL" ) {
        return;
    } elsif ( $event eq "UPDATEFIELD" ) {

        # Update ENTERQUEUE field based on custom UPDATEFIELD queue_log event for Tag Calls and similar
        my ($value,$field) = split(/~/,$parametros[0]);
        $sth = $dbh->prepare(qq{
            UPDATE queue_stats JOIN qevent ON qevent=event_id SET datetime=datetime, $field = ? WHERE uniqueid = ? AND event='ENTERQUEUE'
        });
        $sth->execute($value, $uniqueid) or handle_error( $dbh->err(), $dbh->errstr(), $linea );

        $sth = $dbh->prepare(qq{
            UPDATE queue_stats_mv SET datetime=datetime, $field = ? WHERE real_uniqueid = ?
        });
        $sth->execute($value, $uniqueid) or handle_error( $dbh->err(), $dbh->errstr(), $linea );

    } elsif ( $event eq "UPDATE" ) {
        $value = $parametros[0];
        $table = $queue_name;
        $field = $agent;
        $field =~ s/~/,/g;

        if($table eq "queue_stats_mv") {
            $sth = $dbh->prepare(qq{
                UPDATE $table SET $field=? WHERE real_uniqueid=?
            });
        } else {
            $sth = $dbh->prepare(qq{
                UPDATE $table SET $field=? WHERE uniqueid=?
            });
        }
        $sth->execute($value, $uniqueid) or handle_error( $dbh->err(), $dbh->errstr(), $linea );
        return;
    } elsif ( $event eq "INSERT" ) {
        $value = $parametros[0];
        $table = $queue_name;
        $field = $agent;
        $field =~ s/~/,/g;

        $sth = $dbh->prepare(qq{
            INSERT INTO $table ($field,uniqueid) VALUES ($value,?)
        });
        $sth->execute($uniqueid) or handle_error( $dbh->err(), $dbh->errstr(), $linea );
        return;

    } elsif ( $event eq "FREEINSERT" ) {

        my @timeData = localtime($date);
        my $sec      = $timeData[0];
        my $min      = $timeData[1];
        my $hour     = $timeData[2];
        my $day      = $timeData[3];
        my $month    = $timeData[4] + 1;
        my $year     = $timeData[5] + 1900;
        my $dateu = "$year-$month-$day $hour:$min:$sec";

        $table  = $parametros[0];
        @fields = split(/~/,$parametros[1]);
        @values = split(/~/,$parametros[2]);
        $myfields = join("`,`",@fields);
        $myvalues = join("','",@values);
        $sth = $dbh->prepare(qq{
            INSERT INTO $table (`uniqueid`,`queue`,`datetime`,`$myfields`) VALUES (?,?,?,'$myvalues')
        });
        $sth->execute($uniqueid,$queue_name,$dateu) or handle_error( $dbh->err(), $dbh->errstr(), $linea );
        return;

    } elsif ( $event eq "FREEUPDATE" ) {
        $table  = $parametros[0];
        @fields = split(/~/,$parametros[1]);
        @values = split(/~/,$parametros[2]);
        $query = "UPDATE $table SET ";

        for (my $i = 0; $i < scalar(@fields); $i++) {
            $query .= "`$fields[$i]`='$values[$i]'";
            $p = scalar(@fields) -1;
            if ($i < $p ) {
                $query .= ", ";
            }
        }
        $query.= " WHERE uniqueid=?";
        $sth = $dbh->prepare(qq{
            $query
        });
        $sth->execute($uniqueid) or handle_error( $dbh->err(), $dbh->errstr(), $linea );
        return;


    } elsif ( $event eq "INFO" ) {

        $infoevent = $parametros[0];
        $value     = $parametros[4];

        if($infoevent eq "TAG") {

            $sth = $dbh->prepare(qq{
                UPDATE queue_stats JOIN qevent ON qevent=event_id SET datetime=datetime, info5 = ? WHERE uniqueid = ? AND event='ENTERQUEUE'
            });
            $sth->execute($value, $uniqueid) or handle_error( $dbh->err(), $dbh->errstr(), $linea );
 
        }

    } elsif ( $event eq "UPDATETRANSFER" ) {

        my $destexten   = $parametros[0];
        my $destcontext = $parametros[1];

        my @timeData = localtime($date);
        my $sec      = $timeData[0];
        my $min      = $timeData[1];
        my $hour     = $timeData[2];
        my $day      = $timeData[3];
        my $month    = $timeData[4] + 1;
        my $year     = $timeData[5] + 1900;
        my $dateu = "$year-$month-$day $hour:$min:$sec";

        $sth = $dbh->prepare(qq{
            UPDATE queue_stats JOIN qevent ON qevent=event_id SET datetime=datetime,qevent=(SELECT event_id FROM qevent WHERE event='TRANSFER'),info5=info3,info4=info2,info3=info1,info2 = ?,info1 = ? WHERE uniqueid = ? AND event IN ('COMPLETECALLER','COMPLETEAGENT') AND datetime <= ?
        });
        $sth->execute($destcontext, $destexten, $uniqueid, $dateu) or handle_error( $dbh->err(), $dbh->errstr(), $linea );

    } elsif ( $event eq "BLINDTRANSFER" || $event eq "ATTENDEDTRANSFER" || $event eq "TRANSFER") {
        $event = 'TRANSFER';

        $uniqueid_xfer = $uniqueid."_xfer";
        $uniqueid_xfer = $uniqueid;
        $sth = $dbh->prepare(qq{
            UPDATE queue_stats SET uniqueid = ?,datetime=datetime WHERE uniqueid = ? 
        });
        $sth->execute($uniqueid_xfer, $uniqueid) or handle_error( $dbh->err(), $dbh->errstr(), $linea );

        $uniqueid = $uniqueid_xfer;

    } elsif ( $event eq "DID") {

        # Update ENTERQUEUE with DID information for FreePBX >2.10
        $didhash{$uniqueid}=$parametros[0];

    } elsif ( $event eq "URL") {

        # Update ENTERQUEUE with URL information
        $urlhash{$uniqueid}=$parametros[0];

    } elsif ( $event eq "ENTERQUEUE" ) {

        # If we had a previous DID event, replicate info1 field into enterqueue for Asternic URL
        #
        if(defined($didhash{$uniqueid})) {
            my $cuantos = $#parametros;
            my $fillgap = 2 - $cuantos;

            # If the ENTERQUEUE event lacks info1, info2 and info3, we fill them up
            if($fillgap>0) {
                for(my $a=0;$a<$fillgap;$a++) {
                    my $indextofill = $a + 2;
                    my $indextofield = $a + 3;
                    $parametros[$indextofill]='';
                    $infoqr.=",info$indextofield";
                    $repqr.=",?";
                }
            }

            push @extra, "UPDATE queue_stats_mv SET datetime=datetime,did='".$didhash{$uniqueid}."' WHERE real_uniqueid='$uniqueid'";

            if(substr($last_info_field,-1) eq "3") {
                $parametros[3] = $didhash{$uniqueid};
                $infoqr.=",info4";
                $repqr.=",?";
            }

            delete $didhash{$uniqueid};

        }

        if(defined($urlhash{$uniqueid})) {
            $parametros[0] = $urlhash{$uniqueid};
            push @extra, "UPDATE queue_stats_mv SET datetime=datetime,url='".$urlhash{$uniqueid}."' WHERE real_uniqueid='$uniqueid'";
            delete $urlhash{$uniqueid};
        }

    } elsif ( $event eq "RINGNOANSWER" ) {

        # Skip insertion of RINGNOANSWER events with 0 seconds duration
        if ( $parametros[0] eq "0" ) {
            return;
        }
    } elsif ( $event eq "CONFIGRELOAD" ) {
       
        # Set agent names on FreePBX if convertlocal is set
        &set_agent_names() if $convertlocal;
    }

    if ( $skip == 1 ) {
        if ( $agent =~ /^SIP/i || $agent =~ /^IAX/i) {
            return;
        }
    }

    if($triggerscript ne '') {
        print "executing: $triggerscript $date '$queue_name' '$agent' '$event' $uniqueid\n";
        system("$triggerscript $date '$queue_name' '$agent' '$event' $uniqueid </dev/null >/dev/null 2>&1 &");
    }

    my @timeData = localtime($date);
    my $sec      = $timeData[0];
    my $min      = $timeData[1];
    my $hour     = $timeData[2];
    my $day      = $timeData[3];
    my $month    = $timeData[4] + 1;
    my $year     = $timeData[5] + 1900;

    my $dateu = "$year-$month-$day $hour:$min:$sec";

    $queue_id = check_queue($queue_name);
    $agent_id = check_agent($agent);
    $event_id = check_event($event);

    if($queue_name ne "" & $agent ne "") {

        my $printquery = join("','",@parametros);

        if($printquery ne "") {
            print "INSERT INTO queue_stats (uniqueid, datetime, qname, qagent, qevent$infoqr) VALUES ('$uniqueid','$dateu','$queue_id','$agent_id','$event_id','$printquery')\n";
        } else {
            print "INSERT INTO queue_stats (uniqueid, datetime, qname, qagent, qevent$infoqr) VALUES ('$uniqueid','$dateu','$queue_id','$agent_id','$event_id')\n";
        }

        $sth = $dbh->prepare(qq{
            INSERT INTO queue_stats (uniqueid, datetime, qname, qagent, qevent$infoqr) VALUES (?,?,?,?,?$repqr);
        });
        $sth->execute($uniqueid, $dateu, $queue_id, $agent_id, $event_id, @parametros) or handle_error( $dbh->err(), $dbh->errstr(), $linea );

    } else { 
        print $linea. "\n";
        print "Skip: Queue or Agent empty\n"; 
    }

    foreach (@extra) {
        $sth = $dbh->prepare(qq{
             $_
        });
        $sth->execute() or handle_error( $dbh->err(), $dbh->errstr(), $linea );
#        print  $_."\n";
    }
    @extra = ();
}

# STARTING

# Check if its running
if(-f $pidfile && !$reparse) {
    print "Already running! Aborting...\n";
    exit;
}

if($daemon) {
    &daemonize();
} else {
    # write pid when not daemonized too
    open my $mypidfile, q{>}, $pidfile or die "Failed to open PID file $pidfile for writing.";
    print $mypidfile $$;
    close $mypidfile;
}

&reconecta();
&set_agent_names() if $convertlocal;
&check_tables();
&delete_reparse_230();
&last_event();
&populate_helper_tables();
&repairdb() if !$skiprepair;
&initial_load();

if($reparse && !$daemon) {
   exit;

} else {

    $file = File::Tail->new( name=>$config{'logfile'}, maxinterval=>5 );

    while ( defined( $message = $file->read ) ) {
        next unless defined $message;
        chomp $message;
        procesa($message);
    }
}

sub usage {
    print STDERR "asternicloglog [<options>] \n";
    print STDERR "       -u <name>     - Connect to mysql as username <name> [root]\n";
    print STDERR "       -p <pw>       - Connect to mysql with password <pw>\n";
    print STDERR "       -h <host>     - Connect to mysql host <host> [localhost]\n";
    print STDERR "       -d <dbname>   - Connect to mysql database <dbname> [qstats]\n";
    print STDERR "       -l <queuelog> - Path and name for queue_log [/var/log/asterisk/queue_log]\n";
    print STDERR "       -c            - Convert Local/xxx\@from-queue/n to agent name in FreePBX\n";
    print STDERR "       -r            - Reparse the full log with no date check\n";
    print STDERR "       -z            - Reparse the full log with no date check, *removing* DB data older than first log line\n";
    print STDERR "       -s            - Skip events with SIP/IAX in queue member\n";
    print STDERR "       -g            - Specify a log directory to write debug messages when daemonized\n";
    print STDERR "       -nr           - Skip table repair at startup\n";
    print STDERR "       --daemon      - Daemonize process and detach from console\n";
    print STDERR "       -t <script>   - Full path for a trigger shell script for custom hooks/actions\n";
    print STDERR "       -w            - Write configuration to disk\n";
    print STDERR "       --purge       - Purge all data from tables and exit\n";
    print STDERR "       --repair      - Repair tables and exit\n";
    exit;
}

sub delete_reparse_230() {
    if($destructivereparse) {
        $reparse=1;
        if(check_table_exists('queue_stats_mv') && check_table_field('queue_stats_mv','real_uniqueid')) {
            print "Removing old elements from tables before reparsing...\n";
            my $first = first_queue_log_event_ts();
            $query = "DELETE FROM queue_stats_mv WHERE unix_timestamp(datetime)>='$first'";
            $dbh->do($query);
            $query = "DELETE FROM queue_stats WHERE unix_timestamp(datetime)>='$first'";
            $dbh->do($query);
            $query = "DELETE FROM agent_activity WHERE unix_timestamp(datetime)>='$first'";
            $dbh->do($query);
        }
    }
}


