#!/usr/bin/perl
use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/../lib";
use File::Basename qw(basename);
use File::Spec;
use Fcntl qw(O_CREAT O_EXCL O_WRONLY);
use Getopt::Long qw(GetOptions);
use JSON::PP;
use Siru::DesdeDat;

my ($rk, $directorio, $calcula, $bibliotecas, $ayuda);
$directorio = '.';
GetOptions('rk=i' => \$rk, 'directorio=s' => \$directorio,
    'calcula=s' => \$calcula, 'bibliotecas=s' => \$bibliotecas, 'ayuda|help' => \$ayuda)
    or die "Uso: $0 [--rk N] [--directorio DIR] CIRCUITO.dat\n";
if ($ayuda) {
    print "Uso: $0 [--rk N] [--directorio DIR] CIRCUITO.dat\n";
    exit 0;
}
die "Uso: $0 [--rk N] [--directorio DIR] CIRCUITO.dat\n" unless @ARGV == 1;
my $archivo = $ARGV[0];
my $nombre = basename($archivo);
die "Se esperaba un .dat\n" unless $nombre =~ s/\.dat\z//i;
die "Nombre de archivo invalido\n" unless $nombre =~ /\A[A-Za-z][A-Za-z0-9_-]*\z/;
my $fuente = Siru::DesdeDat->leer($archivo);
if (!defined $rk) {
    my $elegidos = $fuente->{dat}{GLOBAL}{control}{RK}{value};
    die "El .dat no elige RK; indique --rk N\n"
        unless ref($elegidos) eq 'ARRAY' && @$elegidos;
    $rk = $elegidos->[0];
}
die "Numero RK invalido\n" unless defined($rk) && $rk =~ /\A\d+\z/;
my $base = File::Spec->catfile($directorio, "$nombre.din");
my $ampliado = File::Spec->catfile($directorio, "$nombre-ED$rk.din");
my $texto_base = $fuente->base();
my $texto_rk = $fuente->ampliado($rk);
my $completo = !@{$fuente->{pendientes}};
for my $ruta ($base, $ampliado) {
    die "El archivo ya existe: $ruta\n" if -e $ruta;
}
$calcula //= File::Spec->catfile($FindBin::Bin, '..', '..', '..', 'calcula', 'calcula-6.0', 'src', 'calcula');
$bibliotecas //= File::Spec->catdir($FindBin::Bin, '..', '..', '..', 'calcula', 'calcula-6.0', 'src', '.libs');
my $configuracion = $completo ? $fuente->configuracion(
    File::Spec->rel2abs($ampliado), File::Spec->rel2abs($calcula),
    File::Spec->rel2abs($bibliotecas), File::Spec->rel2abs(File::Spec->catfile($directorio, "$nombre-ED$rk.csv")), $rk)
    : undef;
sub escribir {
    my ($ruta, $contenido) = @_;
    sysopen my $fh, $ruta, O_WRONLY | O_CREAT | O_EXCL
        or die "No se pudo crear $ruta: $!\n";
    # decode_json devolvio caracteres; sin esta capa Perl escribe el byte
    # interno y una o acentuada del .dat salia como un 0xF3 solo, que no es
    # UTF-8 valido. El .dat esta en UTF-8 y el .din tiene que quedar igual.
    binmode $fh, ':encoding(UTF-8)' or die "No se pudo poner UTF-8 en $ruta\n";
    print {$fh} $contenido or die "No se pudo escribir $ruta: $!\n";
    close $fh or die "No se pudo cerrar $ruta: $!\n";
}
# La corrida va en el .din, en sus secciones de texto llano comentadas (las
# que lee siru, las mismas que escribe slex/d2datdinc): corrida,
# adaptacion, parametros y estados. Sin JSON y sin rutas.
if ($completo) {
    my $n = sub { sprintf('%.17g', $_[0]) };
    my @s = ('', '# corrida', map({ "#   $_ " . $n->($configuracion->{$_}) } qw(desde hasta paso)));
    if (my $a = $configuracion->{adaptacion}) {
        push @s, '', '# adaptacion', "#   metodo $a->{metodo}",
            map { "#   $_ " . $n->($a->{$_}) } grep { exists $a->{$_} }
                qw(orden_error absoluto relativo paso_min paso_max);
    }
    push @s, '', '# parametros',
        map { "#   $_ " . $n->($configuracion->{parametros}{$_}) } sort keys %{$configuracion->{parametros}};
    push @s, '', '# estados',
        map { "#   $_->{actual} $_->{siguiente} " . $n->($_->{inicial}) . ' ' . ($_->{estimacion} // '-') }
            @{$configuracion->{estados}};
    $texto_rk .= join("\n", @s) . "\n";
}
escribir($base, $texto_base);
escribir($ampliado, $texto_rk);
print "$base\n$ampliado\n";
if (!$completo) {
    warn "El .dat tiene " . scalar(@{$fuente->{pendientes}}) .
        " elementos PENDIENTE comentados; no se genero configuracion ejecutable.\n";
}
