#!/usr/bin/perl
# simplot: graficos desde documentos .ds/.d/.ds2/.dat/.paraplot y tablas
# .simul, por el PARAPLOT unico (doc/PARAPLOT-UNICO.md): d2datdinc traduce el
# pedido al modelo estructurado y Render dibuja con Gnuplot via Tabular2.
#
# El motor historico (PlotGNU, SimPlot.pm, ParaPlot.pm y el flujo
# .caj/.hashplot/.gra de Simusol) se retiro el 11/10/2026 a pedido del autor,
# una vez verificado el PARAPLOT unico con el corpus; esta en la historia de
# svn hasta esa fecha.

use warnings;
use strict;
use FindBin qw($RealBin);
# El prefijo propio tiene prioridad; funciona tambien con DESTDIR y enlaces.
use lib "$RealBin/../share/perl5";
use File::Spec;
use File::Basename qw(basename);
use Getopt::Long qw(GetOptionsFromArray);
use Pod::Usage;
use SimPlot::Dato;

# Documento: genera/ejecuta las secciones GNUPLOT de un .ds y publica sus
# resultados junto al documento (el modo de siempre, sin -graf).
if (!@ARGV || grep(/^--?(?:noX|save|salida|nombre|no-generar|no-ejecutar)(?:=|$)/,@ARGV) ||
    ((grep(/\.(?:ds|d|simul|csv|txt|paraplot)\z/i,@ARGV) || grep($_ eq '--stdin',@ARGV)) &&
     !grep(/^-(?:graf=|sinventana|noverb|nokill|outdir|noclas|i$)|^--(?:simulado|pares)/,@ARGV))) {
    require SimPlot::Documento;
    my $rc=eval {SimPlot::Documento::cli(\@ARGV)};
    if ($@) {warn $@; exit 2}
    exit $rc;
}

if (grep { $_ eq '--stdin' } @ARGV) {
    require SimPlot::Entrada;
    # En este modo no hay nombres de archivos de entrada. Las opciones de
    # presentacion siguen siendo las mismas; salida por defecto: directorio actual.
    my ($destino, @opciones);
    for (my $i=0; $i<@ARGV; ++$i) {
        my $a=$ARGV[$i];
        next if $a eq '--stdin';
        if ($a =~ /^--?outdir=(.+)$/) { $destino=$1; push @opciones,$a; }
        elsif ($a =~ /^--?outdir$/) {
            $destino=$ARGV[++$i] // die "--stdin: falta outdir\n";
            push @opciones,"-outdir=$destino";
        } elsif ($a =~ /^-(?:noverb|nokill|noclas|sinventana|graf=[2345])$/) {
            push @opciones,$a;
        } else { die "--stdin: opcion no admitida: $a\n"; }
    }
    my $r=eval { SimPlot::Entrada::recibir(\*STDIN, directorio=>$destino // '.') };
    if ($@) { warn $@; exit 2; }
    @ARGV=(@opciones,$r->{archivo});
}

if (grep {$_ eq '--pares'} @ARGV) {
    require SimPlot::Pares;
    my $rc=eval {SimPlot::Pares::ejecutar(\@ARGV)};
    if ($@) { warn $@; exit 2; }
    exit $rc;
}

# Siru puede numerar la salida o recibir --salida. La fuente conserva sus
# RESULTADOS/PARAPLOT, pero su tabla debe ser la de esta corrida.
my $simulado;
my @argumentos;
while (@ARGV) {
    my $a = shift @ARGV;
    if ($a eq '--simulado' || $a =~ /^--simulado=/) {
        die "--simulado repetido\n" if defined $simulado;
        $simulado = $a eq '--simulado' ? shift @ARGV : substr($a, 11);
        die "--simulado necesita un archivo existente\n" unless defined($simulado) && -f $simulado;
        $simulado = File::Spec->rel2abs($simulado);
    } else { push @argumentos, $a; }
}
@ARGV = @argumentos;

# Las opciones del modo -graf: las historicas que siguen teniendo sentido.
# -nokill y -noclas se aceptan y no hacen nada (guiones viejos); -kill se
# rechaza: no hay registro de procesos propios y nunca se matan los ajenos.
my ($graf, $outdir, %op) = (3, undef);
Getopt::Long::Configure('no_ignore_case', 'bundling_override');
GetOptionsFromArray(\@ARGV,
    'graf=i'      => \$graf,
    'outdir=s'    => \$outdir,
    'i'           => \$op{i},
    'sinventana'  => \$op{sinventana},
    'noverb'      => \$op{noverb},
    'nokill'      => sub {},
    'noclas'      => sub {},
    'kill'        => \$op{kill},
    'h|help'      => sub { pod2usage(-verbose => 2, -exitval => 0) },
    'v|version'   => sub { print "simplot 2.0 (PARAPLOT unico)\n"; exit 0 },
) or pod2usage(-verbose => 0, -exitval => 2);
if ($op{kill}) {
    warn "Simplot: -kill deshabilitado; cierre las ventanas deseadas manualmente.\n";
    exit 2;
}
pod2usage(-verbose => 0, -exitval => 2,
          -message => "simplot: indicar documentos (.ds, .d, .dat, .paraplot) o tablas (.simul)\n")
    unless @ARGV;

print "---------------------------------------------------------------\n"
    unless $op{noverb};

my $fallos = 0;
for my $documento (@ARGV) {
    warn "ARCHIVO $documento\n";
    my $ok = eval { procesar($documento) };
    if ($@) { warn $@; $ok = 0; }
    $fallos++ unless $ok;
}
exit($fallos ? 1 : 0);

sub procesar {
    my ($documento) = @_;
    die "simplot: no existe: $documento\n" unless -f $documento;
    die "simplot: el flujo Simusol (.caj, .hashplot, .gra, .tvar) se retiro: " .
        "usar el .paraplot, el .ds o la tabla .simul\n"
        if $documento =~ /\.(?:caj|hashplot|gra|tvar)\z/i;
    my ($dato, $global);
    if ($documento =~ /\.(?:d|ds|ds2|dat|paraplot)\z/i) {
        $dato = SimPlot::Dato::leer($documento);
        SimPlot::Dato::vincular_salida($dato, $documento, $simulado) if defined $simulado;
        $global = $dato->{GLOBAL};
        die "Simplot: DAT sin descripcion grafica ni OUTPUTS utilizables\n"
            unless ref($global->{simplot}) eq 'HASH';
    } else {
        # una tabla sola (.simul o equivalente): una grafica por columna
        # contra la primera, con los metadatos que la tabla traiga
        (my $id = basename($documento)) =~ s/\.[^.]*\z//;
        $id = 'TABLA' unless $id =~ /\A[A-Za-z0-9_][A-Za-z0-9_.-]*\z/;
        $global = {simplot => {version => 2, automatico => 1,
                               fuentes => [{id => $id, archivo => File::Spec->rel2abs($documento)}],
                               graficos => [], paneles => []}};
    }
    if ($graf == 0) {
        warn "simplot: -graf=0: no se dibuja\n" unless $op{noverb};
        return 1;
    }
    require SimPlot::Render;
    my %render = (directorio => $outdir // '.',
                  tablas => $global->{tablas} // {},
                  preparacion => $global);
    $render{interactivo} = 1 if $op{i} || $graf == 1;
    $render{ventanas} = 0 if $op{sinventana} || $graf == 4;
    my $r = SimPlot::Render::dibujar($global->{simplot}, $documento, %render);
    print "Simplot v2: $r->{directorio}\n";
    return 1;
}

__END__

=encoding utf8

=head1 NAME

simplot - gráficos desde documentos y tablas del proyecto Simusol

=head1 SYNOPSIS

B<simplot> [I<opciones>] I<documentos o tablas>

  simplot caso.ds                  genera caso-grafico.ds y dibuja
  simplot -graf=4 caso.paraplot    PNG y EPS sin abrir ventanas
  simplot -graf=4 datos.simul      una gráfica por columna contra la primera
  simplot -i caso.dat              elegir las series en diálogo
  simplot --stdin < protocolo      el protocolo simplot-stdin de Siru

=head1 DESCRIPTION

Lee un documento (C<.ds>, C<.d>, C<.ds2>, C<.dat> o C<.paraplot>) o una tabla
(C<.simul> y equivalentes), traduce su pedido gráfico con C<d2datdinc> al
modelo del PARAPLOT único y dibuja con Gnuplot; las tablas las lee y
convierte Tabular2. El lenguaje PARAPLOT está en la documentación del
paquete (C<doc/03-paraplot.md>); el modelo y el DAT, en
C<doc/DAT-SIMPLOT-V2.md>.

El flujo histórico de Simusol (C<.caj>, C<.hashplot>, C<.gra>, C<.tvar>) se
retiró el 11/10/2026: esos archivos se rechazan con el motivo. Un DAT con el
modelo gráfico histórico (version 1) se regenera de su C<.ds> con
C<d2datdinc>.

=head1 OPTIONS

=over 5

=item B<-graf=>I<N>

0 no dibuja; 1 interactivo (como B<-i>); 3 normal; 4 genera PNG y EPS sin
abrir ventanas.

=item B<-i>

Diálogo interactivo: se eligen fuentes y series en la terminal.

=item B<-sinventana>

No abre ventanas X11; genera los archivos de imágenes. Compatible con B<-i>.

=item B<-outdir=>I<DIR>

El directorio donde dejar el directorio de corrida (C<simplot-v2-XXXXXX>).

=item B<--simulado> I<archivo>

La tabla de esta corrida, cuando Siru numera la salida: reemplaza en el
documento la referencia a su tabla propia.

=item B<--stdin>

Recibe una línea JSON UTF-8 (protocolo simplot-stdin, versión 1) seguida de
la tabla completa y EOF. Ver C<doc/DAT-PARAPLOT.md>.

=item B<--pares>

El modo de pares (C<SimPlot::Pares>).

=item B<-noverb>

Menos texto no esencial.

=item B<-nokill>, B<-noclas>

Aceptadas por compatibilidad; no hacen nada.

=item B<-h>, B<--help>; B<-v>, B<--version>

=back

Sin B<-graf> ni estas opciones, un documento entra al modo Documento
(B<--save>, B<--noX>, B<--salida>, B<--no-generar>, B<--no-ejecutar>): genera
las secciones GNUPLOT dentro del propio documento y lo publica.

=head1 AUTHORS

Dolores Alia de Saravia <dolores@gmail.com>,
Luis R. Saravia <luis.saravia@gmail.com>,
Diego Saravia <dsa@ututo.org>,
Nilsa Sarmiento <nilsa@ututo.org>

=head1 LICENSE AND COPYRIGHT

Copyright 2003 Dolores Alia

This program is free software; you can redistribute it and/or modify it
under the terms of the GPLv3+ license.

=cut
