#!/bin/bash
# regenera: vuelve a generar los cuatro derivados de cada circuito del corpus.
#
#   siru/corpus/regenera [-n] [DIRECTORIO | FUENTE.d|FUENTE.ds ...]
#
# Con fuentes sueltas regenera solo lo de esas (el .dat, sus .din y su .tipo).
#
# Cada fuente --un .d o un .ds-- tiene hasta cuatro archivos derivados al lado,
# y cada uno lo hace otro programa. Antes habia que acordarse de los cuatro, y
# del orden, y correrlos a mano uno por uno.
#
# Es el reverso de compara-dat y compara-din: mismo recorrido, mismas reglas
# para encontrar la fuente de cada congelado y desde donde correrla, pero en
# vez de comparar, escribe. Hay que correrlo cada vez que cambia algo que se
# refleja en lo congelado --la biblioteca de modelos, el generador, o los
# propios .d y .ds del corpus-- y despues las dos pruebas tienen que volver a
# dar todo igual.
#
#   -n     ensayo en seco: dice cuanto cambiaria y no toca nada
#   --ds2  ademas rehace los .ds2 (ver abajo: hoy no se reproducen)
#   --sceptre  ademas corre siru/corpus/sceptre sobre cada .d: SCEPTRE y siru
#              sobre el mismo archivo, NOMBRE.sceptre y NOMBRE-Sceptre al lado,
#              y avisa de los que difieren (pedido del autor, 30/09/2026).
#              Sobre TODOS los .d, tengan o no .din: SCEPTRE no depende de
#              libdin, y un .d que siru no traduce igual tiene su referencia.
#              Es lento: compila un Fortran por circuito
#
# Lo que hace con cada archivo, en este orden, que importa porque clasificar
# lee los otros tres:
#
#   *.ds2                     d2ds desde el .d (Simulparser). Un .ds no da
#                             .ds2: el que salia de dsarregla corregia lo que
#                             Siru leia mal, d2datdinc lee bien el .ds, y esos
#                             .ds2 y dsarregla estan en siru/corpus/ds2viejos
#                             (01/10/2026). SOLO CON --ds2, y
#                             por ahora no conviene: los .ds2 congelados no se
#                             reproducen con el d2ds de hoy, que agrega el
#                             control por omision '= 1' que ellos no tienen
#                             (152 de 246 saldrian distintos), y 41 fuentes de
#                             slex_viejos_* fallan porque su 'input library.ds'
#                             no resuelve. Hasta que eso se aclare, el .ds2 se
#                             rehace a mano
#   *.dat                     d2datdinc a secas. El OTHERINFO lleva rutas,
#                             pero son las de esta misma copia de trabajo, asi
#                             que salen iguales
#   *-de-d2datdinc.din        los dos --el base y el del metodo-- de una sola
#   *-de-d2datdinc-ED<N>.din  corrida de d2datdinc --din
#   *.tipo                    siru/corpus/clasificar, al final
#
# Lo que se genera y no estaba versionado se agrega con svn add. Lo congelado
# que el generador ya no escribe NO se borra: se le pone .NOREGENERADO al final
# del nombre, porque la causa puede ser transitoria y esa es la unica copia de
# lo que se producia antes. Si vuelve a generarse, la marca se saca sola.
#
# Solo recorre los circuitos que YA tienen su congelado: uno que nunca dio
# .din no empieza a darlo por correr esto. Para eso esta el "sin congelar" de
# compara-din, que avisa.
#
# Copyright (C) Diego Saravia <dsa@unsa.edu.ar>
# GPL version 3 o posterior.
set -u

QUIEN=-de-d2datdinc
# La herramienta vive en siru/corpus/ y los circuitos en siru/corpus/corpus/
AQUI_TOOL=$(cd "$(dirname "$0")" && pwd)
CORPUS=$AQUI_TOOL/corpus
# d2datdinc, su tabla y su biblioteca: en siru/slex/d2datdinc
AQUI=$(cd "$AQUI_TOOL/../../slex/d2datdinc" 2>/dev/null && pwd || echo "$AQUI_TOOL/../../slex/d2datdinc")
E="${D2DATDINC:-$AQUI/d2datdinc} -c $AQUI/d2datdinc.slex -b $AQUI/biblioteca"
SP=$(cd "$AQUI_TOOL/../../Simulparser" 2>/dev/null && pwd || echo "$AQUI_TOOL/../../Simulparser")

seco=0; con_ds2=0; con_sceptre=0
while [ $# -gt 0 ]; do
  case "$1" in
    -n)    seco=1; shift ;;
    --ds2) con_ds2=1; shift ;;
    --sceptre) con_sceptre=1; shift ;;
    *)     break ;;
  esac
done

# por defecto, el corpus; slex/d2datdinc -> slex -> siru. Un directorio
# recorre ese; fuentes sueltas, solo esas (pedido del autor, 30/09/2026)
DODS=$CORPUS
# cuantas fuentes se pidieron va aparte: con set -u, ${#SOLO[@]} de un
# arreglo asociativo vacio da "variable sin asignar" (bash 5.2), y regenera
# sin fuentes sueltas no hacia nada
declare -A SOLO
n_solo=0
if [ $# -gt 0 ] && [ -d "$1" ]; then DODS=$1; shift; fi
for a in "$@"; do
  [ -f "$a" ] || { echo "no esta $a" >&2; exit 2; }
  SOLO[$(realpath "$a")]=1
  n_solo=$((n_solo+1))
done
# si esta fuente es una de las pedidas (sin fuentes pedidas, todas)
elegida() { [ $n_solo -eq 0 ] || [ -n "${SOLO[$(realpath "$1" 2>/dev/null)]:-}" ]; }

[ -x "${E%% *}" ] || { echo "no esta ${E%% *}: falta hacer make" >&2; exit 77; }
[ -d "$DODS" ] || { echo "no esta $DODS: hace falta la copia de trabajo de siru" >&2; exit 77; }

T=$(mktemp -d)
trap 'rm -rf "$T"' EXIT

# el .d o el .ds del que sale un congelado, por su nombre. El .dat lleva el
# nombre del .ds2, que para un .d que convive con un .ds del mismo nombre
# termina en -desde-d.
fuente() {
  local dir="$1" base="$2"
  if [ "${base%-desde-d}" != "$base" ]; then echo "$dir/${base%-desde-d}.d"
  elif [ -f "$dir/$base.ds" ]; then echo "$dir/$base.ds"
  else echo "$dir/$base.d"; fi
}

# igual que cuando se genero: si el archivo incluye examples/..., se corre
# desde el directorio de arriba, como corria Siru
desde_de() {
  grep -qiE '^[[:space:]]*#?[[:space:]]*(include|input)[[:space:]]+examples/' "$2" \
    && dirname "$1" || echo "$1"
}

# pone $1 en $2, y lo agrega al repositorio si no estaba
poner() {
  [ $seco -eq 1 ] && return 0
  local nuevo="$1" destino="$2" habia=1
  [ -f "$destino" ] || habia=0
  cp "$nuevo" "$destino" || return 1
  [ $habia -eq 1 ] || svn add -q --parents "$destino"
}

ds2=0; dat=0; din=0; nuevos=0; no_regenerados=0; fallan=0

# NOMBRE.log al lado de cada fuente: lo que dicen d2datdinc y clasificar al
# regenerarla, cada linea con quien la dijo (pedido del autor, 30/09/2026; es
# el mismo archivo que deja siru al correrla). Se empieza de cero la primera
# vez que se toca la fuente en esta corrida. Con -n no se escribe.
declare -A LOG_EMPEZADO
log_de() {
  local f="$1" b="${1%.*}"
  if [ "${f##*.}" = ds ] && [ -f "$b.d" ]; then echo "$b-ds.log"; else echo "$b.log"; fi
}
registra() {   # registra FUENTE QUIEN ARCHIVO_CON_EL_TEXTO
  [ $seco -eq 1 ] && return 0
  local log; log=$(log_de "$1")
  if [ -z "${LOG_EMPEZADO[$log]:-}" ]; then
    echo "# $(date '+%Y-%m-%d %H:%M:%S') regenera $(basename "$1")" > "$log"
    svn add -q "$log" 2>/dev/null
    LOG_EMPEZADO[$log]=1
  fi
  [ -s "$3" ] && sed "s/^/$2: /" "$3" >> "$log"
  return 0
}

# ---- los .ds2: d2ds desde un .d -------------------------------------------
# Solo con --ds2: ver el comentario de arriba, hoy no se reproducen
while [ $con_ds2 -eq 1 ] && IFS= read -r a; do
  dir=$(dirname "$a"); base=$(basename "$a" .ds2)
  f=$(fuente "$dir" "$base"); [ -f "$f" ] || continue
  elegida "$f" || continue
  case "$f" in
    *.d)  g="$SP/bin/d2ds" ;;
    *)    continue ;;
  esac
  [ -x "$g" ] || { fallan=$((fallan+1)); echo "no esta $g"; continue; }
  d=$(desde_de "$dir" "$f")
  # al lado del original, no en un temporal: d2ds escribe el include de la
  # biblioteca como ruta relativa a donde va la salida
  tmp="$dir/.regenera-$$.ds2"
  if ! ( cd "$d" && "$g" "$f" -o "$tmp" >/dev/null 2>&1 ); then
    rm -f "$tmp"; fallan=$((fallan+1)); echo "falla el .ds2: $f"; continue
  fi
  if cmp -s "$tmp" "$a"; then rm -f "$tmp"; continue; fi
  poner "$tmp" "$a"; rm -f "$tmp"
  ds2=$((ds2+1))
done < <(find "$DODS" -name '*.ds2' | sort)

# ---- los .dat -------------------------------------------------------------
while IFS= read -r a; do
  dir=$(dirname "$a"); base=$(basename "$a" .dat)
  f=$(fuente "$dir" "$base"); [ -f "$f" ] || continue
  elegida "$f" || continue
  d=$(desde_de "$dir" "$f")
  ( cd "$d" && $E "$f" -o "$T/e.dat" 2>"$T/err" ); r=$?
  registra "$f" "d2datdinc (.dat)" "$T/err"
  if [ $r -ne 0 ]; then
    fallan=$((fallan+1)); echo "falla el .dat: $f"; continue
  fi
  cmp -s "$T/e.dat" "$a" && continue
  poner "$T/e.dat" "$a"
  dat=$((dat+1))
done < <(find "$DODS" -name '*.dat' | sort)

# ---- los .din -------------------------------------------------------------
while IFS= read -r base_din; do
  dir=$(dirname "$base_din")
  nom=$(basename "$base_din" .din); nom=${nom%$QUIEN}
  f=$(fuente "$dir" "$nom"); [ -f "$f" ] || continue
  elegida "$f" || continue
  d=$(desde_de "$dir" "$f")

  rm -rf "$T/s"; mkdir -p "$T/s"
  ( cd "$d" && $E --din --directorio "$T/s" "$f" >/dev/null 2>"$T/err" )
  registra "$f" "d2datdinc (--din)" "$T/err"

  for nuevo in "$T/s"/*; do
    [ -f "$nuevo" ] || continue
    bn=$(basename "$nuevo")
    cmp -s "$nuevo" "$dir/$bn" && continue
    if [ -f "$dir/$bn" ]; then din=$((din+1))
    else nuevos=$((nuevos+1)); echo "nuevo: $dir/$bn"; fi
    poner "$nuevo" "$dir/$bn"
    # volvio a generarse: la marca de la vez que no se generaba ya no aplica
    if [ $seco -eq 0 ] && [ -e "$dir/$bn.NOREGENERADO" ]; then
      echo "vuelve a generarse: $dir/$bn"
      svn rm -q --force "$dir/$bn.NOREGENERADO" 2>/dev/null || rm -f "$dir/$bn.NOREGENERADO"
    fi
  done

  # Lo congelado que ya no se genera NO se borra: se le pone .NOREGENERADO al
  # final. Un circuito puede dejar de dar su .din por algo transitorio --una
  # edicion a medias de otra sesion, un error nuevo del generador-- y borrar lo
  # congelado en ese momento pierde la unica copia de lo que producia antes.
  # Con el nombre marcado queda a la vista, compara-din lo ignora, y si vuelve
  # a generarse se saca la marca sola (ver mas arriba, en el lazo de los que si
  # se generan).
  for cong in "$dir/$nom$QUIEN.din" "$dir/$nom$QUIEN"-ED*.din "$dir/$nom$QUIEN"-ED*.json; do
    [ -f "$cong" ] || continue
    [ -f "$T/s/$(basename "$cong")" ] && continue
    echo "ya no se genera: $cong"
    if [ $seco -eq 0 ]; then
      rm -f "$cong.NOREGENERADO"
      svn mv -q --force "$cong" "$cong.NOREGENERADO" 2>/dev/null \
        || mv "$cong" "$cong.NOREGENERADO"
    fi
    no_regenerados=$((no_regenerados+1))
  done
# tambien los marcados .NOREGENERADO: si vuelven a generarse, se saca la marca
done < <(find "$DODS" \( -name "*$QUIEN.din" -o -name "*$QUIEN.din.NOREGENERADO" \) \
         | sed 's/\.NOREGENERADO$//' | sort -u)

# ---- SCEPTRE, solo con --sceptre: todos los .d -----------------------------
sceptre=0; difieren=0
if [ $con_sceptre -eq 1 ] && [ $seco -eq 0 ]; then
  while IFS= read -r f; do
    dir=$(dirname "$f"); nom=$(basename "$f" .d)
    elegida "$f" || continue
    python3 "$AQUI_TOOL/sceptre" "$f" >"$T/out" 2>"$T/err"; estado=$?
    cat "$T/out"; cat "$T/err" >&2
    registra "$f" sceptre "$T/err"
    sceptre=$((sceptre+1))
    if grep -q "difiere de SCEPTRE" "$T/err"; then difieren=$((difieren+1))
    elif [ $estado -ne 0 ]; then fallan=$((fallan+1)); fi
    for s in "$dir/$nom.sceptre" "$dir/$nom-Sceptre"; do
      [ -f "$s" ] && svn add -q --parents "$s" 2>/dev/null
    done
  done < <(find "$DODS" -name '*.d' | sort)
fi

# ---- los .tipo, al final: clasificar lee el .ds2, el .dat y los .din -------
tipo=0
if [ $seco -eq 0 ] && [ -x "$AQUI_TOOL/clasificar" ]; then
  # clasificar escribe NOMBRE.tipo al lado de cada .d y .ds; sin argumentos
  # recorre el corpus entero
  if [ $n_solo -gt 0 ]; then
    for f in "${!SOLO[@]}"; do
      python3 "$AQUI_TOOL/clasificar" "$f" >/dev/null 2>"$T/err" || fallan=$((fallan+1))
      registra "$f" clasificar "$T/err"
      tipo=$((tipo+1))
    done
  elif [ "$DODS" = "$CORPUS" ]; then
    python3 "$AQUI_TOOL/clasificar" >/dev/null 2>&1 || fallan=$((fallan+1))
    tipo=$(find "$DODS" -name '*.tipo' | wc -l)
  else
    while IFS= read -r f; do
      python3 "$AQUI_TOOL/clasificar" "$f" >/dev/null 2>"$T/err" || fallan=$((fallan+1))
      registra "$f" clasificar "$T/err"
      tipo=$((tipo+1))
    done < <(find "$DODS" \( -name '*.d' -o -name '*.ds' \) | sort)
  fi
fi

echo
[ $seco -eq 1 ] && echo "  (ensayo en seco: no se toco nada; el .tipo no se mira)"
echo "  .ds2 reescritos     $ds2"
echo "  .dat reescritos     $dat"
echo "  .din reescritos     $din"
echo "  .din nuevos         $nuevos"
echo "  .tipo escritos      $tipo"
echo "  .NOREGENERADO       $no_regenerados"
[ $con_sceptre -eq 1 ] && echo "  contra SCEPTRE      $sceptre, difieren $difieren"
echo "  fuentes que fallan  $fallan"
exit $((fallan > 0))
