#!/usr/bin/perl

# ---------------------------------------------------------------
# Prontus CMS
# http://www.prontus.cl
# by Altavoz.net
#
# licensed under LGPL license.
# http://www.prontus.cl/license.html
# ---------------------------------------------------------------

#
# -----------------------COMENTARIO GLOBAL-----------------------
# ---------------------------------------------------------------
# PROPOSITO
# ---------
# CGI encargada de descargar el CSV de respaldo
#
# ---------------------------------------------------------------
use strict;
use utf8;

BEGIN {
    use FindBin qw($Bin);
    my $pathLibsProntus = $Bin;
    unshift(@INC,$pathLibsProntus);
}

use lib_prontus;
# Captura STDERR
use lib_stdlog;
&lib_stdlog::set_stdlog($0, 51200);
use prontus_varglb; &prontus_varglb::init();

use glib_fildir_03;
use glib_cgi_05;

use lib_form;

use Encode qw(decode encode);
use JSON;
use Data::Dumper;

# variables globales

main: {
    &lib_prontus::setUtf8();

    $prontus_varglb::PRONTUS_ID = $ARGV[0];
    my $TS        = $ARGV[1];
    my $ENCODING  = $ARGV[2];
    my $filter_date  = $ARGV[3] || 0;
    my $start_date  = $ARGV[4];
    my $end_date  = $ARGV[5];

    if (scalar @ARGV < 2) {
        print STDERR "Intento de invocación sin los parámetros indispensables.\n";
        print "Uso: perl $0 {prontus_id} {form_timestamp}\n";
        exit;
    }

    if ($prontus_varglb::PRONTUS_ID eq '' || !&lib_prontus::valida_prontus($prontus_varglb::PRONTUS_ID)) {
        print STDERR "Directorio Prontus no es válido [$prontus_varglb::PRONTUS_ID]\n";
        exit;
    }

    # Carga variables de configuracion.
    my $msg_load = &lib_prontus::load_config_by_id($prontus_varglb::PRONTUS_ID);
    if ($msg_load ne '') {
        print STDERR "Error: $msg_load\n";
    }

    # Se comprueba que venga el TS del artículo
    if ($TS !~ /\d{14}/) {
        print STDERR "El parámetro TS no es válido [$TS]\n";
        exit;
    }

    if ($filter_date) {
        if ($start_date !~ /\d{6}/) {
            print STDERR "El parámetro start_date no es válido [$start_date]\n";
            exit;
        } else {
            $start_date = substr($start_date, 4, 4) . substr($start_date, 2, 2) . substr($start_date, 0, 2);
        }
        if ($end_date !~ /\d{6}/) {
            print STDERR "El parámetro end_date no es válido [$end_date]\n";
            exit;
        } else {
            $end_date = substr($end_date, 4, 4) . substr($end_date, 2, 2) . substr($end_date, 0, 2);
        }
    }

    # Si viene el parametro se asigna a la variable global.
    if ($ENCODING ne '') {
        $prontus_varglb::FORM_CSV_CHARSET = $ENCODING;
        $prontus_varglb::CONFIG{$prontus_varglb::PRONTUS_ID}{'FORM_CSV_CHARSET'} = $prontus_varglb::FORM_CSV_CHARSET;
    }

    # Se revisa que el archivo de "orden" exista
    my $DIRFORM = "/$prontus_varglb::PRONTUS_ID/cpan/procs/form/$TS";
    if (! -d "$prontus_varglb::DIR_SERVER$DIRFORM") {
        print STDERR "No existe el directorio de datos [$prontus_varglb::DIR_SERVER$DIRFORM]\n";
        exit;
    }

    my $status_file = "$prontus_varglb::DIR_SERVER$DIRFORM/status.json";

    &glib_fildir_03::write_file($status_file, '{"status":1, "msg":"procesando"}');

    my $CSV;
    my $ORDERFILE  = "order.json";
    my $BACKUPFILE  = "backup.csv";
    if (!(-f "$prontus_varglb::DIR_SERVER$DIRFORM/$ORDERFILE")) {
        if (!(-f "$prontus_varglb::DIR_SERVER$DIRFORM/$BACKUPFILE")) {
        # Si el order no existe, se  revisa que el archivo de respaldo exista
            print STDERR "El archivo de datos está vacío o no existe\n";
            &glib_fildir_03::write_file($status_file, '{"status":2, "msg": "error al generar archivo de descarga"}');
            exit;
        }
        $CSV = &glib_fildir_03::read_file("$prontus_varglb::DIR_SERVER$DIRFORM/$BACKUPFILE");
    } else {
        my $jsonorder = &glib_fildir_03::read_file_bin("$prontus_varglb::DIR_SERVER$DIRFORM/$ORDERFILE");
        my $orderhashref = decode_json($jsonorder);
        my %orderhash = %$orderhashref;

        my @orderreal;
        push(@orderreal, '_fecha');
        push(@orderreal, '_hora');
        push(@orderreal, '_ip');
        foreach my $index (sort { $a <=> $b} keys %orderhash) {
            push(@orderreal, $orderhash{$index});
        }

        my %newheader;
        my $newheaderorder = 0;

        my @files =  &glib_fildir_03::lee_dir("$prontus_varglb::DIR_SERVER$DIRFORM");
        my %orderreal_values; # para check de unicidad de ítems en encabezados.
        foreach my $file (sort @files) {
            next unless($file =~ /(\d{8})\d{6}\.json$/);
            my $day_date = $1;
            if ($filter_date && ($day_date < $start_date || $day_date >= $end_date)) {
                next;
            }

            my $json = &glib_fildir_03::read_file("$prontus_varglb::DIR_SERVER$DIRFORM/$file");
            next if ($json !~ /^\{.+\}$/);

            # quita caracteres encodeados como codigo unicode ya que no son visibles y causan problemas de compatibilidad
            $json =~ s/\\u[0-9a-fA-F]{4}//g;

            my $jsonhashref;

            utf8::encode($json);
            eval { $jsonhashref = decode_json($json); };

            if ($@) {
                print STDERR "Error al decodificar json: $@, file[$file] json:[$json]\n";
                next;
            }
            my %jsonhash = %$jsonhashref;
            my $filesref = $jsonhash{'_files'};

            delete $jsonhash{'_files'};

            # Se recorren según el orden
            foreach my $name (@orderreal) {
                $CSV = $CSV . &lib_form::add_to_csv($jsonhash{$name});
                delete $jsonhash{$name};
            }

            # Lo que no estaba antes, se agrega ahora y se agrega al orden
            %orderreal_values = map {$_ => 1 } @orderreal;
            foreach my $name (sort keys %jsonhash) {
                $CSV = $CSV . &lib_form::add_to_csv($jsonhash{$name});
                push(@orderreal, $name) if (!$orderreal_values{$name});
            }

            # Se agregan los archivos si es que hay.
            if ($filesref) {
                my %files = %{$filesref};

                foreach my $fieldname (keys %files) {
                    my $ruta = "$prontus_varglb::CONFIG{$prontus_varglb::PRONTUS_ID}{'SERVER_PROTOCOLO_CPAN'}://$prontus_varglb::CONFIG{$prontus_varglb::PRONTUS_ID}{'CPAN_SERVER_NAME'}$files{$fieldname}";
                    $CSV = $CSV . &lib_form::add_to_csv($ruta);
                    if (!exists $newheader{$fieldname}) {
                        $newheaderorder++;
                        $newheader{$fieldname} = $newheaderorder;
                    }
                }
            }
            $CSV =~ s/$lib_form::SEPARADOR$/\n/;
        }

        foreach my $name (sort { $newheader{$a} <=> $newheader{$b} } keys %newheader) {
            push(@orderreal, $name) if (!$orderreal_values{$name});
        }

        splice(@orderreal,0,3,'Fecha','Hora','IP');
        my $headers = &lib_form::array_to_csv(@orderreal);
        $CSV = $headers . "\n". $CSV;
    }

    # reconvertimos a utf8 para eliminar caracteres invalidos
    # convierte a octetos
    utf8::encode($CSV);
    my $characters = decode('UTF-8', $CSV, Encode::FB_DEFAULT);
    $CSV     = encode('UTF-8', $characters, Encode::FB_DEFAULT);
    # convierte a caracters internos de perl
    utf8::decode($CSV);

    # eliminamos LINE SEPARATOR U+2028
    $CSV =~ s/\x{2028}//g;
    # elimina caracteres especiales unicode
    $CSV =~ s/[\x{fff0}-\x{ffff}]//g;

    # Encodeamos a latin1 si está configurado asi.
    if ($prontus_varglb::CONFIG{$prontus_varglb::PRONTUS_ID}{'FORM_CSV_CHARSET'} eq 'iso-8859-1') {
        # eliminamos caracters no iso-8859-1, > U+00FF
        $CSV =~ s/[\x{00ff}-\x{ffff}]//g;
        # reconvertimos a iso para eliminar posibles caracteres erroneos
        $CSV = encode("ISO-8859-1", $CSV, Encode::FB_DEFAULT);
    }

    my $filename = "prontus_form$TS.csv";
    &glib_fildir_03::write_file("$prontus_varglb::DIR_SERVER$DIRFORM/$filename", $CSV, $prontus_varglb::CONFIG{$prontus_varglb::PRONTUS_ID}{'FORM_CSV_CHARSET'});
    &glib_fildir_03::write_file($status_file, '{"status":0, "msg": "", "path": "'."$DIRFORM/$filename".'"}');
}
