unit uLectorSimRes3Defs;

{$IFNDEF RELASE}
{xDEFINE FEDE_DEBUG}
{$ENDIF}

{$IFDEF APLICACION_CONSOLA}
{xDEFINE SIMRES3SOLOTEXTO}
{$ENDIF}

{$IFDEF FPC}
{$MODE Delphi}
{$ENDIF}
interface

uses
{$IFNDEF SIMRES3SOLOTEXTO}
{$IFDEF SVG_CANVAS}
  usvgcanvas,
{$ELSE}
{$IFDEF FP_CANVAS}
  ucoloresbasicos,
{$ELSE}
  Graphics,
{$ENDIF}
{$ENDIF}
{$IFDEF WINDOWS}
  // Dialogs,
  //Windows,
{$ENDIF}
{$ENDIF}


  SysUtils,
  uTSimRes,
  uSimResGlobs,
  uHistoVarsOps,
  uPostOpers,
  uPrintCronVars,
  Classes,
  uAuxiliares,
  xMatDefs,
  Math,
  uFechas,
  uAuxiliaresEscrituraSimRes, uConstantesSimSEE,
  uListaComentarioObjeto, uListaTagObjeto, uPrint;

const
  maxNArchisSimRes = 10;

const

  VERSION_ARCHI_SIMRES = 18;
// rch&dv@201806061153  cambiamos la forma en que se anuncia la Sala al publicar las variables
// de estado. Antes esta a mano fijado el nombre del Participante como '-' un guión. Ahora
// Se deja que la sala ponga su nombre 'Sala' que es el que usa al publicar las variables.

//VERSION_ARCHI_SIMRES = 17;
// rch&xc@201712261112
// Pasamos TodasLasCronicas al radio_button de tipo de valores a comparar en la PrintCronVar
// CompararMultiples ...

//  VERSION_ARCHI_SIMRES = 16;
// rch@201712251723 - NAVIDAD -
// Agrego parámetros del eje secundario en PrintCronVar comparar multiples.

// VERSION_ARCHI_SIMRES = 15;
//xcaporale@20170908
//Agrego la variable TodasCronVars
//para indicar que si se quiere graficar todas las cronicas, en vez de realizar el promedio u otra.


//VERSION_ARCHI_SIMRES = 14;
//xcaporale@20170831
//Agrego la variable ejex
//para indicar que Eje x se quiere usar en el grafico de dispersión (tiempo u otro).

//VERSION_ARCHI_SIMRES = 13;
// rchaer@201612100846
// Agrego variables flg_ejecutar y flg_quit_al_final a la PrinCronVar_R
// para que se pueda indicar si se quiere ejecutar el programa R (o solo crear el archivo )
// y si una vez ejecutado se quiere hacer q() para salir automáticamente (y que la salida
// de texto generada se guarde en un archivo de salida.



// VERSION_ARCHI_SIMRES = 12;
// fbarreto@20161116
// Se le agrega a TPostOper_cambioPasoDeTiempo la seleccion de la i-esima
// entrada como valor para el cambio de paso de tiempo.

//VERSION_ARCHI_SIMRES = 11;
// Agrego checkbox en TCronOPer_sumaDobleProductoConDurposTopeado para facilitar
// cálculo de Potencia Firme haciendo que en el modo comparativo sume el dobleproducto

// rchaer@201608291139
// {$carpetaCorrida}simres_{$semillaSim}x{$nCronicasSim}_{$escenario}.xlt
// {$carpetaCorrida}simres_{$semillaSim}x{$nCronicasSim}_{$escenario}.xlt
// VERSION_ARCHI_SIMRES = 10;

//fbarreto@20160216  Se agrega modo comparativo a TCronOper_sumaDobleProductoConDurposTopeado
//VERSION_ARCHI_SIMRES = 9;

//fbarreto@20150403  Se agrega a TPostOper_cambioPasoDeTiempo la posibilidad
// de calcular, además de Suma y Promedio, maximo, minimo, primero y ultimo
//VERSION_ARCHI_SIMRES = 8;

//  VERSION_ARCHI_SIMRES = 7;
// rch@20141116 Agrego postOpers: CVaR, CrearConstante, AcumularConPisoYTecho


//   VERSION_ARCHI_SIMRES = 6;
// rch@20130920 Agrego _{$escenario} al final de los archivos simres

//  VERSION_ARCHI_SIMRES = 5;
// agrego filtrado global de crónica.

//  VERSION_ARCHI_SIMRES = 4;
// rch@2012-2-8 agrego CheckBox Pre-Ordenar en las PrintCronVar Histograma


//  VERSION_ARCHI_SIMRES = 3;



type
  TTipoLinea = (TL_Error, TL_Comentario, TL_ComentarioGlobal, TL_Objeto,
    TL_EsperandoStr);

  { TLectorSimRes3Defs }

  TLectorSimRes3Defs = class
  private

    fechaDesde_f, fechaHasta_f: TFecha;
    filtrar_Cronica: boolean;
    kCron_f: integer; // fitlrado de crónica global agregado en versión 5

    kParamLectura: integer;
    //Linea de lectura
    kLineaLectura: integer;

    kLineasArchisSimRes: TDAofNInt;

    kLineaFechaIni, kLineaFechaFin: integer;

    ComentarioGlobal: boolean;
    comentarioDeObjeto: TStringList;

    //las lineas del archivo cargado si hubo uno
    lineasArchi: TStringList;
    tagsObjetos: TListaTagObjeto;

    procedure OPEN_WRITE(var f: textfile);
    procedure CLOSE_WRITE(var f: textfile);

    procedure formatearArchivoLeido;

    //      procedure leerEIncrementarLinea(var f: TextFile; var linea: String; EsperandoStr: string ); overload;
    function leerEIncrementarLinea(out linea: string;
      EsperandoStr: string): TTipoLinea;
    //Lee una palabra de linea, aumenta el contador de parámetro en 1 y quita
    //la palabra de la línea
    function readPal(var linea: string): string;

    //Usan lineasArchi, no se precisa pasarles el archivo
    procedure LeerSimRes(prepararseParaCorrer: boolean);
    //    procedure LeerFiltroCronica(prepararseParaCorrer: boolean);
    procedure LeerFechas(prepararseParaCorrer: boolean);
    procedure LeerIndices(prepararseParaCorrer: boolean);
    procedure LeerCron_Vars;
    procedure LeerCron_Opers(prepararseParaCorrer: boolean);
    procedure LeerPost_Opers(prepararseParaCorrer: boolean);
    procedure LeerPrintCronVars;

    procedure WriteLnSimRes(var f: TextFile; s: string); overload;
    procedure WriteLnSimRes(var f: TextFile); overload;
    //Incrementa kLinea hasta que lineasArchi[kLinea] = linea
    procedure avanzarkLineaHastaLinea(linea: string);
    procedure escribirLineasHastaLinea(var f: TextFile; linea: string);

    procedure EscribirSimRes(var f: TextFile);
    procedure EscribirFechas(var f: TextFile);
    procedure EscribirIndices(var f: TextFile);
    procedure EscribirCron_Vars(var f: TextFile);
    procedure EscribirCron_Opers(var f: TextFile);
    procedure EscribirPost_Opers(var f: TextFile);
    procedure EscribirPrintCronVars(var f: TextFile);

    function leerIndice(linea: string): TVarIdxs;
    function leerCronVar(linea: string): TCronVar;
    function leerCronOper(linea: string; prepararseParaCorrer: boolean): TCronOper;
    function leerPostOper(linea: string; prepararseParaCorrer: boolean): TPostOper;
    function leerPrintCronVar(linea: string): TPrintCronVar;

    function getOrigen(str: string): TDAofString;
  public

    versionArchivo: integer;
    archisSimRes: TStringList; //Origen de datos, no tiene porque ser un archivo simRes
    simRes: TResultadoSim;
    kPasoDesde, kPasoHasta: integer;
    lstArchis: TStringList;
    lstIdxs, lstCronVars, lstCronOpers, lstPostOpers, lstPrintCronVars: TList;
    lstSimRes_: TList;
    comentariosObjetos: TListaComentarioObjeto;

    version_SimSEE: string;
    fechaSimulacion_f: TFecha;


    constructor Create;
    procedure LeerDefiniciones(archi: string; prepararseParaCorrer: boolean;
      flg_LeerHastaIndices: boolean);


    procedure EscribirDefiniciones(archi: string; guardarBackupSiExiste: boolean;
      maxNBackups: integer);

    function clonarIndice(indice: TVarIdxs): TVarIdxs;
    function clonarCronVar(cronVar: TCronVar): TCronVar;
    function clonarCronOper(cronOper: TCronOper): TCronOper;
    function clonarPostOper(postOper: TPostOper): TPostOper;
    function clonarPrintCronVar(printCronVar: TPrintCronVar): TPrintCronVar;


    function getIndiceByName(nombreIndice: string): TVarIdxs;
    function getCronVarByName(nombreCronVar: string): TCronVar;

    function existeReferenciaAlIndice(indice: TVarIdxs): boolean; overload;
    function existeReferenciaAlIndice(indice: TVarIdxs;
      var referentes: TDAOfCronOper): boolean; overload;
    function existeReferenciaALaCronVar(cronVar: TCronVar): string;

    function indicesSinReferencia: TDAOfTVarIdxs;
    function cronVarsSinReferencia: TDAOfCronVar;

    function esResultadoDeCronOper(cronVar: TCronVar): boolean;

    // busca si la cronVar es resultado de las PostOper entre las PostOper
    // de 0 a jHasta-1
    function esResultadoDePostOper(cronVar: TCronVar; jHasta: integer): boolean;

    function hayErrores(errores: TStrings): boolean;

    procedure agregarIndice(indice: TVarIdxs);
    procedure agregarCronVar(cronVar: TCronVar);
    procedure agregarCronOper(cronOper: TCronOper);
    procedure agregarPostOper(postOper: TPostOper);
    procedure agregarPrintCronVar(printCronVar: TPrintCronVar);


    procedure eliminarIndice(iIndice: integer); overload;
    procedure eliminarIndice(var indice: TVarIdxs); overload;
    procedure eliminarCronVar(iCronVar: integer); overload;
    procedure eliminarCronVar(var cronVar: TCronVar); overload;
    procedure eliminarCronOper(iCronOper: integer);
    procedure eliminarPostOper(iPostOper: integer);
    procedure eliminarPrintCronVar(iPrintCronVar: integer);

    procedure swapObjetosSimRes(item1, item2: Pointer);
    procedure swapIndices(indice1, indice2: TVarIdxs);
    procedure swapCronVars(cronVar1, cronVar2: TCronVar);
    procedure swapCronOpers(cronOper1, cronOper2: TCronOper);
    procedure swapPostOpers(postOper1, postOper2: TPostOper);
    procedure swapPrintCronVars(printCronVar1, printCronVar2: TPrintCronVar);

    procedure altaEdicionPostOper2CronVarsUnReal(tipoPostOper: TClaseDePostOper;
      var postOper: TPostOper; cv1, cv2: TCronVar; aReal: NReal);
    procedure paramsPostOper2CronVarsUnReal(postOper: TPostOper;
      var cv1, cv2: TCronVar; var aReal: NReal);
    procedure altaEdicionPostOper3CronVars(tipoPostOper: TClaseDePostOper;
      var postOper: TPostOper; cv1, cv2, cv3: TCronVar);
    procedure paramsPostOper3CronVars(postOper: TPostOper;
      var cv1, cv2, cv3: TCronVar);

    function nombreRepetidoCronVar(cronVar: TCronVar; nombre: string): boolean;
    function nombreRepetidoIndice(indice: TVarIdxs; nombre: string): boolean;
    //Si result = true, otraPrintCronVar es la PrintCronVar que tiene la hoja con el mismo nombre
    function nombreHojaPrintCronVarRepetido(printCronVar: TPrintCronVar;
      nombreHoja: string; var otraPrintCronVar: TPrintCronVar): boolean;
    procedure Free;

    procedure set_fechaDesde(const s: string);
    function get_fechaDesde: string;
    procedure set_fechaHasta(const s: string);
    function get_fechaHasta: string;

    property fechaDesde: string read get_fechaDesde write set_fechaDesde;
    property fechaHasta: string read get_fechaHasta write set_fechaHasta;

    {$IFDEF pruebasDistSimRes3}
    procedure imprimir;
    {$ENDIF}

  end;

implementation

function TraducirNombreArchivo_SimRes_MonoHiloToMultiHilo(
  nombre_archi: string): string;
var
  carpeta: string;
  archi: string;
  sSemilla, sEscenario: string;
  j: integer;
begin
  Result := '';
  carpeta := ExtractFileDir(nombre_archi);
  archi := ExtractFileName(nombre_archi);
  // {$carpetaCorrida}simres_{$semillaSim}x{$nCronicasSim}_{$escenario}.xlt
  //"C:\SimSEE\rundir\sem 2016-36-1s se bonete a pleno\simres_31x100_Base.xlt"
  j := pos('simres_', archi);
  if j <> 1 then
    exit;
  Delete(archi, 1, sizeOf('simres_'));
  j := pos('x', archi);
  if j < 2 then
    exit;
  sSemilla := copy(archi, 1, j - 1);
  Delete(archi, 1, j);
  j := pos('_', archi);
  if j < 2 then
    exit;
  Delete(archi, 1, j);
  j := pos('.', archi);
  if j < 2 then
    exit;
  sEscenario := copy(archi, 1, j - 1);
  //  {$carpetaCorrida}simres_{$semillaSim}_{$escenario}_d*.xlt
  archi := 'simres_' + sSemilla + '_' + sEscenario + '_d*.xlt';

  Result := carpeta + DirectorySeparator + archi;

end;

procedure clearListaDeObjetos(list: TList);
var
  i: integer;
begin
  for i := 0 to List.Count - 1 do
    TObject(list[i]).Free;
  list.Clear;
end;


procedure TLectorSimRes3Defs.set_fechaDesde(const s: string);
begin
  if s = '{$fechaIniSim}' then
    fechaDesde_f.dt := 0
  else
    fechaDesde_f.dt := StrToDateTime(s);
end;

function TLectorSimRes3Defs.get_fechaDesde: string;
begin
  if FechaDesde_f.dt = 0 then
    Result := '{$fechaIniSim}'
  else
    Result := FechaDesde_f.asStr;
end;

procedure TLectorSimRes3Defs.set_fechaHasta(const s: string);
begin
  if s = '{$fechaFinSim}' then
    fechaHasta_f.dt := 0
  else
    fechaHasta_f.dt := StrToDateTime(s);
end;

function TLectorSimRes3Defs.get_fechaHasta: string;
begin
  if FechaHasta_f.dt = 0 then
    Result := '{$fechaFinSim}'
  else
    Result := FechaHasta_f.asStr;
end;

{$IFDEF pruebasDistSimRes3}

procedure TLectorSimRes3Defs.imprimir;
var
  i: integer;
begin
  writeln('*** archisSimRes ***');
  for i := 0 to lstSimRes.Count - 1 do
    writeln(TResultadoSim(lstSimRes.Items[i]).archiSimRes);

  writeln('*** kPasoDesde, kPasoHasta ***');
  writeln('        ', kPasoDesde, '        ', kPasoHasta);

  for i := 0 to lstSimRes.Count - 1 do
    TResultadoSim(lstSimRes.Items[i]).imprimir;

  // simRes: TResultadoSim;
  // lstSimRes, lstIdxs, lstCronVars, lstCronOpers, lstPostOpers,
  // lstPrintCronVars: TList;
  // comentariosObjetos: TListaComentarioObjeto;

end;

{$ENDIF}

procedure TLectorSimRes3Defs.formatearArchivoLeido;
begin
  borrarLineasVaciasConsecutivas(lineasArchi, 1);
  borrarLineasVaciasAntesDeCierreSeccion(lineasArchi, '-');
end;

function TLectorSimRes3Defs.leerEIncrementarLinea(out linea: string;
  EsperandoStr: string): TTipoLinea;
var
  comGlob: string;
  res: TTipoLinea;
  j1: integer;
begin
  if kLineaLectura < lineasArchi.Count then
  begin
    res := TL_Error;
    comGlob := '';
    repeat
      linea := Trim(lineasArchi[kLineaLectura]);
      kLineaLectura := kLineaLectura + 1;
      kParamLectura := 0;

      if linea <> '' then
      begin
        if ComentarioGlobal then
        begin
          j1 := Pos(cierraComentarioGlobal, linea);
          if j1 > 0 then
          begin
            linea := comGlob + #13#10 + Copy(linea, 1, length(linea) - j1);
            ComentarioGlobal := False;
          end
          else
            comGlob := comGlob + #13#10 + linea;
          res := TL_ComentarioGlobal;
        end
        else
        begin
          if pos(strComment, linea) = 1 then
          begin
            Delete(linea, 1, length(strComment));
            res := TL_Comentario;
          end
          else if (not ComentarioGlobal) and (Pos(AbreComentarioGlobal, linea) = 1) then
          begin
            ComentarioGlobal := True;
            comGlob := Copy(linea, length(AbreComentarioGlobal) + 1,
              length(linea) - length(AbreComentarioGlobal));
          end
          else if linea = EsperandoStr then
            res := TL_EsperandoStr
          else
            res := TL_Objeto;
        end;
      end;
    until (linea <> '') and not ComentarioGlobal;

    Result := res;

  end
  else
    raise Exception.Create(
      'Llegue al final del archivo sin terminar de leer las definiciones. Probablemente hay una sección mal abierta o mal cerrada. Esperando:' + EsperandoStr);
end;

function TLectorSimRes3Defs.readPal(var linea: string): string;
var
  res: string;
begin
  res := NextPal(linea);
  if length(res) > 0 then
  begin
    if res[1] = '"' then
    begin
      while (linea <> '') and (res[Length(res)] <> '"') do
        res := res + ' ' + NextPal(linea);
      //Borro las comillas
      Result := Copy(res, 2, Length(res) - 2);
    end
    else
      Result := res;
    kParamLectura := kParamLectura + 1;
  end
  else
    Result := '';
end;

function TLectorSimRes3Defs.getIndiceByName(nombreIndice: string): TVarIdxs;
var
  i: integer;
  res: TVarIdxs;
begin
  res := nil;
  if lowercase(nombreIndice) = 'nil' then
  begin
    Result := nil;
    exit;
  end;

  for i := 0 to lstIdxs.Count - 1 do
    if TVarIdxs(lstIdxs[i]).nombreIndice = nombreIndice then
    begin
      res := TVarIdxs(lstIdxs[i]);
      break;
    end;
  if res = nil then
    raise Exception.Create('No se encuentra el indice ' + nombreIndice +
      ' leyendo la línea ' + IntToStr(kLineaLectura))
  else
    Result := res;
end;

function TLectorSimRes3Defs.getCronVarByName(nombreCronVar: string): TCronVar;
var
  i: integer;
  res: TCronVar;
begin
  res := nil;
  if lowercase(nombreCronVar) = 'nil' then
  begin
    Result := nil;
    exit;
  end;

  for i := 0 to lstCronVars.Count - 1 do
    if TCronVar(lstCronVars[i]).nombre = nombreCronVar then
    begin
      res := TCronVar(lstCronVars[i]);
      break;
    end;
  if res = nil then
    raise Exception.Create('No se encuentra la cronVar ' + nombreCronVar +
      ' leyendo la línea ' + IntToStr(kLineaLectura))
  else
    Result := res;
end;



procedure TLectorSimRes3Defs.LeerSimRes(prepararseParaCorrer: boolean);
var
  iSimRes: integer;
  linea: string;
  tipoLinea: TTipoLinea;
  simResi: TResultadoSim;
  nombre_archi: string;

begin
  uSimResGlobs.Set_nCronicasDelEstudio(MAXINT);
  lstArchis.Clear;
  clearListaDeObjetos(lstSimRes_);

  //+SimRes
  repeat
    leerEIncrementarLinea(linea, '+SimRes');
  until linea = '+SimRes';

  SetLength(kLineasArchisSimRes, maxNArchisSimRes);
  iSimRes := 0;
  tipoLinea := leerEIncrementarLinea(linea, '-SimRes');
  while linea <> '-SimRes' do
  begin
    case tipoLinea of
      TL_Error: raise Exception.Create(
          'Error leyendo archivo SimRes, linea ' + IntToStr(kLineaLectura) +
          ': ' + linea);
{      TL_Comentario       : comentariosObjetos.addComentarioDeLinea('SimRes', linea, kLineaInicioDeSeccion, kLinea);
      TL_ComentarioGlobal : comentariosObjetos.addComentarioDeLinea('SimRes', linea, kLineaInicioDeSeccion, kLinea);}
      TL_Objeto:
      begin
        kLineasArchisSimRes[iSimRes] := kLineaLectura - 1;
        nombre_archi := readPal(linea);

        if nombre_archi = OLD_strUsarArchivoDeCorrida then
          nombre_archi := strUsarArchivoDeCorrida;
        if (self.versionArchivo < 10) and (pos('*', nombre_archi) = 0) and
          (pos('{$', nombre_archi) = 0) then
          nombre_archi := TraducirNombreArchivo_SimRes_MonoHiloToMultiHilo(
            nombre_archi);

        lstArchis.add(nombre_archi);
        if prepararseParaCorrer then
        begin
          simResi := TResultadosSim_MultiARchivo.Create(nombre_archi);
          if simResi.nCronicas < uSimResGlobs.nCronicasDelEstudio then
          begin
            uSimResGlobs.set_nCronicasDelEstudio(simResi.nCronicas);
            simRes := simResi;
            //se usara para avanzar este pues es el que termina con su archivo primero
          end;
          lstSimRes_.Add(simResi);
          if lstSimRes_.Count = 1 then
          begin
            self.version_SimSEE := simResi.encabezado_.version_SimSEE;
            self.fechaSimulacion_f.dt := simResi.encabezado_.FechaIni;
          end;
        end;
        iSimRes := iSimRes + 1;
      end;
      //TL_EsperandoStr   : //Nada, sale por el while;
    end;
    tipoLinea := leerEIncrementarLinea(linea, '-SimRes');
  end;
  if iSimRes <> Length(kLineasArchisSimRes) then
    kLineasArchisSimRes := copy(kLineasArchisSimRes, 0, iSimRes);
end;

(***

procedure TLectorSimRes3Defs.LeerFiltroCronica(prepararseParaCorrer: boolean);
var
  linea:     string;
  tipoLinea: TTipoLinea;
  fechaIniOk, fechaFinOk: boolean;
  fechaIni, fechaFin: TDateTime;
begin
  repeat
    leerEIncrementarLinea(linea, '+FiltroCronica');
  until linea = '+FiltroCronica';

  tipoLinea := leerEIncrementarLinea(linea, '-FiltroCronica');
  while linea <> '-FiltroCronica' do
  begin
    case tipoLinea of
      TL_Error: raise Exception.Create('Error leyendo fechas, linea ' +
          IntToStr(kLineaLectura) + ': ' + linea);
      TL_Objeto:
      begin
        if not fechaIniOk then
        begin
          kLineaFechaIni := kLineaLectura - 1;
          fechaIniOk     := True;
          fechaDesde     := readPal(linea);
          if prepararseParaCorrer then
          begin
            fechaIni   := StrToDateTime(fechaDesde);
            kPasoDesde := simres.kPasoInicioParaFecha(fechaIni);
            usimresGlobs.desde :=
              simres.fechaDeInicioDelPaso(kPasoDesde);
         end
          else
          begin
            kPasoDesde := 0;
            usimresGlobs.desde := 0;
          end;
        end
        else if not fechaFinOk then
          //para entrar aca tengo que haber leído la fechaIni
        begin
          kLineaFechaFin := kLineaLectura - 1;
          fechaFinOk     := True;
          fechaHasta     := readPal(linea);
          if prepararseParaCorrer then
          begin
            fechaFin   := StrToDateTime(fechaHasta);
            kPasoHasta := simres.kPasoInicioParaFecha(fechaFin);
            usimresglobs.hasta :=
              simres.fechaDeInicioDelPaso(kPasoHasta);
          end
          else
          begin
            kPasoDesde := 0;
            usimresGlobs.desde := 0;
          end;
        end;
      end;
      //TL_EsperandoStr   : //Nada, sale por el while;
    end;
    tipoLinea := leerEIncrementarLinea(linea, '-Fechas');
  end;
  uSimResGlobs.nPasosDelEstudio := kPasoHasta - kPasoDesde;
  if prepararseParaCorrer and (uSimResGlobs.nPasosDelEstudio <= 0) then
    raise Exception.Create(
      'El horizonte del estudio es NULO!!. Revise el filtro de fechas.');
end;
*)

procedure TLectorSimRes3Defs.LeerFechas(prepararseParaCorrer: boolean);
var
  linea: string;
  tipoLinea: TTipoLinea;
  fechaIniOk, fechaFinOk: boolean;
  fechaIni, fechaFin: TDateTime;

begin
  fechaIniOk := False;
  fechaFinOk := False;
  //+Fecha
  repeat
    leerEIncrementarLinea(linea, '+Fechas');
  until linea = '+Fechas';

  tipoLinea := leerEIncrementarLinea(linea, '-Fechas');
  while linea <> '-Fechas' do
  begin
    case tipoLinea of
      TL_Error: raise Exception.Create('Error leyendo fechas, linea ' +
          IntToStr(kLineaLectura) + ': ' + linea);
{      TL_Comentario       : comentariosObjetos.addComentarioDeLinea('Fechas', linea, kLineaInicioDeSeccion, kLinea);
      TL_ComentarioGlobal : comentariosObjetos.addComentarioDeLinea('Fechas', linea, kLineaInicioDeSeccion, kLinea);}
      TL_Objeto:
      begin
        if not fechaIniOk then
        begin
          kLineaFechaIni := kLineaLectura - 1;
          fechaIniOk := True;
          fechaDesde := trim(linea);
          if prepararseParaCorrer then
          begin
            fechaIni := StrToDateTime(fechaDesde);
            kPasoDesde := simres.kPasoInicioParaFecha(fechaIni);
            usimresGlobs.desde :=
              simres.fechaDeInicioDelPaso(kPasoDesde);
          end
          else
          begin
            kPasoDesde := 0;
            usimresGlobs.desde := 0;
          end;
        end
        else if not fechaFinOk then
          //para entrar aca tengo que haber leído la fechaIni
        begin
          kLineaFechaFin := kLineaLectura - 1;
          fechaFinOk := True;
          fechaHasta := trim(linea);
          if prepararseParaCorrer then
          begin
            fechaFin := StrToDateTime(fechaHasta);
            kPasoHasta := simres.kPasoInicioParaFecha(fechaFin);
            usimresglobs.hasta :=
              simres.fechaDeInicioDelPaso(kPasoHasta);
          end
          else
          begin
            kPasoDesde := 0;
            usimresGlobs.desde := 0;
          end;
        end;
      end;
      //TL_EsperandoStr   : //Nada, sale por el while;
    end;
    tipoLinea := leerEIncrementarLinea(linea, '-Fechas');
  end;
  uSimResGlobs.nPasosDelEstudio := kPasoHasta - kPasoDesde;
  if prepararseParaCorrer and (uSimResGlobs.nPasosDelEstudio <= 0) then
    raise Exception.Create(
      'El horizonte del estudio es NULO!!. Revise el filtro de fechas.');
end;



procedure TLectorSimRes3Defs.LeerIndices(prepararseParaCorrer: boolean);
var
  linea: string;
  defIndice, indice: TVarIdxs;
  numSimRes: integer;
  tipoLinea: TTipoLinea;
begin
  clearListaDeObjetos(lstIdxs);
  //+Indices
  repeat
    leerEIncrementarLinea(linea, '+Indices');
  until linea = '+Indices';

  tipoLinea := leerEIncrementarLinea(linea, '-Indices');
  while linea <> '-Indices' do
  begin
    case tipoLinea of
      TL_Error: raise Exception.Create(
          'Error leyendo índices, en la Línea ' + IntToStr(kLineaLectura) +
          ', Parámetro Nro ' + IntToStr(kParamLectura) + ': ' + linea);
{      TL_Comentario       : comentariosObjetos.addComentarioDeLinea('Indices', linea, kLineaInicioDeSeccion, kLinea);
      TL_ComentarioGlobal : comentariosObjetos.addComentarioDeLinea('Indices', linea, kLineaInicioDeSeccion, kLinea);}
      TL_Objeto:
      begin
        try
          defIndice := leerIndice(linea);
          if prepararseParaCorrer then
          begin
            if defIndice.numSimRes = '*' then
            begin
              for numSimRes := 0 to lstSimRes_.Count - 1 do
              begin
                indice :=
                  TVarIdxs.Create(defIndice.nombreIndice + IntToStr(numSimRes + 1),
                  defIndice.nombreParticipe, defIndice.nombreVar,
                  IntToStr(numSimRes + 1));
                indice.prepararse(
                  TResultadoSim(lstSimRes_[numSimRes]));
                lstIdxs.Add(indice);
              end;
            end
            else
            begin
              numSimRes := StrToInt(defIndice.numSimRes) - 1;
              if (numSimRes >= lstSimRes_.Count) or (numSimRes < 0) then
                raise Exception.Create(
                  'No se encuentra el simRes número ' + IntToStr(numSimRes + 1) +
                  ' leyendo la línea ' + IntToStr(kLineaLectura));
              indice :=
                TVarIdxs.Create(defIndice.nombreIndice, defIndice.nombreParticipe,
                defIndice.nombreVar, defIndice.numSimRes);
              indice.prepararse(
                TResultadoSim(lstSimRes_[numSimRes]));
              lstIdxs.Add(indice);
            end;
            defIndice.Free;
          end
          else
          begin
            lstIdxs.Add(defIndice);
            lineasArchi[kLineaLectura - 1] :=
              tagsObjetos.addTagObjeto(defIndice);
          end;
          if comentarioDeObjeto.Count > 0 then
          begin
            comentariosObjetos.addComentarioDelObjeto(
              defIndice, comentarioDeObjeto);
            comentarioDeObjeto.Clear;
          end;
        except
          on E: Exception do
          begin
            E.Message :=
              e.Message + #13#10 + 'Leyendo índices, en la Línea ' +
              IntToStr(kLineaLectura) + ', Parámetro Nro ' +
              IntToStr(kParamLectura) + ': ' + linea;
            raise;
          end;
        end;
      end;
      //TL_EsperandoStr   : //Nada, sale por el while;
    end;
    tipoLinea := leerEIncrementarLinea(linea, '-Indices');
  end;
end;

procedure TLectorSimRes3Defs.LeerCron_Vars;
var
  linea: string;
  tipoLinea: TTipoLinea;
  cronVar: TCronVar;
begin
  clearListaDeObjetos(lstCronVars);
{  //Por ahora solo soportamos todos los CronVars con el número de crónicas del
  //simRes que tenga menor cantidad de crónicas y el número de pasos que haya en
  //la ventana [desde, hasta) en el primer simres
  nPasos:= round(((hasta - desde) * 24) / TResultadoSim(lstSimRes[0]).encabezado.durPaso);}

  //+CronVars
  repeat
    leerEIncrementarLinea(linea, '+CronVars');
  until linea = '+CronVars';

  tipoLinea := leerEIncrementarLinea(linea, '-CronVars');
  while linea <> '-CronVars' do
  begin
    case tipoLinea of
      TL_Error: raise Exception.Create(
          'Error leyendo CronVars, en la Línea ' + IntToStr(kLineaLectura) +
          ', Parámetro Nro ' + IntToStr(kParamLectura) + ': ' + linea);
{      TL_Comentario       : comentariosObjetos.addComentarioDeLinea('CronVars', linea, kLineaInicioDeSeccion, kLineaLectura);
      TL_ComentarioGlobal : comentariosObjetos.addComentarioDeLinea('CronVars', linea, kLineaInicioDeSeccion, kLineaLectura);}
      TL_Objeto:
      begin
        try
          cronVar := leerCronVar(linea);
          lstCronVars.Add(cronVar);
          lineasArchi[kLineaLectura - 1] :=
            tagsObjetos.addTagObjeto(cronVar);
          if comentarioDeObjeto.Count > 0 then
          begin
            comentariosObjetos.addComentarioDelObjeto(
              cronVar, comentarioDeObjeto);
            comentarioDeObjeto.Clear;
          end;
        except
          on E: Exception do
          begin
            E.Message :=
              e.Message + #13#10 + 'Leyendo CronVars, en la Línea ' +
              IntToStr(kLineaLectura) + ', Parámetro Nro ' +
              IntToStr(kParamLectura) + ': ' + linea;
            raise;
          end;
        end;
      end;
      //TL_EsperandoStr   : //Nada, sale por el while;
    end;
    tipoLinea := leerEIncrementarLinea(linea, '-CronVars');
  end;
end;

procedure TLectorSimRes3Defs.LeerCron_Opers(prepararseParaCorrer: boolean);
var
  linea: string;
  tipoLinea: TTipoLinea;
  cronOper: TCronOper;
begin
  clearListaDeObjetos(lstCronOpers);
  //+CronOpers
  repeat
    leerEIncrementarLinea(linea, '+CronOpers');
  until linea = '+CronOpers';

  tipoLinea := leerEIncrementarLinea(linea, '-CronOpers');
  while linea <> '-CronOpers' do
  begin
    case tipoLinea of
      TL_Error: raise Exception.Create(
          'Error leyendo CronOpers, en la Línea ' + IntToStr(kLineaLectura) +
          ', Parámetro Nro ' + IntToStr(kParamLectura) + ': ' + linea);
{      TL_Comentario       : comentariosObjetos.addComentarioDeLinea('CronOpers', linea, kLineaInicioDeSeccion, kLineaLectura);
      TL_ComentarioGlobal : comentariosObjetos.addComentarioDeLinea('CronOpers', linea, kLineaInicioDeSeccion, kLineaLectura);}
      TL_Objeto:
      begin
        try
          cronOper := leerCronOper(linea, prepararseParaCorrer);
          lstCronOpers.Add(cronOper);
          lineasArchi[kLineaLectura - 1] :=
            tagsObjetos.addTagObjeto(cronOper);
          if comentarioDeObjeto.Count > 0 then
          begin
            comentariosObjetos.addComentarioDelObjeto(
              cronOper, comentarioDeObjeto);
            comentarioDeObjeto.Clear;
          end;
        except
          on E: Exception do
          begin
            E.Message :=
              e.Message + #13#10 + 'Leyendo CronOpers, en la Línea ' +
              IntToStr(kLineaLectura) + ', Parámetro Nro ' +
              IntToStr(kParamLectura) + ': ' + linea;
            raise;
          end;
        end;
      end;
      //TL_EsperandoStr   : //Nada, sale por el while;
    end;
    tipoLinea := leerEIncrementarLinea(linea, '-CronOpers');
  end;
end;

procedure TLectorSimRes3Defs.LeerPost_Opers(prepararseParaCorrer: boolean);
var
  linea: string;
  tipoLinea: TTipoLinea;
  postOper: TPostOper;
begin
  clearListaDeObjetos(lstPostOpers);
  //+PostOpers
  repeat
    leerEIncrementarLinea(linea, '+PostOpers');
  until linea = '+PostOpers';

  tipoLinea := leerEIncrementarLinea(linea, '-PostOpers');
  while linea <> '-PostOpers' do
  begin
    case tipoLinea of
      TL_Error: raise Exception.Create(
          'Error leyendo PostOpers, en la Línea ' + IntToStr(kLineaLectura) +
          ', Parámetro Nro ' + IntToStr(kParamLectura) + ': ' + linea);
{      TL_Comentario       : comentariosObjetos.addComentarioDeLinea('PostOpers', linea, kLineaInicioDeSeccion, kLineaLectura);
      TL_ComentarioGlobal : comentariosObjetos.addComentarioDeLinea('PostOpers', linea, kLineaInicioDeSeccion, kLineaLectura);}
      TL_Objeto:
      begin
        try
          postOper := leerPostOper(linea, prepararseParaCorrer);
          lstPostOpers.Add(postOper);
          lineasArchi[kLineaLectura - 1] :=
            tagsObjetos.addTagObjeto(postOper);
          if comentarioDeObjeto.Count > 0 then
          begin
            comentariosObjetos.addComentarioDelObjeto(
              postOper, comentarioDeObjeto);
            comentarioDeObjeto.Clear;
          end;
        except
          on E: Exception do
          begin
            E.Message :=
              e.Message + #13#10 + 'Leyendo PostOpers, en la Línea ' +
              IntToStr(kLineaLectura) + ', Parámetro Nro ' +
              IntToStr(kParamLectura) + ': ' + linea;
            raise;
          end;
        end;
      end;
      //TL_EsperandoStr   : //Nada, sale por el while;
    end;
    tipoLinea := leerEIncrementarLinea(linea, '-PostOpers');
  end;
end;

procedure TLectorSimRes3Defs.LeerPrintCronVars;
var
  linea: string;
  tipoLinea: TTipoLinea;
  printCronVar: TPrintCronVar;
begin
  clearListaDeObjetos(lstPrintCronVars);
  //+PrintCronVars
  repeat
    leerEIncrementarLinea(linea, '+PrintCronVars');
  until linea = '+PrintCronVars';

  tipoLinea := leerEIncrementarLinea(linea, '-PrintCronVars');
  while linea <> '-PrintCronVars' do
  begin
    case tipoLinea of
      TL_Error: raise Exception.Create(
          'Error leyendo PrintCronVars, en la Línea ' + IntToStr(kLineaLectura) +
          ', Parámetro Nro ' + IntToStr(kParamLectura) + ': ' + linea);
{      TL_Comentario       : comentariosObjetos.addComentarioDeLinea('PrintCronVars', linea, kLineaInicioDeSeccion, kLineaLectura);
      TL_ComentarioGlobal : comentariosObjetos.addComentarioDeLinea('PrintCronVars', linea, kLineaInicioDeSeccion, kLineaLectura);}
      TL_Objeto:
      begin
        try
          printCronVar := leerPrintCronVar(linea);
          lstPrintCronVars.Add(printCronVar);
          lineasArchi[kLineaLectura - 1] :=
            tagsObjetos.addTagObjeto(printCronVar);
          //comentarioDeObjeto acumular las lineas comentadas directamente antes de
          //este objeto
          if comentarioDeObjeto.Count > 0 then
          begin
            comentariosObjetos.addComentarioDelObjeto(
              printCronVar, comentarioDeObjeto);
            comentarioDeObjeto.Clear;
          end;
        except
          on E: Exception do
          begin
            E.Message :=
              e.Message + #13#10 + 'Leyendo PrintCronVars, en la Línea ' +
              IntToStr(kLineaLectura) + ', Parámetro Nro ' +
              IntToStr(kParamLectura) + ': ' + linea;
            raise;
          end;
        end;
      end;
      //      TL_EsperandoStr   : ;
    end;
    tipoLinea := leerEIncrementarLinea(linea, '-PrintCronVars');
  end;
end;

procedure TLectorSimRes3Defs.WriteLnSimRes(var f: TextFile; s: string);
begin
  Writeln(f, s);
  kLineaLectura := kLineaLectura + nroOcurrencias(#13#10, s) + 1;
end;

procedure TLectorSimRes3Defs.WriteLnSimRes(var f: TextFile);
begin
  Writeln(f);
  kLineaLectura := kLineaLectura + 1;
end;

procedure TLectorSimRes3Defs.avanzarkLineaHastaLinea(linea: string);
begin
  while (kLineaLectura < lineasArchi.Count) and
    (lineasArchi[kLineaLectura] <> linea) do
    kLineaLectura := kLineaLectura + 1;
end;

procedure TLectorSimRes3Defs.escribirLineasHastaLinea(var f: TextFile; linea: string);
begin
  while (kLineaLectura < lineasArchi.Count) and
    (lineasArchi[kLineaLectura] <> linea) do
    WriteLnSimRes(f, lineasArchi[kLineaLectura]);
end;

procedure TLectorSimRes3Defs.EscribirSimRes(var f: TextFile);
var
  i: integer;
begin
  avanzarkLineaHastaLinea('+SimRes');
  WriteLnSimRes(f, '+SimRes');

  for i := 0 to archisSimRes.Count - 1 do
  begin
    //Si estoy creando uno nuevo no leí las líneas donde estaban los archiSimRes
    if Length(kLineasArchisSimRes) > 0 then
      while kLineaLectura < kLineasArchisSimRes[i] do
        WriteLnSimRes(f, lineasArchi[kLineaLectura]);
    WriteLnSimRes(f, '"' + archisSimRes[i] + '"');
  end;

  escribirLineasHastaLinea(f, '-SimRes');

  WriteLnSimRes(f, '-SimRes');
  WriteLnSimRes(f);
end;

procedure TLectorSimRes3Defs.EscribirFechas(var f: TextFile);
begin
  avanzarkLineaHastaLinea('+Fechas');
  WriteLnSimRes(f, '+Fechas');

  while kLineaLectura < kLineaFechaIni do
    WriteLnSimRes(f, lineasArchi[kLineaLectura]);
  WriteLnSimRes(f, fechaDesde);

  while kLineaLectura < kLineaFechaFin do
    WriteLnSimRes(f, lineasArchi[kLineaLectura]);
  WriteLnSimRes(f, fechaHasta);

  escribirLineasHastaLinea(f, '-Fechas');
  WriteLnSimRes(f, '-Fechas');
  WriteLnSimRes(f);
end;

procedure TLectorSimRes3Defs.EscribirIndices(var f: TextFile);
var
  i: integer;
  linea, comentario: string;
  aux: TList;
  indice: TVarIdxs;
begin
  avanzarkLineaHastaLinea('+Indices');
  WriteLnSimRes(f, '+Indices');

  aux := clonarTList(lstIdxs);
  while (kLineaLectura < lineasArchi.Count) and
    (lineasArchi[kLineaLectura] <> '-Indices') do
  begin
    linea := lineasArchi[kLineaLectura];
    if Pos(strTag, linea) > 0 then
    begin
      indice := TVarIdxs(tagsObjetos.getObjeto(linea));
      comentario := comentariosObjetos.comentarioDelObjetoConSimbolos(indice);
      if comentario <> '' then
        WriteLnSimRes(f, comentario);
      WriteLnSimRes(f, indice.serialize);
      aux.Remove(indice);
    end
    else
      WriteLnSimRes(f, linea);
  end;

  escribirLineasHastaLinea(f, '-Indices');

  //Escribo los indices que se hayan agregado despues de la lectura y que por lo
  //tanto no tienen tag
  for i := 0 to aux.Count - 1 do
  begin
    indice := aux[i];
    comentario := comentariosObjetos.comentarioDelObjetoConSimbolos(indice);
    if comentario <> '' then
      WriteLnSimRes(f, comentario);
    WriteLnSimRes(f, indice.serialize);
  end;
  aux.Free;

  WriteLnSimRes(f, '-Indices');
  WriteLnSimRes(f);
end;

procedure TLectorSimRes3Defs.EscribirCron_Vars(var f: TextFile);
var
  i: integer;
  linea, comentario: string;
  aux: TList;
  cronVar: TCronVar;
begin
  avanzarkLineaHastaLinea('+CronVars');
  WriteLnSimRes(f, '+CronVars');

  aux := clonarTList(lstCronVars);
  while (kLineaLectura < lineasArchi.Count) and
    (lineasArchi[kLineaLectura] <> '-CronVars') do
  begin
    linea := lineasArchi[kLineaLectura];
    if Pos(strTag, linea) > 0 then
    begin
      cronVar := TCronVar(tagsObjetos.getObjeto(linea));
      comentario := comentariosObjetos.comentarioDelObjetoConSimbolos(cronVar);
      if comentario <> '' then
        WriteLnSimRes(f, comentario);
      WriteLnSimRes(f, cronVar.serialize);
      aux.Remove(cronVar);
    end
    else
      WriteLnSimRes(f, linea);
  end;

  escribirLineasHastaLinea(f, '-CronVars');

  //Escribo los indices que se hayan agregado despues de la lectura y que por lo
  //tanto no tienen tag
  for i := 0 to aux.Count - 1 do
  begin
    cronVar := aux[i];
    comentario := comentariosObjetos.comentarioDelObjetoConSimbolos(cronVar);
    if comentario <> '' then
      WriteLnSimRes(f, comentario);
    WriteLnSimRes(f, cronVar.serialize);
  end;
  aux.Free;

  WriteLnSimRes(f, '-CronVars');
  WriteLnSimRes(f);
end;

procedure TLectorSimRes3Defs.EscribirCron_Opers(var f: TextFile);
var
  i: integer;
  linea, comentario: string;
  aux: TList;
  cronOper: TCronOper;
begin
  avanzarkLineaHastaLinea('+CronOpers');
  WriteLnSimRes(f, '+CronOpers');

  aux := clonarTList(lstCronOpers);
  while (kLineaLectura < lineasArchi.Count) and
    (lineasArchi[kLineaLectura] <> '-CronOpers') do
  begin
    linea := lineasArchi[kLineaLectura];
    if Pos(strTag, linea) > 0 then
    begin
      cronOper := TCronOper(tagsObjetos.getObjeto(linea));
      comentario := comentariosObjetos.comentarioDelObjetoConSimbolos(cronOper);
      if comentario <> '' then
        WriteLnSimRes(f, comentario);
      WriteLnSimRes(f, cronOper.serialize);
      aux.Remove(cronOper);
    end
    else
      WriteLnSimRes(f, linea);
  end;

  escribirLineasHastaLinea(f, '-CronOpers');

  //Escribo los indices que se hayan agregado despues de la lectura y que por lo
  //tanto no tienen tag
  for i := 0 to aux.Count - 1 do
  begin
    cronOper := aux[i];
    comentario := comentariosObjetos.comentarioDelObjetoConSimbolos(cronOper);
    if comentario <> '' then
      WriteLnSimRes(f, comentario);
    WriteLnSimRes(f, cronOper.serialize);
  end;
  aux.Free;

  WriteLnSimRes(f, '-CronOpers');
  WriteLnSimRes(f);
end;

procedure TLectorSimRes3Defs.EscribirPost_Opers(var f: TextFile);
var
  i: integer;
  linea, comentario: string;
  aux: TList;
  postOper: TPostOper;
begin
  avanzarkLineaHastaLinea('+PostOpers');
  WriteLnSimRes(f, '+PostOpers');

  aux := clonarTList(lstPostOpers);
  while (kLineaLectura < lineasArchi.Count) and
    (lineasArchi[kLineaLectura] <> '-PostOpers') do
  begin
    linea := lineasArchi[kLineaLectura];
    if Pos(strTag, linea) > 0 then
    begin
      postOper := TPostOper(tagsObjetos.getObjeto(linea));
      comentario := comentariosObjetos.comentarioDelObjetoConSimbolos(postOper);
      if comentario <> '' then
        WriteLnSimRes(f, comentario);
      WriteLnSimRes(f, postOper.serialize);
      aux.Remove(postOper);
    end
    else
      WriteLnSimRes(f, linea);
  end;

  escribirLineasHastaLinea(f, '-PostOpers');

  //Escribo los indices que se hayan agregado despues de la lectura y que por lo
  //tanto no tienen tag
  for i := 0 to aux.Count - 1 do
  begin
    postOper := aux[i];
    comentario := comentariosObjetos.comentarioDelObjetoConSimbolos(postOper);
    if comentario <> '' then
      WriteLnSimRes(f, comentario);
    WriteLnSimRes(f, postOper.serialize);
  end;
  aux.Free;

  WriteLnSimRes(f, '-PostOpers');
  WriteLnSimRes(f);
end;

procedure TLectorSimRes3Defs.EscribirPrintCronVars(var f: TextFile);
var
  i: integer;
  linea, comentario: string;
  aux: TList;
  printCronVar: TPrintCronVar;
begin
  avanzarkLineaHastaLinea('+PrintCronVars');
  WriteLnSimRes(f, '+PrintCronVars');

  aux := clonarTList(lstPrintCronVars);
  while (kLineaLectura < lineasArchi.Count) and
    (lineasArchi[kLineaLectura] <> '-PrintCronVars') do
  begin
    linea := lineasArchi[kLineaLectura];
    if Pos(strTag, linea) > 0 then
    begin
      printCronVar := TPrintCronVar(tagsObjetos.getObjeto(linea));
      comentario := comentariosObjetos.comentarioDelObjetoConSimbolos(printCronVar);
      if comentario <> '' then
        WriteLnSimRes(f, comentario);
      WriteLnSimRes(f, printCronVar.serialize);
      aux.Remove(printCronVar);
    end
    else
      WriteLnSimRes(f, linea);
  end;

  escribirLineasHastaLinea(f, '-PrintCronVars');

  //Escribo los indices que se hayan agregado despues de la lectura y que por lo
  //tanto no tienen tag
  for i := 0 to aux.Count - 1 do
  begin
    printCronVar := aux[i];
    comentario := comentariosObjetos.comentarioDelObjetoConSimbolos(printCronVar);
    if comentario <> '' then
      WriteLnSimRes(f, comentario);
    WriteLnSimRes(f, printCronVar.serialize);
  end;
  aux.Free;

  WriteLnSimRes(f, '-PrintCronVars');
  WriteLnSimRes(f);
end;


function TLectorSimRes3Defs.leerIndice(linea: string): TVarIdxs;
var
  nomIndice, nomActor, nomVar, strSimRes: string;
  indice: TVarIdxs;
begin
  nomIndice := readPal(linea);
  nomActor := readPal(linea);
  if self.versionArchivo < 18 then
    if nomActor = '-' then
      nomActor := 'Sala';
  nomVar := readPal(linea);
  strSimRes := readPal(linea);
  indice := TVarIdxs.Create(nomIndice, nomActor, nomVar, strSimRes);

  Result := indice;
end;

function TLectorSimRes3Defs.leerCronVar(linea: string): TCronVar;
var
  nomCronVar: string;
begin
  nomCronVar := readPal(linea);
  Result := TCronVar.Create(nomCronVar);
end;

function TLectorSimRes3Defs.leerCronOper(linea: string;
  prepararseParaCorrer: boolean): TCronOper;
var
  tipoOper: string;

  nomCronVar, nomCronVar2, nomIndice, nomIndice2: string;
  indexArray: TDAOfTVarIdxs;
  intParam1, i: integer;
  realParam1: NReal;
  realArray: TDAOfNReal;
  cronOper: TCronOper;
  modoComp, flg_AcumProducto: boolean;
begin
  tipoOper := LowerCase(readPal(linea));

  if tipoOper = LowerCase(TCronOper_suma.tipo) then
  begin
    nomCronVar := readPal(linea);
    nomIndice := readPal(linea);
    cronOper := TCronOper_suma.Create(getCronVarByName(nomCronVar),
      getIndiceByName(nomIndice));
  end
  else if tipoOper = LowerCase(TCronOper_sumaConSigno.tipo) then
  begin
    nomCronVar := readPal(linea);
    nomCronVar2 := readPal(linea);
    nomIndice := readPal(linea);
    cronOper := TCronOper_sumaConSigno.Create(getCronVarByName(nomCronVar),
      getCronVarByName(nomCronVar2), getIndiceByName(nomIndice));
  end
  else if tipoOper = LowerCase(TCronOper_Combinar.tipo) then
  begin
    nomCronVar := readPal(linea);
    intParam1 := StrToInt(readPal(linea));
    SetLength(realArray, intParam1);
    for i := 0 to intParam1 - 1 do
      realArray[i] := StrToFloat(readPal(linea));
    SetLength(indexArray, intParam1);
    for i := 0 to intParam1 - 1 do
    begin
      nomIndice := readPal(linea);
      indexArray[i] := getIndiceByName(nomIndice);
    end;

    cronOper := TCronOper_Combinar.Create(getCronVarByName(nomCronVar),
      indexArray, realArray);
  end
  else if tipoOper = LowerCase(TCronOper_promedio.tipo) then
  begin
    nomCronVar := readPal(linea);
    nomIndice := readPal(linea);

    cronOper := TCronOper_promedio.Create(getCronVarByName(nomCronVar),
      getIndiceByName(nomIndice));
  end
  else if tipoOper = LowerCase(TCronOper_sumaProductoConDurpos.tipo) then
  begin
    nomCronVar := readPal(linea);
    nomIndice := readPal(linea);

    cronOper := TCronOper_sumaProductoConDurpos.Create(getCronVarByName(nomCronVar),
      getIndiceByName(nomIndice));
  end
  else if tipoOper = LowerCase(TCronOper_sumaProductoConDurposHasta.tipo) then
  begin
    nomCronVar := readPal(linea);
    nomIndice := readPal(linea);
    intParam1 := StrToInt(readPal(linea));

    cronOper := TCronOper_sumaProductoConDurposHasta.Create(
      getCronVarByName(nomCronVar), getIndiceByName(nomIndice), intParam1);
  end
  else if tipoOper = LowerCase(TCronOper_filtrarCronica.tipo) then
  begin
    nomCronVar := readPal(linea);
    nomIndice := readPal(linea);
    intParam1 := StrToInt(readPal(linea));

    cronOper := TCronOper_filtrarCronica.Create(getCronVarByName(nomCronVar),
      getIndiceByName(nomIndice), intParam1);
  end
  else if tipoOper = LowerCase(TCronOper_sumaProductoConDurposTopeado.tipo) then
  begin
    nomCronVar := readPal(linea);
    nomCronVar2 := readPal(linea);
    nomIndice := readPal(linea);
    realParam1 := StrToFloat(readPal(linea));

    cronOper := TCronOper_sumaProductoConDurposTopeado.Create(
      getCronVarByName(nomCronVar), getCronVarByName(nomCronVar2),
      getIndiceByName(nomIndice), realParam1);
  end
  else if tipoOper = LowerCase(TCronOper_sumaDobleProductoConDurposTopeado.tipo) then
  begin
    nomCronVar := readPal(linea);
    nomCronVar2 := readPal(linea);
    nomIndice := readPal(linea);
    nomIndice2 := readPal(linea);
    realParam1 := StrToFloat(readPal(linea));

    if versionArchivo < 9 then
      modoComp := False
    else
      modoComp := StrToBool(readPal(linea));

    if versionArchivo < 11 then
      flg_AcumProducto := False
    else
      flg_AcumProducto := StrToBool(readPal(linea));


    cronOper := TCronOper_sumaDobleProductoConDurposTopeado.Create(
      getCronVarByName(nomCronVar), getCronVarByName(nomCronVar2),
      getIndiceByName(nomIndice), getIndiceByName(nomIndice2),
      realParam1, modoComp, flg_AcumProducto);
  end
  else if tipoOper = LowerCase(TCronOper_promedioPonderadoPorDurpos.tipo) then
  begin
    nomCronVar := readPal(linea);
    nomIndice := readPal(linea);

    cronOper := TCronOper_promedioPonderadoPorDurpos.Create(
      getCronVarByName(nomCronVar), getIndiceByName(nomIndice));
  end
  else if tipoOper = LowerCase(TCronOper_suma_m.tipo) then
  begin
    nomCronVar := readPal(linea);
    intParam1 := StrToInt(readPal(linea));
    SetLength(indexArray, intParam1);
    for i := 0 to intParam1 - 1 do
    begin
      nomIndice := readPal(linea);
      indexArray[i] := getIndiceByName(nomIndice);
    end;

    cronOper := TCronOper_suma_m.Create(getCronVarByName(nomCronVar), indexArray);
  end
  else if tipoOper = LowerCase(TCronOper_promedio_m.tipo) then
  begin
    nomCronVar := readPal(linea);
    intParam1 := StrToInt(readPal(linea));
    SetLength(indexArray, intParam1);
    for i := 0 to intParam1 - 1 do
    begin
      nomIndice := readPal(linea);
      indexArray[i] := getIndiceByName(nomIndice);
    end;

    cronOper := TCronOper_promedio_m.Create(getCronVarByName(nomCronVar),
      indexArray);
  end
  else if tipoOper = LowerCase(TCronOper_sumaProductoConDurpos_m.tipo) then
  begin
    nomCronVar := readPal(linea);
    intParam1 := StrToInt(readPal(linea));
    SetLength(indexArray, intParam1);
    for i := 0 to intParam1 - 1 do
    begin
      nomIndice := readPal(linea);
      indexArray[i] := getIndiceByName(nomIndice);
    end;

    cronOper := TCronOper_sumaProductoConDurpos_m.Create(getCronVarByName(nomCronVar),
      indexArray);
  end

  else if tipoOper = LowerCase(TCronOper_promedioPonderadoConDurpos_m.tipo) then
  begin
    nomCronVar := readPal(linea);
    intParam1 := StrToInt(readPal(linea));
    SetLength(indexArray, intParam1);
    for i := 0 to intParam1 - 1 do
    begin
      nomIndice := readPal(linea);
      indexArray[i] := getIndiceByName(nomIndice);
    end;

    cronOper := TCronOper_promedioPonderadoConDurpos_m.Create(
      getCronVarByName(nomCronVar), indexArray);
  end
  else if tipoOper = LowerCase(TCronOper_Maximo_m.tipo) then
  begin
    nomCronVar := readPal(linea);
    intParam1 := StrToInt(readPal(linea));
    SetLength(indexArray, intParam1);
    for i := 0 to intParam1 - 1 do
    begin
      nomIndice := readPal(linea);
      indexArray[i] := getIndiceByName(nomIndice);
    end;

    cronOper := TCronOper_Maximo_m.Create(getCronVarByName(nomCronVar), indexArray);
  end
  else
    raise Exception.Create('Tipo de Operación Desconocido "' +
      tipoOper + '"' + ' leyendo la línea ' + IntToStr(kLineaLectura));
  if prepararseParaCorrer then
  begin
    writeln('Preparando CronOper: ', CronOper.tipo);
    cronOper.prepararse;
  end;
  Result := cronOper;
end;

function TLectorSimRes3Defs.leerPostOper(linea: string;
  prepararseParaCorrer: boolean): TPostOper;
var
  tipoOper: string;
  nomCronVarRes, nomParam1, nomParam2, nomParam3: string;
  realParam1: NReal;
  realParam2: NReal;
  //  realParam3: NReal;
  i, intParam1, intParam2: integer;
  boolParam1: boolean;
  cronVarArray: TDAOfCronVar;
  coefVarArray: TDAOfNReal;
  despVarArray: TDAOfNInt;
  postOper: TPostOper;
  cronVarLst: TList;
begin
  tipoOper := LowerCase(readPal(linea));

  if tipoOper = LowerCase(TPostOper_minEntreCronVarYReal.tipo) then
  begin
    nomCronVarRes := readPal(linea);
    nomParam1 := readPal(linea);
    realParam1 := StrToFloat(readPal(linea));
    postOper := TPostOper_minEntreCronVarYReal.Create(getCronVarByName(nomCronVarRes),
      getCronVarByName(nomParam1), realParam1);
  end
  else if tipoOper = LowerCase(TPostOper_CrearConstanteReal.tipo) then
  begin
    nomCronVarRes := readPal(linea);
    realParam1 := StrToFloat(readPal(linea));
    postOper := TPostOper_CrearConstanteReal.Create(
      getCronVarByName(nomCronVarRes), realParam1);
  end
  else if tipoOper = LowerCase(TPostOper_maxEntreCronVarYReal.tipo) then
  begin
    nomCronVarRes := readPal(linea);
    nomParam1 := readPal(linea);
    realParam1 := StrToFloat(readPal(linea));
    postOper := TPostOper_maxEntreCronVarYReal.Create(getCronVarByName(nomCronVarRes),
      getCronVarByName(nomParam1), realParam1);
  end
  else if tipoOper = LowerCase(TPostOper_CronVarMasReal.tipo) then
  begin
    nomCronVarRes := readPal(linea);
    nomParam1 := readPal(linea);
    realParam1 := StrToFloat(readPal(linea));
    postOper := TPostOper_CronVarMasReal.Create(getCronVarByName(nomCronVarRes),
      getCronVarByName(nomParam1), realParam1);
  end
  else if tipoOper = LowerCase(TPostOper_CronVarPorReal.tipo) then
  begin
    nomCronVarRes := readPal(linea);
    nomParam1 := readPal(linea);
    realParam1 := StrToFloat(readPal(linea));
    postOper := TPostOper_CronVarPorReal.Create(getCronVarByName(nomCronVarRes),
      getCronVarByName(nomParam1), realParam1);
  end
  else if tipoOper = LowerCase(TPostOper_RestaCronVars.tipo) then
  begin
    nomCronVarRes := readPal(linea);
    nomParam1 := readPal(linea);
    nomParam2 := readPal(linea);
    postOper := TPostOper_RestaCronVars.Create(getCronVarByName(nomCronVarRes),
      getCronVarByName(nomParam1), getCronVarByName(nomParam2));
  end
  else if tipoOper = LowerCase('cronVarSobreReal') then
  begin
    nomCronVarRes := readPal(linea);
    nomParam1 := readPal(linea);
    realParam1 := 1 / StrToFloat(readPal(linea));

    postOper := TPostOper_CronVarPorReal.Create(getCronVarByName(nomCronVarRes),
      getCronVarByName(nomParam1), realParam1);
  end
  else if tipoOper = LowerCase(TPostOper_combinarCronVars.tipo) then
  begin
    nomCronVarRes := readPal(linea);
    intParam1 := StrToInt(readPal(linea));
    setLength(coefVarArray, intParam1);
    SetLength(cronVarArray, intParam1);

    for i := 0 to intParam1 - 1 do
      coefVarArray[i] := StrToFloat(readPal(linea));

    for i := 0 to intParam1 - 1 do
    begin
      nomParam1 := readPal(linea);
      cronVarArray[i] := getCronVarByName(nomParam1);
    end;

    postOper := TPostOper_CombinarCronVars.Create(getCronVarByName(nomCronVarRes),
      cronVarArray, coefVarArray);
  end
  else if tipoOper = LowerCase(TPostOper_combinarDespCronVars.tipo) then
  begin
    nomCronVarRes := readPal(linea);
    intParam1 := StrToInt(readPal(linea));
    setLength(coefVarArray, intParam1);
    SetLength(cronVarArray, intParam1);
    setlength(despVarArray, intParam1);

    for i := 0 to intParam1 - 1 do
      coefVarArray[i] := StrToFloat(readPal(linea));

    for i := 0 to intParam1 - 1 do
      despVarArray[i] := StrToInt(readPal(linea));

    for i := 0 to intParam1 - 1 do
    begin
      nomParam1 := readPal(linea);
      cronVarArray[i] := getCronVarByName(nomParam1);
    end;

    postOper := TPostOper_CombinarDespCronVars.Create(getCronVarByName(nomCronVarRes),
      cronVarArray, coefVarArray, despVarArray);
  end
  else if tipoOper = LowerCase(TPostOper_aplicarActualizador.tipo) then
  begin
    nomCronVarRes := readPal(linea);
    nomParam1 := readPal(linea);
    realParam1 := nextFloat(linea);

    postOper := TPostOper_AplicarActualizador.Create(getCronVarByName(nomCronVarRes),
      getCronVarByName(nomParam1), realParam1);
  end
  else if tipoOper = LowerCase(TPostOper_multiplicacionCronVars.tipo) then
  begin
    nomCronVarRes := readPal(linea);
    nomParam1 := readPal(linea);
    nomParam2 := readPal(linea);

    postOper := TPostOper_multiplicacionCronVars.Create(getCronVarByName(nomCronVarRes),
      getCronVarByName(nomParam1), getCronVarByName(nomParam2));
  end
  else if tipoOper = LowerCase(TPostOper_DivisionCronVars.tipo) then
  begin
    nomCronVarRes := readPal(linea);
    nomParam1 := readPal(linea);
    nomParam2 := readPal(linea);

    postOper := TPostOper_DivisionCronVars.Create(getCronVarByName(nomCronVarRes),
      getCronVarByName(nomParam1), getCronVarByName(nomParam2));
  end
  else if tipoOper = LowerCase(TPostOper_cambioPasoDeTiempo.tipo) then
  begin

    nomCronVarRes := readPal(linea);
    nomParam1 := readPal(linea);
    realParam1 := StrToFloat(readPal(linea));

    intParam2 := -1;

    if versionArchivo > 11 then
      // En esta version se mantienen las operaciones
    begin                                         // PROM y SUMA y se agrega la opcion de
      intParam1 := StrToInt(readPal(linea));      // seleccionar entradas
      intParam2 := StrToInt(readPal(linea));
      // MIN, MAX e i-esima (esto incluya al primero y al ultimo)
    end
    else if versionArchivo > 7 then               //  En la segunda version las opciones
    begin                                         //  eran MIN, MAX, PROM, SUMA, PRIMIRO y ULTIMO
      intParam1 := StrToInt(readPal(linea));

      if (intParam1 = 2) then // estaba seleccionado el primero
      begin
        intParam1 := 4;
        intParam2 := 0;
      end;
      if (intParam1 = 5) then // estaba seleccionado el ultimo
      begin
        intParam1 := 4;
        intParam2 := getCronVarByName(nomParam1).nPasos;
      end;
      if (intParam1 = 4) then // estaba seleccionado el maximo
      begin
        intParam1 := 3;
      end;
      if (intParam1 = 3) then // estaba seleccionado la suma
      begin
        intParam1 := 2;
      end;

    end
    else
    begin
      boolParam1 := StrToBool(readPal(linea));   // En la primera version
      if boolParam1 then                        // con un checkbox se
        intParam1 := 0 // TCPT_Promedio           // elegia si sumar o promediar
      else
        intParam1 := 2; // TCPT_Suma
    end;

    postOper := TPostOper_cambioPasoDeTiempo.Create(getCronVarByName(nomCronVarRes),
      getCronVarByName(nomParam1), realParam1, TTipoCPT(intParam1), intParam2);

  end

  else if tipoOper = LowerCase(TPostOper_CVaR.tipo) then
  begin
    nomCronVarRes := readPal(linea);
    nomParam1 := readPal(linea);
    realParam1 := StrToFloat(readPal(linea));
    realParam2 := StrToFloat(readPal(linea));
    intParam1 := StrToInt(readPal(linea));

    postOper := TPostOper_CVaR.Create(getCronVarByName(nomCronVarRes),
      getCronVarByName(nomParam1), realParam1, realParam2, intParam1);
  end

  else if tipoOper = LowerCase(TPostOper_acumularCronVar.tipo) then
  begin
    nomCronVarRes := readPal(linea);
    nomParam1 := readPal(linea);

    postOper := TPostOper_acumularCronVar.Create(getCronVarByName(nomCronVarRes),
      getCronVarByName(nomParam1));
  end
  else if tipoOper = LowerCase(TPostOper_acumularConPisoYTecho.tipo) then
  begin
    nomCronVarRes := readPal(linea); // Res
    nomParam1 := readPal(linea); // Ingreso
    nomParam2 := readPal(linea); // Piso
    nomParam3 := readPal(linea); // Techo
    realParam1 := StrToFloat(readPal(linea));
    postOper := TPostOper_acumularConPisoYTecho.Create(
      getCronVarByName(nomCronVarRes), getCronVarByName(nomParam1),
      getCronVarByName(nomParam2), getCronVarByName(nomParam3), realParam1);
  end
  else if tipoOper = LowerCase(TPostOper_potenciaFirmeHidraulica.tipo) then
  begin
    nomCronVarRes := readPal(linea);
    intParam1 := StrToInt(readPal(linea));
    SetLength(cronVarArray, intParam1);
    for i := 0 to intParam1 - 1 do
    begin
      nomParam1 := readPal(linea);
      cronVarArray[i] := getCronVarByName(nomParam1);
    end;

    postOper := TPostOper_potenciaFirmeHidraulica.Create(
      getCronVarByName(nomCronVarRes), cronVarArray);
  end
  else if tipoOper = LowerCase(TPostOper_maximo.tipo) then
  begin
    nomCronVarRes := readPal(linea);
    intParam1 := StrToInt(readPal(linea));
    SetLength(cronVarArray, intParam1);

    for i := 0 to intParam1 - 1 do
    begin
      nomParam1 := readPal(linea);
      cronVarArray[i] := getCronVarByName(nomParam1);
    end;

    postOper := TPostOper_maximo.Create(getCronVarByName(nomCronVarRes),
      cronVarArray);
  end
  else if tipoOper = LowerCase(TPostOper_MultiOrdenar.tipo) then
  begin
    nomCronVarRes := readPal(linea);
    intParam1 := StrToInt(readPal(linea));

    cronVarLst := TList.Create;
    for i := 0 to intParam1 - 1 do
    begin
      nomParam1 := readPal(linea);
      if nomCronVarRes <> nomParam1 then
        cronVarLst.Add(getCronVarByName(nomParam1));
    end;

    SetLength(cronVarArray, cronVarLst.Count);
    for i := 0 to cronVarLst.Count - 1 do
      cronVarArray[i] := TCronVar(cronVarLst[i]);

    cronVarLst.Free;

    postOper := TPostOper_MultiOrdenar.Create(getCronVarByName(nomCronVarRes),
      cronVarArray);
  end
  else if tipoOper = LowerCase(TPostOper_MultiPromedioMovil.tipo) then
  begin
    nomCronVarRes := readPal(linea);
    intParam1 := StrToInt(readPal(linea));
    SetLength(cronVarArray, intParam1);

    for i := 0 to intParam1 - 1 do
    begin
      nomParam1 := readPal(linea);
      cronVarArray[i] := getCronVarByName(nomParam1);
    end;

    intParam1 := StrToInt(readPal(linea));

    postOper := TPostOper_MultiPromedioMovil.Create(getCronVarByName(nomCronVarRes),
      cronVarArray, intParam1);
  end

  else if tipoOper = LowerCase(TPostOper_MonotonizarCronVars.tipo) then
  begin
    nomCronVarRes := readPal(linea);
    intParam1 := StrToInt(readPal(linea));
    SetLength(cronVarArray, intParam1);

    for i := 0 to intParam1 - 1 do
    begin
      nomParam1 := readPal(linea);
      cronVarArray[i] := getCronVarByName(nomParam1);
    end;

    intParam1 := StrToInt(readPal(linea));
    boolParam1 := StrToBool(readPal(linea));
    postOper := TPostOper_MonotonizarCronVars.Create(getCronVarByName(nomCronVarRes),
      cronVarArray, intParam1, boolParam1);
  end
  else if tipoOper = LowerCase(TPostOper_Recronizar.tipo) then
  begin
    nomCronVarRes := readPal(linea);
    nomParam1 := readPal(linea);
    intParam1 := StrToInt(readPal(linea));

    postOper := TPostOper_Recronizar.Create(getCronVarByName(nomCronVarRes),
      getCronVarByName(nomParam1), intParam1);
  end
  // 14.5.18 - ireyes - gflieller
  else if tipoOper = LowerCase(TPostOper_Concatenar.tipo) then
  begin
    nomCronVarRes := readPal(linea);
    nomParam1 := readPal(linea);

    postOper := TPostOper_Concatenar.Create(getCronVarByName(nomCronVarRes),
      getCronVarByName(nomParam1));
  end


  else if tipoOper = LowerCase(TPostOper_ParalelizarCronVars.tipo) then
  begin
    nomCronVarRes := readPal(linea);
    intParam1 := StrToInt(readPal(linea));
    SetLength(cronVarArray, intParam1);

    for i := 0 to intParam1 - 1 do
    begin
      nomParam1 := readPal(linea);
      cronVarArray[i] := getCronVarByName(nomParam1);
    end;

    postOper := TPostOper_ParalelizarCronVars.Create(getCronVarByName(nomCronVarRes),
      cronVarArray);
  end

  else if tipoOper = LowerCase(TPostOper_Enventanar.tipo) then
  begin
    nomCronVarRes := readPal(linea);
    nomParam1 := readPal(linea);
    realParam1 := StrToFloat(readPal(linea));
    realParam2 := StrToFloat(readPal(linea));

    postOper := TPostOper_Enventanar.Create(getCronVarByName(nomCronVarRes),
      getCronVarByName(nomParam1), realParam1, realParam2);
  end
  else if tipoOper = LowerCase(TPostOper_Transponer.tipo) then
  begin
    nomCronVarRes := readPal(linea);
    nomParam1 := readPal(linea);

    postOper := TPostOper_Transponer.Create(getCronVarByName(nomCronVarRes),
      getCronVarByName(nomParam1));
  end
  else if tipoOper = LowerCase(TPostOper_AcumCron.tipo) then
  begin
    nomCronVarRes := readPal(linea);
    nomParam1 := readPal(linea);
    boolParam1 := StrToBool(readPal(linea));
    intParam1 := StrToInt(readPal(linea));

    postOper := TPostOper_AcumCron.Create(getCronVarByName(nomCronVarRes),
      getCronVarByName(nomParam1), boolParam1, TSentidoAcumCron(intParam1));
  end


  else
    raise Exception.Create('Tipo de Post Operación desconocido "' +
      tipoOper + '" leyendo la línea ' + IntToStr(kLineaLectura));

  if prepararseParaCorrer then
    try
      writeln('Preparando PostOper: ', postOper.tipo);
      postOper.prepararse;
    except
      on E: Exception do
      begin
        raise Exception.Create('PostOper: ' + postOper.tipo + ' ' + E.Message);
      end;
    end;

  Result := postOper;
end;


function TLectorSimRes3Defs.leerPrintCronVar(linea: string): TPrintCronVar;
var
  tipoPrint: string;
  titulosCols: TDAofString;
  nomCronVar, nombreHoja, titulo: string;

  titulo_ejeX: string;

  titulo_eje1: string;
  digitos_eje1, decimales_eje1: integer;
  minEjeYAuto_eje1, maxEjeYAuto_eje1: boolean;
  minEjeY_eje1, maxEjeY_eje1: NReal;

  titulo_eje2: string;
  digitos_eje2, decimales_eje2: integer;
  minEjeYAuto_eje2, maxEjeYAuto_eje2: boolean;
  minEjeY_eje2, maxEjeY_eje2: NReal;

  Print_Todas, Print_promedio: boolean;
  Pre_Ordenar: boolean;
  TipoIMpresion_PE: boolean;
  i, n: integer;
  Print_probAisladas: TDAofNReal;
  chart_Mat: boolean;
  printCronVar: TPrintCronVar;
  minX, maxX: NReal;
  nPuntosHistograma: integer;

  CronVarsEjex: TCronVar;

  largoArray: integer;
  cronVarArray: TDAOfCronVar;
  tipoGraficoArray: TDAOfTTipoGrafico;
  ejeArray: TDAOfTTipoEje;
{$IFNDEF SIMRES3SOLOTEXTO}
  colorArray: TDAOfTColor;
  tipoGraficoStr: string;
  tipoGrafico: TTipoGrafico;
{$ENDIF}
  tipoValoresAComparar: string;
  probExcedencia: NReal;
  ejex: TTipoVariableDelEje;
  _obsoleta_: boolean;
  probExcedencia_Sup: NReal;

  s1, s2, s3, s4: string;
  flg_quit_al_final: boolean;
  flg_ejecutar: boolean;
begin

  // Valores por defecto para versiones viejas
  titulo_eje2 := '';
  minEjeYAuto_eje2 := True;
  maxEjeYAuto_eje2 := True;
  minEjeY_eje2 := 0.0;
  MaxEjeY_eje2 := 100.0;



  writeln('Interpretando PrinCronVar: ' + linea);

  tipoPrint := LowerCase(readPal(linea));

{$IFNDEF SIMRES3SOLOTEXTO}
  if tipoPrint = LowerCase(TPrintCronVar_matrizDeDatos.tipo) then
  begin
    nomCronVar := readPal(linea);
    nombreHoja := readPal(linea);
    titulo := readPal(linea);
    titulo_eje1 := readPal(linea);
    n := StrToInt(readPal(linea));
    SetLength(titulosCols, n);
    for i := 0 to n - 1 do
      titulosCols[i] := readPal(linea);
    digitos_eje1 := StrToInt(readPal(linea));
    decimales_eje1 := StrToInt(readPal(linea));
    Print_promedio := StrToBool(readPal(linea));
    chart_Mat := StrToBool(readPal(linea));
    minEjeYAuto_eje1 := StrToBool(readPal(linea));
    maxEjeYAuto_eje1 := StrToBool(readPal(linea));
    minEjeY_eje1 := StrToFloat(readPal(linea));
    MaxEjeY_eje1 := StrToFloat(readPal(linea));

    printCronVar := TPrintCronVar_matrizDeDatos.Create(getCronVarByName(nomCronVar),
      nombreHoja, titulo, titulo_eje1, titulosCols, digitos_eje1,
      decimales_eje1, Print_promedio, chart_Mat, minEjeYAuto_eje1,
      maxEjeYAuto_eje1, minEjeY_eje1, MaxEjeY_eje1);
  end
  else if tipoPrint = LowerCase(TPrintCronVar_Histograma.tipo) then
  begin
    nomCronVar := readPal(linea);
    nombreHoja := readPal(linea);
    titulo := readPal(linea);
    titulo_eje1 := readPal(linea);
    digitos_eje1 := StrToInt(readPal(linea));
    decimales_eje1 := StrToInt(readPal(linea));

    Print_Todas := StrToBool(readPal(linea));
    Print_promedio := StrToBool(readPal(linea));

    if versionArchivo > 3 then
    begin
      Pre_Ordenar := StrToBool(readPal(linea));
      TipoImpresion_PE := StrToBool(readPal(linea));
    end
    else
    begin
      Pre_Ordenar := True;
      TipoImpresion_PE := True;
    end;
    n := StrToInt(readPal(linea));
    SetLength(Print_probAisladas, n);
    for i := 0 to n - 1 do
      Print_probAisladas[i] := StrToFloat(readPal(linea));
    chart_Mat := StrToBool(readPal(linea));
    minEjeYAuto_eje1 := StrToBool(readPal(linea));
    maxEjeYAuto_eje1 := StrToBool(readPal(linea));
    minEjeY_eje1 := StrToFloat(readPal(linea));
    MaxEjeY_eje1 := StrToFloat(readPal(linea));

    printCronVar := TPrintCronVar_histograma.Create(getCronVarByName(nomCronVar),
      nombreHoja, titulo, titulo_eje1, digitos_eje1, decimales_eje1,
      Print_Todas, Print_promedio, Pre_ordenar, TipoImpresion_PE,
      Print_probAisladas, chart_Mat, minEjeYAuto_eje1, maxEjeYAuto_eje1,
      minEjeY_eje1, MaxEjeY_eje1);
  end
  else
  {$ENDIF}
  if tipoPrint = LowerCase(TPrintCronVar_Histograma_text.tipo) then
  begin
    nomCronVar := readPal(linea);
    nombreHoja := readPal(linea);
    titulo := readPal(linea);
    titulo_eje1 := readPal(linea);
    digitos_eje1 := StrToInt(readPal(linea));
    decimales_eje1 := StrToInt(readPal(linea));
    Print_Todas := StrToBool(readPal(linea));
    Print_promedio := StrToBool(readPal(linea));
    if versionArchivo > 3 then
    begin
      Pre_Ordenar := StrToBool(readPal(linea));
      TipoImpresion_PE := StrToBool(readPal(linea));
    end
    else
    begin
      Pre_Ordenar := True;
      TipoImpresion_PE := True;
    end;

    n := StrToInt(readPal(linea));
    SetLength(Print_probAisladas, n);
    for i := 0 to n - 1 do
      Print_probAisladas[i] := StrToFloat(readPal(linea));

    printCronVar := TPrintCronVar_histograma_text.Create(getCronVarByName(nomCronVar),
      nombreHoja, titulo, titulo_eje1, digitos_eje1, decimales_eje1,
      Print_Todas, Print_promedio, Pre_Ordenar, TipoImpresion_PE, Print_probAisladas);
  end
{$IFNDEF SIMRES3SOLOTEXTO}
  else if tipoPrint = LowerCase(TPrintCronVar_HistogramaGlobal.tipo) then
  begin
    nomCronVar := readPal(linea);
    nombreHoja := readPal(linea);
    titulo := readPal(linea);
    titulo_eje1 := readPal(linea);
    digitos_eje1 := StrToInt(readPal(linea));
    decimales_eje1 := StrToInt(readPal(linea));
    minX := StrToFloat(readPal(linea));
    maxX := StrToFloat(readPal(linea));
    nPuntosHistograma := StrToInt(readPal(linea));
{    chart_Mat:= StrToBool(readPal(linea));
    minEjeYAuto:= StrToBool(readPal(linea));
    maxEjeYAuto:= StrToBool(readPal(linea));
    minEjeY:= StrToFloat(readPal(linea));
    MaxEjeY:= StrToFloat(readPal(linea));}

    printCronVar := TPrintCronVar_HistogramaGlobal.Create(getCronVarByName(nomCronVar),
      nombreHoja, titulo, titulo_eje1, digitos_eje1, decimales_eje1,
      minX, maxX, nPuntosHistograma
                                                         {chart_Mat, minEjeYAuto, maxEjeYAuto,
                                                         minEjeY, MaxEjeY});
  end
  else if tipoPrint = LowerCase(TPrintCronVar_compararValoresMultiplesCronVars.tipo) then
  begin
    if versionArchivo < 1 then
    begin
      largoArray := StrToInt(readPal(linea));
      SetLength(cronVarArray, largoArray);
      for i := 0 to largoArray - 1 do
      begin
        nomCronVar := readPal(linea);
        cronVarArray[i] := getCronVarByName(nomCronVar);
      end;
      nombreHoja := readPal(linea);
      titulo := readPal(linea);
      titulo_eje1 := readPal(linea);
      digitos_eje1 := StrToInt(readPal(linea));
      decimales_eje1 := StrToInt(readPal(linea));

      tipoValoresAComparar := readPal(linea);

      probExcedencia := StrToFloat(readPal(linea));
      chart_Mat := StrToBool(readPal(linea));

      tipoGraficoStr := readPal(linea);
      if tipoGraficoStr = 'Líneas' then
        tipoGraficoStr := 'Dispersión';

      tipoGrafico := StringToTTipoGrafico(tipoGraficoStr);
      minEjeYAuto_eje1 := StrToBool(readPal(linea));
      maxEjeYAuto_eje1 := StrToBool(readPal(linea));
      minEjeY_eje1 := StrToFloat(readPal(linea));
      MaxEjeY_eje1 := StrToFloat(readPal(linea));

      SetLength(tipoGraficoArray, length(cronVarArray));
      SetLength(ejeArray, length(cronVarArray));
      SetLength(colorArray, length(cronVarArray));
      for i := 0 to high(tipoGraficoArray) do
      begin
        tipoGraficoArray[i] := tipoGrafico;
        ejeArray[i] := Primario;
        colorArray[i] := clDefault;
      end;
    end
    else if versionArchivo < 2 then
    begin
      largoArray := StrToInt(readPal(linea));
      SetLength(cronVarArray, largoArray);
      SetLength(tipoGraficoArray, length(cronVarArray));
      SetLength(ejeArray, length(cronVarArray));
      SetLength(colorArray, length(cronVarArray));

      for i := 0 to largoArray - 1 do
      begin
        nomCronVar := readPal(linea);
        cronVarArray[i] := getCronVarByName(nomCronVar);
        tipoGraficoStr := readPal(linea);
        if tipoGraficoStr = 'Líneas' then
          tipoGraficoStr := 'Dispersión';
        tipoGraficoArray[i] := StringToTTipoGrafico(tipoGraficoStr);
        ejeArray[i] := StringToTTipoEje(readPal(linea));
        colorArray[i] := StringToColor(readPal(linea));
      end;

      nombreHoja := readPal(linea);
      titulo := readPal(linea);
      titulo_eje1 := readPal(linea);
      digitos_eje1 := StrToInt(readPal(linea));
      decimales_eje1 := StrToInt(readPal(linea));
      tipoValoresAComparar := readPal(linea);
      probExcedencia := StrToFloat(readPal(linea));
      chart_Mat := StrToBool(readPal(linea));
      minEjeYAuto_eje1 := StrToBool(readPal(linea));
      maxEjeYAuto_eje1 := StrToBool(readPal(linea));
      minEjeY_eje1 := StrToFloat(readPal(linea));
      MaxEjeY_eje1 := StrToFloat(readPal(linea));
    end
    else
    begin
      largoArray := StrToInt(readPal(linea));
      SetLength(cronVarArray, largoArray);
      SetLength(tipoGraficoArray, length(cronVarArray));
      SetLength(ejeArray, length(cronVarArray));
      SetLength(colorArray, length(cronVarArray));

      for i := 0 to largoArray - 1 do
      begin
        nomCronVar := readPal(linea);
        cronVarArray[i] := getCronVarByName(nomCronVar);
        tipoGraficoStr := readPal(linea);
        tipoGraficoArray[i] := StringToTTipoGrafico(tipoGraficoStr);
        ejeArray[i] := StringToTTipoEje(readPal(linea));
        colorArray[i] := StringToColor(readPal(linea));
      end;

      nombreHoja := readPal(linea);
      titulo := readPal(linea);
      titulo_eje1 := readPal(linea);
      digitos_eje1 := StrToInt(readPal(linea));
      decimales_eje1 := StrToInt(readPal(linea));
      tipoValoresAComparar := readPal(linea);
      probExcedencia := StrToFloat(readPal(linea));

      if versionArchivo > 15 then
        titulo_ejeX := readPal(linea)
      else
        titulo_ejeX := '';

      if versionArchivo > 14 then
      begin
        ejex := StringToTEje(readPal(linea));
        CronVarsEjex := getCronVarByName(readPal(linea));
        if versionArchivo < 17 then
          _obsoleta_ := StrToBool(readPal(linea));
      end
      else if versionArchivo > 13 then
      begin
        ejex := StringToTEje(readPal(linea));
        CronVarsEjex := getCronVarByName(readPal(linea));
      end
      else
      begin
        ejex := tiempo;
        CronVarsEjex := cronVarArray[0];
      end;

      if versionArchivo > 3 then
      begin
        Pre_Ordenar := StrToBool(readPal(linea));
        probExcedencia_Sup := StrToFloat(readPal(linea));
      end;

      chart_Mat := StrToBool(readPal(linea));
      minEjeYAuto_eje1 := StrToBool(readPal(linea));
      maxEjeYAuto_eje1 := StrToBool(readPal(linea));
      minEjeY_eje1 := StrToFloat(readPal(linea));
      maxEjeY_eje1 := StrToFloat(readPal(linea));
    end;



    if not (versionArchivo > 3) then
    begin
      Pre_Ordenar := True;
      probExcedencia_Sup := 1.0;
    end;

    if versionArchivo > 15 then
    begin
      titulo_eje2 := readPal(linea);
      digitos_eje2 := StrToInt(readPal(linea));
      decimales_eje2 := StrToInt(readPal(linea));
      minEjeYAuto_eje2 := StrToBool(readPal(linea));
      maxEjeYAuto_eje2 := StrToBool(readPal(linea));
      minEjeY_eje2 := StrToFloat(readPal(linea));
      maxEjeY_eje2 := StrToFloat(readPal(linea));
    end
    else
    begin
      titulo_eje2 := '';
      digitos_eje2 := 12;
      decimales_eje2 := 2;
      minEjeYAuto_eje2 := True;
      maxEjeYAuto_eje2 := True;
      minEjeY_eje2 := 0.0;
      maxEjeY_eje2 := 100.0;
    end;


    // me parece que es acá que va, sino con las versiones 1 y 2 de archivo no se
    // creaba el printCronVar
    printCronVar :=
      TPrintCronVar_compararValoresMultiplesCronVars.Create(
      cronVarArray, nombreHoja, titulo, titulo_eje1, digitos_eje1,
      decimales_eje1, StringToTTipoValoresAComparar(tipoValoresAComparar),
      probExcedencia, titulo_ejeX, ejex, CronVarsEjex,
      pre_Ordenar, probExcedencia_Sup, chart_Mat, tipoGraficoArray,
      ejeArray, colorArray, minEjeYAuto_eje1, maxEjeYAuto_eje1,
      minEjeY_eje1, maxEjeY_eje1, titulo_eje2, digitos_eje2,
      decimales_eje2, minEjeYAuto_eje2, maxEjeYAuto_eje2, minEjeY_eje2, MaxEjeY_eje2);
  end
  {$ENDIF}

  else if (tipoPrint = 'r') or (tipoPrint = LowerCase(TPrintCronVar_R.tipo)) then
  begin
    largoArray := StrToInt(readPal(linea));
    SetLength(cronVarArray, largoArray);
    for i := 0 to largoArray - 1 do
    begin
      nomCronVar := readPal(linea);
      cronVarArray[i] := getCronVarByName(nomCronVar);
    end;

    s1 := readPal(linea);
    s2 := readPal(linea);
    s3 := HTTpDecode(readPal(linea));

    s4 := readPal(linea);

    if versionArchivo >= 13 then
    begin
      flg_ejecutar := StrToBool(readPal(linea));
      flg_quit_al_final := StrToBool(readPal(linea));
    end
    else
    begin
      flg_ejecutar := True;
      flg_quit_al_final := True;
    end;

    printCronVar := TPrintCronVar_R.Create(cronVarArray, s1, s2, s3,
      s4, flg_ejecutar, flg_quit_al_final);
  end
  else
    raise Exception.Create('Tipo de PrintCronVar desconocido "' +
      tipoPrint + '" leyendo la línea ' + IntToStr(kLineaLectura));
  Result := printCronVar;
end;

function TLectorSimRes3Defs.getOrigen(str: string): TDAofString;
var
  aux, lineas: string;
  f: textfile;
  k: integer;
  lst: TStringList;
  res: TDAofString;
  Rslt: TSearchRec;

begin
  if ExtractFileExt(str) = '.txt' then
  begin
    if FileExists(str) then
    begin
      lst := TStringList.Create;
      AssignFile(f, str);
      Reset(f);
      while not EOF(f) do
      begin
        readln(f, lineas);
        lst.Add(lineas);
      end;
      SetLength(res, lst.Count);
      for k := 0 to lst.Count - 1 do
        res[k] := lst[k];
      lst.Free;
      Close(f);
      Result := res;
    end
    else
      raise Exception.Create('TLectorSimRes3Defs.getOrigen: Error, el archivo ' +
        str + ' no existe');
  end
  else
  if ExtractFileExt(str) = '.xlt' then
  begin
    aux := copy(str, Length(str) - 6, 3);
   {$IFDEF FEDE_DEBUG}
    writeln(aux);
   {$ENDIF}

    if aux = '*x*' then
    begin
      lst := TStringList.Create;
      if FindFirst(str, faArchive, Rslt) = 0 then
      begin
        repeat
          Lst.Add(Rslt.Name);
        until FindNext(Rslt) <> 0;
        FindClose(Rslt);
      end;
      if lst.Count <> 0 then
      begin
        SetLength(res, lst.Count);
        for k := 0 to lst.Count - 1 do
          res[k] := ExtractFilePath(str) + lst[k];
        lst.Free;
        Result := res;
      end
      else
        raise Exception.Create(
          'TLectorSimRes3Defs.getOrigen: Error, no se encontraron archivos');
    end
    else
    begin
      SetLength(res, 1);
      res[0] := str;
      Result := res;
    end;
  end
  else
    raise Exception.Create('TLectorSimRes3Defs.getOrigen: Error, el archivo ' +
      str + ' no es un origen valido');
end;

constructor TLectorSimRes3Defs.Create;
begin
  inherited Create;
  simRes := nil;
  kPasoDesde := -1;
  kPasoHasta := -1;
  archisSimRes := TStringList.Create;
  lstArchis := TStringList.Create;
  lstSimRes_ := TList.Create;
  lstIdxs := TList.Create;
  lstCronVars := TList.Create;
  lstCronOpers := TList.Create;
  lstPostOpers := TList.Create;
  lstPrintCronVars := TList.Create;
  comentarioDeObjeto := TStringList.Create;
  comentariosObjetos := TListaComentarioObjeto.Create;
  lineasArchi := TStringList.Create;
  tagsObjetos := TListaTagObjeto.Create;
  versionArchivo := VERSION_ARCHI_SIMRES;
  self.fechaDesde_f := TFecha.Create_Dt(0);
  self.fechaHasta_f := TFecha.Create_dt(0);
  self.kCron_f := -1; // significa SIN FILTRADO
  version_SimSEE := '';
  fechaSimulacion_f := TFecha.Create_AnioMesDia(1900, 1, 1);
end;

procedure TLectorSimRes3Defs.LeerDefiniciones(archi: string;
  prepararseParaCorrer: boolean; flg_LeerHastaIndices: boolean);
var
  ver: string;
  ipos: integer;

begin
  if not FileExists(archi) then
    raise Exception.Create(
      'TLectorSimRes3Defs.LeerDefiniciones: Error, no existe el archivo simres '
      + archi);

  try
    uauxiliares.setSeparadoresGlobales;
    kLineaFechaIni := -1;
    kLineaFechaFin := -1;
    kLineasArchisSimRes := nil;
    comentarioDeObjeto.Clear;


    lineasArchi.LoadFromFile(archi);
    ver := lineasArchi[0];

    formatearArchivoLeido;
    ver := lineasArchi[0];

    ipos := pos('VERSION=', ver);
    if ipos > 0 then
    begin
      ver := copy(ver, ipos + length('VERSION='), length(ver) -
        (ipos + length('VERSION=')) + 1);
      versionArchivo := StrToInt(ver);
      kLineaLectura := 1;
    end
    else
    begin
      versionArchivo := 0;
      kLineaLectura := 0;
    end;

    LeerSimRes(prepararseParaCorrer);
    LeerFechas(prepararseParaCorrer);
    if versionArchivo >= 5 then
    //      LeerFiltroCronica(prepararseParaCorrer)
    else
    begin
      self.filtrar_Cronica := False;
      self.kCron_f := -1;
    end;

    if self.filtrar_Cronica then
      uSimResGlobs.Set_nCronicasDelEstudio(1);

    writeln('Leyendo índices. .. ');
    LeerIndices(prepararseParaCorrer);

    if flg_LeerHastaIndices then
      exit;
    writeln('Leyendo CronVars. .. ');
    LeerCron_Vars;
    writeln('Leyendo CronOpers. .. ');
    LeerCron_Opers(prepararseParaCorrer);
    writeln('Leyendo PostOpers. .. ');
    LeerPost_Opers(prepararseParaCorrer);
    writeln('Leyendo Prints. .. ');
    LeerPrintCronVars;

    versionArchivo := VERSION_ARCHI_SIMRES;
  finally
    uauxiliares.setSeparadoresLocales
  end;

end;

procedure TLectorSimRes3Defs.OPEN_WRITE(var f: textfile);
begin
  Rewrite(f);
  kLineaLectura := 1;
  Writeln(f, 'VERSION=', VERSION_ARCHI_SIMRES);
  uauxiliares.setSeparadoresGlobales;
end;

procedure TLectorSimRes3Defs.CLOSE_WRITE(var f: textfile);
begin
  uauxiliares.setSeparadoresLocales;
  CloseFile(f);
end;


procedure TLectorSimRes3Defs.EscribirDefiniciones(archi: string;
  guardarBackupSiExiste: boolean; maxNBackups: integer);
var
  f: TextFile;
begin
  if guardarBackupSiExiste and FileExists(archi) then
    uconstantesSimSEE.backupearArchivoAntesDeSalvar(archi, maxNBackups);
  AssignFile(f, archi);
  try
    OPEN_WRITE(f);
    EscribirSimRes(f);
    EscribirFechas(f);
    EscribirIndices(f);
    EscribirCron_Vars(f);
    EscribirCron_Opers(f);
    EscribirPost_Opers(f);
    EscribirPrintCronVars(f);
  finally
    CLOSE_WRITE(f);
  end;
end;

function TLectorSimRes3Defs.existeReferenciaAlIndice(indice: TVarIdxs): boolean;
var
  i: integer;
  res: boolean;
begin
  res := False;
  for i := 0 to lstCronOpers.Count - 1 do
    if TCronOper(lstCronOpers[i]).referenciaIndice(indice) then
    begin
      res := True;
      break;
    end;
  Result := res;
end;

function TLectorSimRes3Defs.existeReferenciaAlIndice(indice: TVarIdxs;
  var referentes: TDAOfCronOper): boolean;
var
  i, iReferentes: integer;
begin
  SetLength(referentes, lstCronOpers.Count);
  iReferentes := 0;

  for i := 0 to lstCronOpers.Count - 1 do
    if TCronOper(lstCronOpers[i]).referenciaIndice(indice) then
    begin
      referentes[iReferentes] := TCronOper(lstCronOpers[i]);
      iReferentes := iReferentes + 1;
    end;

  if iReferentes > 0 then
    referentes := Copy(referentes, 0, iReferentes);
  Result := iReferentes > 0;
end;

function TLectorSimRes3Defs.existeReferenciaALaCronVar(cronVar: TCronVar): string;
var
  i: integer;
  res: string;
begin
  res := '';
  for i := 0 to lstCronOpers.Count - 1 do
    if TCronOper(lstCronOpers[i]).referenciaCronVar(cronVar) then
    begin
      res := 'La variable crónica es resultado de una operación crónica de tipo ' +
        TCronOper(lstCronOpers[i]).tipo +
        '. Elimíne la operación crónica antes de eliminar la variable.';
      break;
    end;
  if res = '' then
  begin
    for i := 0 to lstPostOpers.Count - 1 do
      if TPostOper(lstPostOpers[i]).referenciaCronVar(cronVar) then
      begin
        res := 'La variable crónica es parámetro o resultado de una post operación de tipo '
          + TPostOper(lstPostOpers[i]).tipo +
          '. Elimíne la post operación antes de eliminar la variable.';
        break;
      end;

    if res = '' then
    begin
      for i := 0 to lstPrintCronVars.Count - 1 do
        if TPrintCronVar(lstPrintCronVars[i]).referenciaCronVar(cronVar) then
        begin
          res := 'La impresión "' + TPrintCronVar(lstPrintCronVars[i]).titulo +
            '" imprime la variable crónica. Elimíne la impresión antes de eliminar la variable.';
          break;
        end;
    end;
  end;
  Result := res;
end;

function TLectorSimRes3Defs.indicesSinReferencia: TDAOfTVarIdxs;
var
  res: TDAOfTVarIdxs;
  i, iRes: integer;
begin
  SetLength(res, lstIdxs.Count);
  iRes := 0;

  for i := 0 to lstIdxs.Count - 1 do
    if not existeReferenciaAlIndice(TVarIdxs(lstIdxs[i])) then
    begin
      res[iRes] := lstIdxs[i];
      iRes := iRes + 1;
    end;

  // Si hay indices sin referencias, los copio
  if iRes <> 0 then
    res := Copy(res, 0, iRes)
  // Si no, devuelvo un array vacio
  else
    SetLength(res, 0);

  Result := res;
end;

function TLectorSimRes3Defs.cronVarsSinReferencia: TDAOfCronVar;
var
  res: TDAOfCronVar;
  i, iRes: integer;
begin
  SetLength(res, lstCronVars.Count);
  iRes := 0;

  for i := 0 to lstCronVars.Count - 1 do
    if existeReferenciaALaCronVar(lstCronVars[i]) = '' then
    begin
      res[iRes] := lstCronVars[i];
      iRes := iRes + 1;
    end;

  // Si hay variables cronicas sin referencia, las copio
  if iRes <> 0 then
    res := copy(res, 0, iRes)
  // Si no, devuelvo un array vacio
  else
    SetLength(res, 0);

  Result := res;
end;

function TLectorSimRes3Defs.esResultadoDeCronOper(cronVar: TCronVar): boolean;
var
  i: integer;
begin
  Result := False;
  for i := 0 to lstCronOpers.Count - 1 do
    if TCronOper(lstCronOpers[i]).referenciaCronVar(cronVar) then
    begin
      Result := True;
      break;
    end;
end;

function TLectorSimRes3Defs.esResultadoDePostOper(cronVar: TCronVar;
  jHasta: integer): boolean;
var
  i: integer;
  max_i: integer;
begin
  Result := False;
  max_i := min(jHasta - 1, lstPostOpers.Count - 1);
  for i := 0 to max_i do
    if TPostOper(lstPostOpers[i]).res = cronVar then
    begin
      Result := True;
      break;
    end;
end;

function TLectorSimRes3Defs.hayErrores(errores: TStrings): boolean;
var
  i: integer;
  printCronVar: TPrintCronVar;
  cronVar: TCronVar;
  cronVars: TDAOfCronVar;
  postOper: TPostOper;
  j: integer;
begin
  errores.Clear;
  //Chequeo que no haya post opers que tengan entre sus parámetros cron vars que
  //no sean resultado de alguna cron oper O DE OTRA PostOper anterior
  for i := 0 to lstPostOpers.Count - 1 do
  begin
    postOper := TPostOper(lstPostOpers[i]);
    cronVars := postOper.parametrosCronVar;

    for j := 0 to High(cronVars) do
    begin
      cronVar := cronVars[j];
      if not esResultadoDeCronOper(cronVar) and not
        esResultadoDePostOper(cronVar, i) then
        errores.Add('La variable crónica "' + cronVar.nombre +
          '" no es asignada por ninguna operación crónica pero es parámetro de una post operación de tipo '
          + postOper.tipo + '.');
    end;
  end;

  //Chequeo que no haya prints de CronVars que no sean resultado de alguna
  //CronOper o PostOper
  for i := 0 to lstPrintCronVars.Count - 1 do
  begin
    printCronVar := TPrintCronVar(lstPrintCronVars[i]);
    cronVars := printCronVar.cronVarsAImprimir;

    for j := 0 to High(cronVars) do
    begin
      cronVar := cronVars[j];
      if not esResultadoDeCronOper(cronVar) and not
        esResultadoDePostOper(cronVar, 9999) then
        errores.Add(AnsiToUtf8('La variable crónica "' + cronVar.nombre +
          '" no es asignada por ninguna operación crónica ni ninguna post operación pero es parámetro de la impresión "'
          + printCronVar.titulo + '".'));
    end;
  end;
  Result := errores.Count <> 0;
end;

procedure TLectorSimRes3Defs.agregarIndice(indice: TVarIdxs);
begin
  lstIdxs.Add(indice);
end;

procedure TLectorSimRes3Defs.agregarCronVar(cronVar: TCronVar);
begin
  lstCronVars.Add(cronVar);
end;

procedure TLectorSimRes3Defs.agregarCronOper(cronOper: TCronOper);
begin
  lstCronOpers.Add(cronOper);
end;

procedure TLectorSimRes3Defs.agregarPostOper(postOper: TPostOper);
begin
  lstPostOpers.Add(postOper);
end;

procedure TLectorSimRes3Defs.agregarPrintCronVar(printCronVar: TPrintCronVar);
begin
  lstPrintCronVars.Add(printCronVar);
end;

function TLectorSimRes3Defs.clonarIndice(indice: TVarIdxs): TVarIdxs;
begin
  Result := leerIndice(indice.serialize);
end;

function TLectorSimRes3Defs.clonarCronVar(cronVar: TCronVar): TCronVar;
begin
  Result := leerCronVar(cronVar.serialize);
end;

function TLectorSimRes3Defs.clonarCronOper(cronOper: TCronOper): TCronOper;
begin
  uauxiliares.setSeparadoresGlobales;
  Result := leerCronOper(cronOper.serialize, False);
  uAuxiliares.setSeparadoresLocales;
end;

function TLectorSimRes3Defs.clonarPostOper(postOper: TPostOper): TPostOper;
begin
  uauxiliares.setSeparadoresGlobales;
  Result := leerPostOper(postOper.serialize, False);
  uAuxiliares.setSeparadoresLocales;
end;

function TLectorSimRes3Defs.clonarPrintCronVar(printCronVar:
  TPrintCronVar): TPrintCronVar;
begin
  uauxiliares.setSeparadoresGlobales;
  Result := leerPrintCronVar(printCronVar.serialize);
  uAuxiliares.setSeparadoresLocales;
end;

procedure TLectorSimRes3Defs.eliminarIndice(iIndice: integer);
var
  tag: string;
begin
  tag := tagsObjetos.eliminarTagObjeto(lstIdxs[iIndice]);
  if tag <> '' then
    lineasArchi.Delete(lineasArchi.IndexOf(tag));

  TVarIdxs(lstIdxs[iIndice]).Free;
  lstIdxs.Delete(iIndice);
end;

procedure TLectorSimRes3Defs.eliminarIndice(var indice: TVarIdxs);
var
  tag: string;
begin
  tag := tagsObjetos.eliminarTagObjeto(indice);
  if tag <> '' then
    lineasArchi.Delete(lineasArchi.IndexOf(tag));

  lstIdxs.Remove(indice);
  indice.Free;
end;

procedure TLectorSimRes3Defs.eliminarCronVar(iCronVar: integer);
var
  tag: string;
begin
  tag := tagsObjetos.eliminarTagObjeto(lstCronVars[iCronVar]);
  if tag <> '' then
    lineasArchi.Delete(lineasArchi.IndexOf(tag));

  TCronVar(lstCronVars[iCronVar]).Free;
  lstCronVars.Delete(iCronVar);
end;

procedure TLectorSimRes3Defs.eliminarCronVar(var cronVar: TCronVar);
var
  tag: string;
begin
  tag := tagsObjetos.eliminarTagObjeto(cronVar);
  if tag <> '' then
    lineasArchi.Delete(lineasArchi.IndexOf(tag));

  lstCronVars.Remove(cronVar);
  cronVar.Free;
end;

procedure TLectorSimRes3Defs.eliminarCronOper(iCronOper: integer);
var
  tag: string;
begin
  tag := tagsObjetos.eliminarTagObjeto(lstCronOpers[iCronOper]);
  if tag <> '' then
    lineasArchi.Delete(lineasArchi.IndexOf(tag));

  TCronOper(lstCronOpers[iCronOper]).Free;
  lstCronOpers.Delete(iCronOper);
end;

procedure TLectorSimRes3Defs.eliminarPostOper(iPostOper: integer);
var
  tag: string;
begin
  tag := tagsObjetos.eliminarTagObjeto(lstPostOpers[iPostOper]);
  if tag <> '' then
    lineasArchi.Delete(lineasArchi.IndexOf(tag));

  TPostOper(lstPostOpers[iPostOper]).Free;
  lstPostOpers.Delete(iPostOper);
end;

procedure TLectorSimRes3Defs.eliminarPrintCronVar(iPrintCronVar: integer);
var
  tag: string;
begin
  tag := tagsObjetos.eliminarTagObjeto(lstPrintCronVars[iPrintCronVar]);
  if tag <> '' then
    lineasArchi.Delete(lineasArchi.IndexOf(tag));

  TPrintCronVar(lstPrintCronVars[iPrintCronVar]).Free;
  lstPrintCronVars.Delete(iPrintCronVar);
end;

procedure TLectorSimRes3Defs.swapObjetosSimRes(item1, item2: Pointer);
begin
  tagsObjetos.swapObjetos(item1, item2);
end;

procedure TLectorSimRes3Defs.swapIndices(indice1, indice2: TVarIdxs);
begin
  tagsObjetos.swapObjetos(indice1, indice2);
end;

procedure TLectorSimRes3Defs.swapCronVars(cronVar1, cronVar2: TCronVar);
begin
  tagsObjetos.swapObjetos(cronVar1, cronVar2);
end;

procedure TLectorSimRes3Defs.swapCronOpers(cronOper1, cronOper2: TCronOper);
begin
  tagsObjetos.swapObjetos(cronOper1, cronOper2);
end;

procedure TLectorSimRes3Defs.swapPostOpers(postOper1, postOper2: TPostOper);
begin
  tagsObjetos.swapObjetos(postOper1, postOper2);
end;

procedure TLectorSimRes3Defs.swapPrintCronVars(printCronVar1,
  printCronVar2: TPrintCronVar);
begin
  tagsObjetos.swapObjetos(printCronVar1, printCronVar2);
end;

procedure TLectorSimRes3Defs.altaEdicionPostOper2CronVarsUnReal(
  tipoPostOper: TClaseDePostOper; var postOper: TPostOper; cv1, cv2: TCronVar;
  aReal: NReal);
begin
  if tipoPostOper = TPostOper_minEntreCronVarYReal then
  begin
    if postOper = nil then
      postOper := TPostOper_minEntreCronVarYReal.Create(cv1, cv2, aReal)
    else
    begin
      TPostOper_minEntreCronVarYReal(postOper).res := cv1;
      TPostOper_minEntreCronVarYReal(postOper).param1 := cv2;
      TPostOper_minEntreCronVarYReal(postOper).aReal := aReal;
    end;
  end
  else if tipoPostOper = TPostOper_maxEntreCronVarYReal then
  begin
    if postOper = nil then
      postOper := TPostOper_maxEntreCronVarYReal.Create(cv1, cv2, aReal)
    else
    begin
      TPostOper_maxEntreCronVarYReal(postOper).res := cv1;
      TPostOper_maxEntreCronVarYReal(postOper).param1 := cv2;
      TPostOper_maxEntreCronVarYReal(postOper).aReal := aReal;
    end;
  end
  else if tipoPostOper = TPostOper_cronVarMasReal then
  begin
    if postOper = nil then
      postOper := TPostOper_cronVarMasReal.Create(cv1, cv2, aReal)
    else
    begin
      TPostOper_cronVarMasReal(postOper).res := cv1;
      TPostOper_cronVarMasReal(postOper).param1 := cv2;
      TPostOper_cronVarMasReal(postOper).aReal := aReal;
    end;
  end
  else if tipoPostOper = TPostOper_cronVarPorReal then
  begin
    if postOper = nil then
      postOper := TPostOper_cronVarPorReal.Create(cv1, cv2, aReal)
    else
    begin
      TPostOper_cronVarMasReal(postOper).res := cv1;
      TPostOper_cronVarMasReal(postOper).param1 := cv2;
      TPostOper_cronVarMasReal(postOper).aReal := aReal;
    end;
  end
  else if tipoPostOper = TPostOper_aplicarActualizador then
  begin
    if postOper = nil then
      postOper := TPostOper_aplicarActualizador.Create(cv1, cv2, aReal)
    else
    begin
      TPostOper_aplicarActualizador(postOper).res := cv1;
      TPostOper_aplicarActualizador(postOper).param1 := cv2;
      TPostOper_aplicarActualizador(postOper).aReal := aReal;
    end;
  end
  else
    raise Exception.Create(
      'TLectorSimRes3Defs.altaEdicionPostOper2CronVarsUnReal: clase no registrada ' +
      tipoPostOper.ClassName);
end;

procedure TLectorSimRes3Defs.paramsPostOper2CronVarsUnReal(postOper: TPostOper;
  var cv1, cv2: TCronVar; var aReal: NReal);
begin
  if postOper.ClassType = TPostOper_minEntreCronVarYReal then
  begin
    cv1 := TPostOper_minEntreCronVarYReal(postOper).res;
    cv2 := TPostOper_minEntreCronVarYReal(postOper).param1;
    aReal := TPostOper_minEntreCronVarYReal(postOper).aReal;
  end
  else if postOper.ClassType = TPostOper_maxEntreCronVarYReal then
  begin
    cv1 := TPostOper_maxEntreCronVarYReal(postOper).res;
    cv2 := TPostOper_maxEntreCronVarYReal(postOper).param1;
    aReal := TPostOper_maxEntreCronVarYReal(postOper).aReal;
  end
  else if postOper.ClassType = TPostOper_cronVarMasReal then
  begin
    cv1 := TPostOper_cronVarMasReal(postOper).res;
    cv2 := TPostOper_cronVarMasReal(postOper).param1;
    aReal := TPostOper_cronVarMasReal(postOper).aReal;
  end
  else if postOper.ClassType = TPostOper_cronVarPorReal then
  begin
    cv1 := TPostOper_cronVarPorReal(postOper).res;
    cv2 := TPostOper_cronVarPorReal(postOper).param1;
    aReal := TPostOper_cronVarPorReal(postOper).aReal;
  end
  else if postOper.ClassType = TPostOper_aplicarActualizador then
  begin
    cv1 := TPostOper_aplicarActualizador(postOper).res;
    cv2 := TPostOper_aplicarActualizador(postOper).param1;
    aReal := TPostOper_aplicarActualizador(postOper).aReal;
  end
  else
    raise Exception.Create(
      'TLectorSimRes3Defs.paramsPostOper2CronVarsUnReal: clase no registrada ' +
      postOper.ClassName);
end;

procedure TLectorSimRes3Defs.altaEdicionPostOper3CronVars(tipoPostOper: TClaseDePostOper;
  var postOper: TPostOper; cv1, cv2, cv3: TCronVar);
begin
  if tipoPostOper = TPostOper_restaCronVars then
  begin
    if postOper = nil then
      postOper := TPostOper_restaCronVars.Create(cv1, cv2, cv3)
    else
    begin
      TPostOper_restaCronVars(postOper).res := cv1;
      TPostOper_restaCronVars(postOper).param1 := cv2;
      TPostOper_restaCronVars(postOper).param2 := cv3;
    end;
  end
  else if tipoPostOper = TPostOper_multiplicacionCronVars then
  begin
    if postOper = nil then
      postOper := TPostOper_multiplicacionCronVars.Create(cv1, cv2, cv3)
    else
    begin
      TPostOper_multiplicacionCronVars(postOper).res := cv1;
      TPostOper_multiplicacionCronVars(postOper).param1 := cv2;
      TPostOper_multiplicacionCronVars(postOper).param2 := cv3;
    end;
  end
  else if tipoPostOper = TPostOper_DivisionCronVars then
  begin
    if postOper = nil then
      postOper := TPostOper_DivisionCronVars.Create(cv1, cv2, cv3)
    else
    begin
      TPostOper_DivisionCronVars(postOper).res := cv1;
      TPostOper_DivisionCronVars(postOper).param1 := cv2;
      TPostOper_DivisionCronVars(postOper).param2 := cv3;
    end;
  end
  else
    raise Exception.Create(
      'TLectorSimRes3Defs.altaEdicionPostOper3CronVars: clase no registrada ' +
      tipoPostOper.ClassName);
end;

procedure TLectorSimRes3Defs.paramsPostOper3CronVars(postOper: TPostOper;
  var cv1, cv2, cv3: TCronVar);
begin
  if postOper.ClassType = TPostOper_RestaCronVars then
  begin
    cv1 := TPostOper_RestaCronVars(postOper).res;
    cv2 := TPostOper_RestaCronVars(postOper).param1;
    cv3 := TPostOper_RestaCronVars(postOper).param2;
  end
  else if postOper.ClassType = TPostOper_multiplicacionCronVars then
  begin
    cv1 := TPostOper_multiplicacionCronVars(postOper).res;
    cv2 := TPostOper_multiplicacionCronVars(postOper).param1;
    cv3 := TPostOper_multiplicacionCronVars(postOper).param2;
  end
  else if postOper.ClassType = TPostOper_DivisionCronVars then
  begin
    cv1 := TPostOper_DivisionCronVars(postOper).res;
    cv2 := TPostOper_DivisionCronVars(postOper).param1;
    cv3 := TPostOper_DivisionCronVars(postOper).param2;
  end
  else
    raise Exception.Create(
      'TLectorSimRes3Defs.paramsPostOper3CronVars: clase no registrada ' +
      postOper.ClassName);
end;

function TLectorSimRes3Defs.nombreRepetidoCronVar(cronVar: TCronVar;
  nombre: string): boolean;
var
  i: integer;
  res: boolean;
begin
  res := False;
  for i := 0 to lstCronVars.Count - 1 do
    if (TCronVar(lstCronVars[i]).nombre = nombre) and
      (lstCronVars[i] <> cronVar) then
    begin
      res := True;
      break;
    end;
  Result := res;
end;

function TLectorSimRes3Defs.nombreRepetidoIndice(indice: TVarIdxs;
  nombre: string): boolean;
var
  i: integer;
  res: boolean;
begin
  res := False;
  for i := 0 to lstIdxs.Count - 1 do
    if (TVarIdxs(lstIdxs[i]).nombreIndice = nombre) and (lstIdxs[i] <> indice) then
    begin
      res := True;
      break;
    end;
  Result := res;
end;

function TLectorSimRes3Defs.nombreHojaPrintCronVarRepetido(printCronVar: TPrintCronVar;
  nombreHoja: string; var otraPrintCronVar: TPrintCronVar): boolean;
var
  i: integer;
  res: boolean;
begin
  otraPrintCronVar := nil;
  res := False;

  // No se puede llamar una hoja con el nombre 'x' porque ya esta usado
  if (nombreHoja = 'x') then
  begin
    otraPrintCronVar := nil;
    Result := True;
  end
  else
  begin
    for i := 0 to lstPrintCronVars.Count - 1 do
      if (TPrintCronVar(lstPrintCronVars[i]).nombreHoja = nombreHoja) and
        (lstPrintCronVars[i] <> printCronVar) then
      begin
        otraPrintCronVar := lstPrintCronVars[i];
        //algo := otraPrintCronVar.titulo;
        res := True;
        break;
      end;
    Result := res;
  end;
end;

procedure TLectorSimRes3Defs.Free;
var
  i: integer;
begin
  self.fechaDesde_f.Free;
  self.fechaHasta_f.Free;


  archisSimRes.Free;

  lstArchis.Free;

  for i := 0 to lstSimRes_.Count - 1 do
    TResultadoSim(lstSimRes_[i]).Free;
  lstSimRes_.Free;

  for i := 0 to lstIdxs.Count - 1 do
    TVarIdxs(lstIdxs[i]).Free;
  lstIdxs.Free;

  for i := 0 to lstCronVars.Count - 1 do
    TCronVar(lstCronVars[i]).Free;
  lstCronVars.Free;

  for i := 0 to lstCronOpers.Count - 1 do
    TCronOper(lstCronOpers[i]).Free;
  lstCronOpers.Free;

  for i := 0 to lstPostOpers.Count - 1 do
    TPostOper(lstPostOpers[i]).Free;
  lstPostOpers.Free;

  for i := 0 to lstPrintCronVars.Count - 1 do
    TPrintCronVar(lstPrintCronVars[i]).Free;
  lstPrintCronVars.Free;
  comentarioDeObjeto.Free;
  comentariosObjetos.Free;

  lineasArchi.Free;
  tagsObjetos.FreeConElementos;
  kLineasArchisSimRes := nil;

  inherited Free;
end;

end.
