// definición de CronVars y CronOpers
unit uHistoVarsOps;


interface

uses
  SysUtils, Math, xmatdefs, uTSimRes, Classes, uAuxiliares, uSimResGlobs;

type
  TClaseDeIndice = class of TVarIdxs;

  TVarIdxs = class
    idxs: TDAofNInt;
    nombreIndice: string;
    nombreParticipe, nombreVar: string;
    numSimRes: string;
    simRes: TResultadoSim;
    constructor Create(nombreIndice, nombreActor, nombreVar, numSimRes: string);
    procedure prepararse(simRes: TResultadoSim);
    procedure Free;
    function serialize: string; virtual;
  end;

  TDAOfTVarIdxs = array of TVarIdxs;

  TClaseDeCronVar = class of TCronVar;

  { TCronVar }

  TCronVar = class
  public
    nombre: string;
    nCronicas, nPasos: integer;
    dtIni: TDateTime;
    DurPaso_horas: NReal;

    v_: TMatOfNReal;

    constructor Create(nombre: string);

    procedure inicializar(nCronicas, nPasos: integer; dtIni: TDateTime;
      durPaso_Horas: NReal);

    function vpe(kPaso: integer; probabildadExcedencia: NReal): NReal;

    procedure LiberarMemoria;
    procedure Free;
    function serialize: string; virtual;

    function GetVal(kPaso, jCronica: integer): NReal;
    procedure SetVal(kPaso, jCronica: integer; aValor: NReal);

    property valores[kPaso: integer; jCronica: integer]: NReal read GetVal write SetVal;
      default;

    // archi es el camino completo al archivo (sin la extensión)
    // Primer columna las fechas y luego las crónicas
    procedure Write_R_csv(archi: string; idstr: string);
  end;

  TDAOfCronVar = array of TCronVar;

  TClaseDeCronOper = class of TCronOper;

  TCronOper = class
  public
    res: TCronVar;
    constructor Create_GRIS; // crea una instancia sin inicializar nada.

    //Resuelve los valores que tengan que ver con los índices o el
    //encabezado de la simulacion
    procedure prepararse; virtual; abstract;
    procedure Evaluar; virtual; abstract;
    //Retorna un string con la descripcion de la operacion y su sintaxis
    class function ayudaCronOper: string; virtual; abstract;
    class function tipo: string; virtual; abstract;

    function referenciaIndice(indice: TVarIdxs): boolean; virtual; abstract;
    function parametrosIndice: string; virtual; abstract;

    // retorna TRUE si la cronVar está entre los parámetros o es resultado.
    function referenciaCronVar(cronVar: TCronVar): boolean; virtual;

    function resultados: string; virtual;
    function parametrosAdicionales: string; virtual;
    function serialize: string; virtual;
  end;

  TDAOfCronOper = array of TCronOper;

  TCronOperUnIndice = class(TCronOper)
  protected
    indices: TDAofNInt;
  public
    param1: TVarIdxs;
    function referenciaIndice(indice: TVarIdxs): boolean; override;
    function parametrosIndice: string; override;
  end;

  TCronOperDosIndices = class(TCronOperUnIndice)
  protected
    indices2: TDAofNInt;
  public
    param2: TVarIdxs;
    function referenciaIndice(indice: TVarIdxs): boolean; override;
    function parametrosIndice: string; override;
  end;

  TCronOperMultiIndice = class(TCronOper)
  protected
    indices: TMatOfNInt;
  public
    params: TDAOfTVarIdxs;
    function referenciaIndice(indice: TVarIdxs): boolean; override;
    function parametrosIndice: string; override;
  end;

  TCronOper_suma = class(TCronOperUnIndice)
  public
    constructor Create(res: TCronVar; param1: TVarIdxs);
    //Resuelve los valores que tengan que ver con los índices o el
    //encabezado de la simulacion
    procedure prepararse; override;
    procedure Evaluar; override;
    class function ayudaCronOper: string; override;
    class function tipo: string; override;
    function serialize: string; override;
  end;

  TCronOper_sumaConSigno = class(TCronOperUnIndice)
  private
    sumaPos, sumaNeg: double;
  public
    resNeg: TCronVar;
    constructor Create(resPos, resNeg: TCronVar; param1: TVarIdxs);
    //Resuelve los valores que tengan que ver con los índices o el
    //encabezado de la simulacion
    procedure prepararse; override;
    procedure Evaluar; override;
    class function ayudaCronOper: string; override;
    class function tipo: string; override;
    function referenciaCronVar(cronVar: TCronVar): boolean; override;
    function resultados: string; override;
    function serialize: string; override;
  end;

  TCronOper_Combinar = class(TCronOperMultiIndice)
  public
    coefs: TDAofNReal;
    constructor Create(res: TCronVar; params: TDAOfTVarIdxs; coefs: TDAofNReal);
    //Resuelve los valores que tengan que ver con los índices o el
    //encabezado de la simulacion
    procedure prepararse; override;
    procedure Evaluar; override;
    procedure Free;
    class function ayudaCronOper: string; override;
    class function tipo: string; override;
    function parametrosAdicionales: string; override;
    function serialize: string; override;
  end;

  TCronOper_promedio = class(TCronOperUnIndice)
  public
    constructor Create(res: TCronVar; param1: TVarIdxs);
    //Resuelve los valores que tengan que ver con los índices o el
    //encabezado de la simulacion
    procedure prepararse; override;
    procedure Evaluar; override;
    class function ayudaCronOper: string; override;
    class function tipo: string; override;
    function serialize: string; override;
  end;

  TCronOper_sumaProductoConDurpos = class(TCronOperUnIndice)
  public
    constructor Create(res: TCronVar; param1: TVarIdxs);
    //Resuelve los valores que tengan que ver con los índices o el
    //encabezado de la simulacion
    procedure prepararse; override;
    procedure Evaluar; override;
    class function ayudaCronOper: string; override;
    class function tipo: string; override;
    function serialize: string; override;
  end;

  TCronOper_sumaProductoConDurposHasta = class(TCronOperUnIndice)
  public
    kposteHasta: integer;

    constructor Create(res: TCronVar; param1: TVarIdxs; kposteHasta: integer);
    //Resuelve los valores que tengan que ver con los índices o el
    //encabezado de la simulacion
    procedure prepararse; override;
    procedure Evaluar; override;
    class function ayudaCronOper: string; override;
    class function tipo: string; override;
    function parametrosAdicionales: string; override;
    function serialize: string; override;
  end;

  TCronOper_promedioPonderadoPorDurpos = class(TCronOperUnIndice)
  public
    constructor Create(res: TCronVar; param1: TVarIdxs);
    //Resuelve los valores que tengan que ver con los índices o el
    //encabezado de la simulacion
    procedure prepararse; override;
    procedure Evaluar; override;
    class function ayudaCronOper: string; override;
    class function tipo: string; override;
    function serialize: string; override;
  end;

  TCronOper_filtrarCronica = class(TCronOperUnIndice)
  public
    kCronica: integer;
    constructor Create(res: TCronVar; param1: TVarIdxs; kCronica: integer);
    //Resuelve los valores que tengan que ver con los índices o el
    //encabezado de la simulacion
    procedure prepararse; override;
    procedure Evaluar; override;
    class function ayudaCronOper: string; override;
    class function tipo: string; override;
    function parametrosAdicionales: string; override;
    function serialize: string; override;
  end;

  // si no interesa el recorte poner nil
  TCronOper_sumaProductoConDurposTopeado = class(TCronOperUnIndice)
  private
    recorte: double;
  public
    resRecorte: TCronVar;
    TopeDe1: NReal;

    constructor Create(resSP, resRecorte: TCronVar; param1: TVarIdxs;
      TopeDe1: NReal);
    //Resuelve los valores que tengan que ver con los índices o el
    //encabezado de la simulacion
    procedure prepararse; override;
    procedure Evaluar; override;
    class function ayudaCronOper: string; override;
    class function tipo: string; override;
    function referenciaCronVar(cronVar: TCronVar): boolean; override;
    function resultados: string; override;
    function parametrosAdicionales: string; override;
    function serialize: string; override;

  end;

  // si no interesa el recorte poner nil

  { TCronOper_sumaDobleProductoConDurposTopeado }

  TCronOper_sumaDobleProductoConDurposTopeado = class(TCronOperDosIndices)
  private
    recorte: double;
  public
    resRecorte: TCronVar;
    TopeDe2: NReal;
    modoComparativo_, flg_acumProducto: boolean;

    constructor Create(resSP, resRecorte: TCronVar; param1, param2: TVarIdxs;
      TopeDe2: NReal; modoComparativo, flg_acumProducto: boolean);
    //Resuelve los valores que tengan que ver con los índices o el
    //encabezado de la simulacion
    procedure prepararse; override;
    procedure Evaluar; override;
    class function ayudaCronOper: string; override;
    class function tipo: string; override;
    function referenciaCronVar(cronVar: TCronVar): boolean; override;
    function resultados: string; override;
    function parametrosAdicionales: string; override;
    function serialize: string; override;
  end;

  TCronOper_suma_m = class(TCronOperMultiIndice)
  public
    constructor Create(res: TCronVar; params: TDAOfTVarIdxs);
    //Resuelve los valores que tengan que ver con los índices o el
    //encabezado de la simulacion
    procedure prepararse; override;
    procedure Evaluar; override;
    class function ayudaCronOper: string; override;
    class function tipo: string; override;
    procedure Free;
    function serialize: string; override;
  end;

  TCronOper_promedio_m = class(TCronOperMultiIndice)
  public
    constructor Create(res: TCronVar; params: TDAOfTVarIdxs);
    //Resuelve los valores que tengan que ver con los índices o el
    //encabezado de la simulacion
    procedure prepararse; override;
    procedure Evaluar; override;
    class function ayudaCronOper: string; override;
    class function tipo: string; override;
    procedure Free;
    function serialize: string; override;
  end;

  TCronOper_sumaProductoConDurpos_m = class(TCronOperMultiIndice)
  public
    constructor Create(res: TCronVar; params: TDAOfTVarIdxs);
    //Resuelve los valores que tengan que ver con los índices o el
    //encabezado de la simulacion
    procedure prepararse; override;
    procedure Evaluar; override;
    class function ayudaCronOper: string; override;
    class function tipo: string; override;
    procedure Free;
    function serialize: string; override;
  end;

  TCronOper_PromedioPonderadoConDurpos_m = class(TCronOperMultiIndice)
  public
    constructor Create(res: TCronVar; params: TDAOfTVarIdxs);
    //Resuelve los valores que tengan que ver con los índices o el
    //encabezado de la simulacion
    procedure prepararse; override;
    procedure Evaluar; override;
    class function ayudaCronOper: string; override;
    class function tipo: string; override;
    procedure Free;
    function serialize: string; override;
  end;


  TCronOper_Maximo_m = class(TCronOperMultiIndice)
  public
    constructor Create(res: TCronVar; params: TDAOfTVarIdxs);
    //Resuelve los valores que tengan que ver con los índices o el
    //encabezado de la simulacion
    procedure prepararse; override;
    procedure Evaluar; override;
    class function ayudaCronOper: string; override;
    class function tipo: string; override;
    procedure Free;
    function serialize: string; override;
  end;

implementation

uses
  uAuxiliaresEscrituraSimRes;


//-------------------
//Métodos de TVarIdxs
//===================

constructor TVarIdxs.Create(nombreIndice, nombreActor, nombreVar, numSimRes: string);
begin
  inherited Create;
  self.nombreIndice := nombreIndice;
  if nombreActor = '-' then
    nombreParticipe := 'Sala'
  else
    nombreParticipe := nombreActor;
  self.nombreVar := nombreVar;
  self.numSimRes := numSimRes;
  self.simRes := nil;
  self.idxs := nil;
end;

procedure TVarIdxs.prepararse(simRes: TResultadoSim);
begin
  self.simRes := simRes;
  idxs := simRes.getIndices(nombreParticipe, nombreVar);
end;

procedure TVarIdxs.Free;
begin
  setlength(idxs, 0);
  inherited Free;
end;

function TVarIdxs.serialize: string;
begin
  Result := encomille(nombreIndice) + #9 + encomille(nombreParticipe) +
    #9 + encomille(nombreVar) + #9 + numSimRes;
end;


//-------------------
//Métodos de TCronVar
//===================


constructor TCronVar.Create(nombre: string);
begin
  inherited Create;
  self.nombre := nombre;
  nCronicas := -1;
  nPasos := -1;
  dtIni := -1;
  durPaso_Horas := -1;
end;

function TCronVar.GetVal(kPaso, jCronica: integer): NReal;
var
  kPaso_, jCronica_: integer;
begin
  kPaso_ := min(kPaso, NPasos - 1);
  jCronica_ := min(jCronica, NCronicas - 1);
  Result := v_[kPaso_, jCronica_];
end;

procedure TCronVar.SetVal(kPaso, jCronica: integer; aValor: NReal);
begin
  v_[kPaso, jCronica] := aValor;
end;



procedure TCronVar.inicializar(nCronicas, nPasos: integer; dtIni: TDateTime;
  durPaso_Horas: NReal);
var
  k: integer;
begin

  if ((nCronicas <= 0) or (nPasos <= 0)) then
    raise Exception.Create('TCronVar.inicializar: llamaron al inicializar de la CronVar '
      + nombre +
      ' con nCronicas o nPasos <= 0. Asegurese que todas las CronVars que son usadas como parámetro en una PostOper sean utilizadas antes por una CronOper.');

  // si ya estaba inicializada la reinicializo
  // salvo que sea de la misma dimensión.
  if (self.nPasos > 0) then
  begin
    if (self.nPasos = nPasos) and (self.nCronicas = nCronicas) then
      exit;
    writeln('ATENCION!: Reinicializando CronVar: ' + Self.nombre +
      '( ' + IntToStr(self.nPasos) + 'x' + IntToStr(self.nCronicas) +
      ' )->( ' + IntToStr(self.nPasos) + 'x' + IntToStr(self.nCronicas) + ' )');
    LiberarMemoria;
  end;

  self.nPasos := nPasos;
  self.nCronicas := nCronicas;
  self.dtIni := dtIni;
  self.DurPaso_horas := DurPaso_Horas;

  setlength(v_, nPasos);
  for k := 0 to nPasos - 1 do
    setlength(v_[k], NCronicas);
  writeln('Inicializar( ' + nombre + ', ' + IntToStr(self.nPasos) +
    'x' + IntToStr(self.nCronicas) + ' ) ');
end;

// Valor a una Probabilidad de Excedencia.
function TCronVar.vpe(kPaso: integer; probabildadExcedencia: NReal): NReal;
var
  i: integer;
  arrayAux: TDAofNReal;
  res: NReal;
begin
  SetLength(arrayAux, Length(v_[kPaso]));
  for i := 0 to high(v_[kPaso]) do
    arrayAux[i] := v_[kPaso][i];
  QuickSort_Decreciente(arrayAux);
  res := arrayAux[trunc(probabildadExcedencia * high(arrayAux))];
  SetLength(arrayAux, 0);
  Result := res;
end;


procedure TCronVar.LiberarMemoria;
var
  k: integer;
begin
  for k := 0 to nPasos - 1 do
    setlength(v_[k], 0);
  setlength(v_, 0);
end;


procedure TCronVar.Free;
begin
  LiberarMemoria;
  inherited Free;
end;

function TCronVar.serialize: string;
begin
  Result := encomille(nombre);
end;


(****
procedure TCronVar.Write_R_csv(archi: string);
var
  fmat: textfile;
  dtFechaPrimerPaso, fechaDelPaso: TDateTime;
  dtPaso: double;
  aval: double;
begin

  Assignfile(fmat, archi + '.csv');
  rewrite(fmat);

  dtFechaPrimerPaso := Self.dtIni;
  dtPaso := self.DurPaso_horas / 24.0;

  // encabezado
  Write(fmat, '"date"' );
  for iCronica := 0 to NCronicas - 1 do
  begin
    aval := self[iPaso, iCronica];
    Write(fmat, ',', '"r'+IntToStr( iCronica+1 )+'"' );
  end;
  writeln(fmat);


  for iPaso := 0 to NPasos - 1 do
  begin
    fechaDelPaso := dtFechaPrimerPaso + dtPaso * iPaso;
    Write(fmat, DateTimeToStr(fechaDelPaso));

    for iCronica := 0 to NCronicas - 1 do
    begin
      aval := self[iPaso, iCronica];
      Write(fmat, ',', FloatToStr(aval));
    end;
    writeln(fmat);
  end;
  closefile(fmat);

end;

****)

procedure TCronVar.Write_R_csv(archi: string; idstr: string);
var
  fmat: textfile;
  aval: double;
  Year, Month, Day, hour, Minute, Second, Millisecond: word;
begin

  Assignfile(fmat, archi + '.csv');
  rewrite(fmat);

  for iPaso := 0 to NPasos - 1 do
  begin
    aval := self[iPaso, 0];
    Write(fmat, FloatToStr(aval));
    for iCronica := 1 to NCronicas - 1 do
    begin
      aval := self[iPaso, iCronica];
      Write(fmat, ',', FloatToStr(aval));
    end;
    writeln(fmat);
  end;
  closefile(fmat);

  Assignfile(fmat, archi + '_def.csv');
  rewrite(fmat);
  writeln(fmat, 'nPasos,', nPasos);
  writeln(fmat, 'nCronicas,', nCronicas);
  writeln(fmat, 'DurPaso_horas,', DurPaso_horas);
  writeln(fmat, 'PrimeraMuestra_dt,', dtIni);
  decodedate(dtIni, year, month, day);
  decodetime(dtIni, Hour, Minute, Second, MilliSecond);

  writeln(fmat, 'PrimeraMuestra_Year,', year);
  writeln(fmat, 'PrimeraMuestra_Month,', Month);
  writeln(fmat, 'PrimeraMuestra_Day,', day);

  writeln(fmat, 'PrimeraMuestra_Hour,', Hour);
  writeln(fmat, 'PrimeraMuestra_Minute,', Minute);
  writeln(fmat, 'PrimeraMuestra_Second,', Second);
  writeln(fmat, 'PrimeraMuestra_MilliSecond,', MilliSecond);
  writeln(fmat, 'idstr,', idstr);
(*
  for iPaso := 0 to NPasos - 1 do
  begin
    fechaDelPaso := dtFechaPrimerPaso + dtPaso * iPaso;
    Writeln(fmat, fechaDelPaso:20:10 );
    writeln(fmat);
  end;
  *)
  closefile(fmat);

end;

//--------------------
//Métodos de TCronOper
//====================


constructor TCronOper.create_GRIS;
begin
  inherited Create;
end;

function TCronOper.referenciaCronVar(cronVar: TCronVar): boolean;
begin
  Result := Self.res = cronVar;
end;


function TCronOper.resultados: string;
begin
  Result := res.nombre;
end;

function TCronOper.parametrosAdicionales: string;
begin
  Result := '-';
end;


function TCronOper.serialize: string;
begin
  Result := tipo + #9 + encomille(res.nombre);
end;

//----------------------------
//Métodos de TCronOperUnIndice
//============================

function TCronOperUnIndice.referenciaIndice(indice: TVarIdxs): boolean;
begin
  Result := Self.param1 = indice;
end;

function TCronOperUnIndice.parametrosIndice: string;
begin
  Result := param1.nombreIndice;
end;

//------------------------------
//Métodos de TCronOperDosIndices
//==============================

function TCronOperDosIndices.referenciaIndice(indice: TVarIdxs): boolean;
begin
  Result := inherited referenciaIndice(indice) or (self.param2 = indice);
end;

function TCronOperDosIndices.parametrosIndice: string;
begin
  if param2 <> nil then
    Result := inherited parametrosIndice + ', ' + param2.nombreIndice
  else
    Result := inherited parametrosIndice;
end;

//-------------------------------
//Métodos de TCronOperMultiIndice
//===============================

function TCronOperMultiIndice.referenciaIndice(indice: TVarIdxs): boolean;
var
  res: boolean;
  i: integer;
begin
  res := False;
  i := 0;
  while (i <= high(params)) and not res do
  begin
    res := params[i] = indice;
    i := i + 1;
  end;
  Result := res;
end;

function TCronOperMultiIndice.parametrosIndice: string;
var
  i: integer;
  res: string;
begin
  res := params[0].nombreIndice;
  for i := 1 to high(params) do
    res := res + ', ' + params[i].nombreIndice;
  Result := res;
end;



//-------------------------
//Métodos de TCronOper_suma
//=========================

constructor TCronOper_suma.Create(res: TCronVar; param1: TVarIdxs);
begin
  inherited Create;
  self.res := res;
  self.param1 := param1;
  self.indices := nil;
end;

procedure TCronOper_suma.prepararse;
begin
  res.inicializar(uSimResGlobs.nCronicasDelEstudio, uSimResGlobs.nPasosDelEstudio,
    uSimResGlobs.desde, param1.simRes.durPaso_);
  self.indices := param1.idxs;
end;

procedure TCronOper_suma.evaluar;
begin
  res[iPaso, iCronica] := param1.simRes.suma(indices);
end;

class function TCronOper_suma.ayudaCronOper: string;
begin
  Result := '< suma resCronVar param1Idxs >'#13#10 +
    'Suma los valores seleccionados por los índices (param1Idxs) y el resultado se'#13#10
    + 'guarda en (resCronVar).'#13#10;
end;

class function TCronOper_suma.tipo: string;
begin
  Result := 'suma';
end;


function TCronOper_suma.serialize: string;
begin
  Result := inherited serialize + #9 + encomille(param1.nombreIndice);
end;

//---------------------------------
//Métodos de TCronOper_sumaConSigno
//=================================

constructor TCronOper_sumaConSigno.Create(resPos, resNeg: TCronVar; param1: TVarIdxs);
begin
  inherited Create;
  self.res := resPos;
  self.resNeg := resNeg;
  self.param1 := param1;
  self.indices := nil;
end;

procedure TCronOper_sumaConSigno.prepararse;
begin
  res.inicializar(uSimResGlobs.nCronicasDelEstudio, uSimResGlobs.nPasosDelEstudio,
    uSimResGlobs.desde, param1.simRes.durPaso_);
  resNeg.inicializar(uSimResGlobs.nCronicasDelEstudio, uSimResGlobs.nPasosDelEstudio,
    uSimResGlobs.desde, param1.simRes.durPaso_);
  self.indices := param1.idxs;
end;

procedure TCronOper_sumaConSigno.evaluar;
begin
  param1.simRes.sumaConSigno(indices, sumaPos, sumaNeg);
  res[iPaso, iCronica] := sumaPos;
  resNeg[iPaso, iCronica] := sumaNeg;
end;

class function TCronOper_sumaConSigno.ayudaCronOper: string;
begin
  Result := '< sumaConSigno resPosCronVar resNegCronVar param1Idxs >'#13#10 +
    'Suma los valores seleccionados por los índices (param1Idxs) y el resultado lo'#13#10
    + 'guarda en (resPosCronVar) o (resNegCronVar) según sea positivo o negativo.'#13#10 +
    'Se pensó para analizar el flujo por una interconexión entre países y poder así'#13#10 + 'tener por separado flujo de importación y de exportación.'#13#10;
end;

class function TCronOper_sumaConSigno.tipo: string;
begin
  Result := 'sumaConSigno';
end;

function TCronOper_sumaConSigno.serialize: string;
begin
  Result := inherited serialize + #9 + encomille(resNeg.nombre) +
    #9 + encomille(param1.nombreIndice);
end;

function TCronOper_sumaConSigno.referenciaCronVar(cronVar: TCronVar): boolean;
begin
  Result := inherited referenciaCronVar(cronVar) or (cronVar = Self.resNeg);
end;

function TCronOper_sumaConSigno.resultados: string;
begin
  Result := inherited resultados + ', ' + resNeg.nombre;
end;

//-----------------------------
//Métodos de TCronOper_Combinar
//=============================

constructor TCronOper_Combinar.Create(res: TCronVar; params: TDAOfTVarIdxs;
  coefs: TDAofNReal);
begin
  if length(coefs) <> Length(params) then
    raise Exception.Create(
      'TCronOper_Combinar.Create: la cantidad de coeficientes pasados como parámetro no coincide con la cantidad de indices');
  inherited Create;
  self.res := res;
  self.coefs := coefs;
  self.params := params;
  self.indices := nil;
end;

procedure TCronOper_Combinar.prepararse;
var
  i: integer;
begin
  for i := 1 to high(params) do
    if params[0].simRes <> params[i].simRes then
      raise Exception.Create(
        'TCronOper_Combinar.Create: los indices pasados como parametro no corresponden al mismo SimRes');
  res.inicializar(uSimResGlobs.nCronicasDelEstudio, uSimResGlobs.nPasosDelEstudio,
    uSimResGlobs.desde, params[0].simRes.durPaso_);

  SetLength(indices, Length(params));
  for i := 0 to high(params) do
    self.indices[i] := params[i].idxs;
end;


procedure TCronOper_Combinar.Evaluar;
begin
  res[iPaso, iCronica] := params[0].simRes.combinar(indices, coefs);
end;

class function TCronOper_Combinar.ayudaCronOper: string;
begin
  Result :=
    '< combinar resCronVar nIndices param1Idxs ... paramNIndicesIdxs coef1Real ... coefnIndicesReal >'#13#10 + 'Realiza la combinación lineal de los coeficientes por los valores seleccionados por los indices'#13#10 + 'coef1Real * param1Idxs + ... + coefnIndicesReal * paramNIndicesIdxs y el resultado lo'#13#10 + 'guarda en resCronVar. nIndices es la cantidad de indices (y coeficientes) que se van a usar.'#13#10;
end;

class function TCronOper_Combinar.tipo: string;
begin
  Result := 'combinar';
end;

procedure TCronOper_Combinar.Free;
begin
  SetLength(indices, 0);
  inherited Free;
end;

function TCronOper_Combinar.parametrosAdicionales: string;
begin
  Result := 'coeficientes= ' + TDAOfNRealToStringSinTamanio(coefs, 16, 10, ', ');
end;

function TCronOper_Combinar.serialize: string;
begin
  Result := inherited serialize + #9 + TDAOfNRealToTabbedStringConTamanio(
    coefs, 8, 3) + #9 + TDAOfTVarIdxsToString(params);
end;

//-----------------------------
//Métodos de TCronOper_promedio
//=============================

constructor TCronOper_promedio.Create(res: TCronVar; param1: TVarIdxs);
begin
  inherited Create;
  self.res := res;
  self.param1 := param1;
  self.indices := nil;
end;

procedure TCronOper_promedio.prepararse;
begin
  res.inicializar(uSimResGlobs.nCronicasDelEstudio, uSimResGlobs.nPasosDelEstudio,
    uSimResGlobs.desde, param1.simRes.durPaso_);
  self.indices := param1.idxs;
end;


procedure TCronOper_promedio.evaluar;
begin
  res[iPaso, iCronica] := param1.simRes.promedio(indices);
end;

class function TCronOper_promedio.ayudaCronOper: string;
begin
  Result := '< promedio resCronVar param1Idxs >'#13#10 +
    'Caclula el promedio de los valores seleccionados por (param1Indxs) y lo guarda'#13#10
    + 'en (resCronVar)'#13#10;
end;

class function TCronOper_promedio.tipo: string;
begin
  Result := 'promedio';
end;


function TCronOper_promedio.serialize: string;
begin
  Result := inherited serialize + #9 + encomille(param1.nombreIndice);
end;

//------------------------------------------
//Métodos de TCronOper_sumaProductoConDurpos
//==========================================

constructor TCronOper_sumaProductoConDurpos.Create(res: TCronVar; param1: TVarIdxs);
begin
  inherited Create;
  self.res := res;
  self.param1 := param1;
  self.indices := nil;
end;

procedure TCronOper_sumaProductoConDurpos.prepararse;
begin
  res.inicializar(uSimResGlobs.nCronicasDelEstudio, uSimResGlobs.nPasosDelEstudio,
    uSimResGlobs.desde, param1.simRes.durPaso_);
  self.indices := param1.idxs;
end;

procedure TCronOper_sumaProductoConDurpos.evaluar;
begin
  res[iPaso, iCronica] := param1.simRes.sumaproductocondurpos(indices);
end;

class function TCronOper_sumaProductoConDurpos.ayudaCronOper: string;
begin
  Result := '< sumaProductoConDurpos resCronVar param1Idxs >'#13#10;
end;

class function TCronOper_sumaProductoConDurpos.tipo: string;
begin
  Result := 'sumaProductoConDurpos';
end;

function TCronOper_sumaProductoConDurpos.serialize: string;
begin
  Result := inherited serialize + #9 + encomille(param1.nombreIndice);
end;


//-----------------------------------------------
//Métodos de TCronOper_sumaProductoConDurposHasta
//===============================================

constructor TCronOper_sumaProductoConDurposHasta.Create(res: TCronVar;
  param1: TVarIdxs; kposteHasta: integer);
begin
  inherited Create;
  self.res := res;
  self.param1 := param1;
  self.kposteHasta := kposteHasta;
  self.indices := nil;
end;

procedure TCronOper_sumaProductoConDurposHasta.prepararse;
begin
  res.inicializar(uSimResGlobs.nCronicasDelEstudio, uSimResGlobs.nPasosDelEstudio,
    uSimResGlobs.desde, param1.simRes.durPaso_);
  self.indices := param1.idxs;
end;

procedure TCronOper_sumaProductoConDurposHasta.evaluar;
begin
  res[iPaso, iCronica] := param1.simRes.sumaproductoconDurposHasta(indices, kposteHasta);
end;

class function TCronOper_sumaProductoConDurposHasta.ayudaCronOper: string;
begin
  Result := '< sumaProductoConDurposHasta resCronVar param1Idxs kposteHasta_integer >'#13#10;
end;

class function TCronOper_sumaProductoConDurposHasta.tipo: string;
begin
  Result := 'sumaProductoConDurposHasta';
end;

function TCronOper_sumaProductoConDurposHasta.parametrosAdicionales: string;
begin
  Result := 'kPosteHasta= ' + IntToStr(kposteHasta);
end;



function TCronOper_sumaProductoConDurposHasta.serialize: string;
begin
  Result := inherited serialize + #9 + encomille(param1.nombreIndice) +
    #9 + IntToStr(kposteHasta);
end;

//------------------------------------------
//Métodos de TCronOper_promedioPonderadoPorDurpos
//==========================================

constructor TCronOper_promedioPonderadoPorDurpos.Create(res: TCronVar;
  param1: TVarIdxs);
begin
  inherited Create;
  self.res := res;
  self.param1 := param1;
  self.indices := nil;
end;

procedure TCronOper_promedioPonderadoPorDurpos.prepararse;
begin
  res.inicializar(uSimResGlobs.nCronicasDelEstudio, uSimResGlobs.nPasosDelEstudio,
    uSimResGlobs.desde, param1.simRes.durPaso_);
  self.indices := param1.idxs;
end;

procedure TCronOper_promedioPonderadoPorDurpos.evaluar;
begin
  res[iPaso, iCronica] := param1.simRes.promedioPonderadoPorDurpos(indices);
end;

class function TCronOper_promedioPonderadoPorDurpos.ayudaCronOper: string;
begin
  Result := '< promedioPonderadoPorDurpos resCronVar param1Idxs >'#13#10;
end;

class function TCronOper_promedioPonderadoPorDurpos.tipo: string;
begin
  Result := 'promedioPonderadoPorDurpos';
end;

function TCronOper_promedioPonderadoPorDurpos.serialize: string;
begin
  Result := inherited serialize + #9 + encomille(param1.nombreIndice);
end;


//-----------------------------------
//Métodos de TCronOper_filtrarCronica
//===================================

constructor TCronOper_filtrarCronica.Create(res: TCronVar; param1: TVarIdxs;
  kCronica: integer);
begin
  inherited Create;
  self.res := res;
  self.param1 := param1;
  self.kCronica := kCronica;
  self.indices := nil;
end;

procedure TCronOper_filtrarCronica.prepararse;
begin
  res.inicializar(1, uSimResGlobs.nPasosDelEstudio, uSimResGlobs.desde,
    param1.simRes.durPaso_);
  self.indices := param1.idxs;
end;

procedure TCronOper_filtrarCronica.Evaluar;
begin
  if iCronica = kCronica - 1 then
    res[iPaso, 0] := param1.simRes.promedio(indices);
end;

class function TCronOper_filtrarCronica.ayudaCronOper: string;
begin
  Result := '< filtrarCronica resCronVar param1Idxs kCronica_integer >'#13#10;
end;

class function TCronOper_filtrarCronica.tipo: string;
begin
  Result := 'filtrarCronica';
end;

function TCronOper_filtrarCronica.parametrosAdicionales: string;
begin
  Result := 'Crónica= ' + IntToStr(kCronica);
end;

function TCronOper_filtrarCronica.serialize: string;
begin
  Result := inherited serialize + #9 + encomille(param1.nombreIndice) +
    #9 + IntToStr(kCronica);
end;


//-------------------------------------------------
//Métodos de TCronOper_sumaProductoConDurposTopeado
//=================================================

constructor TCronOper_sumaProductoConDurposTopeado.Create(resSP, resRecorte: TCronVar;
  param1: TVarIdxs; TopeDe1: NReal);
begin
  inherited Create;
  self.res := resSP;
  self.resRecorte := resRecorte;
  self.param1 := param1;
  self.TopeDe1 := TopeDe1;
  self.indices := nil;
end;

procedure TCronOper_sumaProductoConDurposTopeado.prepararse;
begin
  res.inicializar(uSimResGlobs.nCronicasDelEstudio, uSimResGlobs.nPasosDelEstudio,
    uSimResGlobs.desde, param1.simRes.durPaso_);
  if resRecorte <> nil then
    resRecorte.inicializar(uSimResGlobs.nCronicasDelEstudio,
      uSimResGlobs.nPasosDelEstudio, uSimResGlobs.desde, param1.simRes.durPaso_);
  self.indices := param1.idxs;
end;

procedure TCronOper_sumaProductoConDurposTopeado.Evaluar;
begin
  res[iPaso, iCronica] := param1.simRes.sumaProductoConDurposTopeado(
    indices, TopeDe1, recorte);
  if resRecorte <> nil then
    resRecorte[iPaso, iCronica] := recorte;
end;

class function TCronOper_sumaProductoConDurposTopeado.ayudaCronOper: string;
begin
  Result :=
    '< sumaProductoConDurposTopeado resSPCronVar resRecorteCronVar paramAIdxs TopeDeA_NReal>'#13#10 + 'Calcula la suma producto de los valores seleccionados por paramAIdxs, considerando topeados'#13#10 + 'los valores de A por el valor del parámetro TopeDeA.'#13#10 +
    'Los resultados e cargan en resSPCronVar y los valores recortados se cargan en resRecorteCronVar.'#13#10 + 'Si no interesa asignar los recortes se puede poner "nil" en resRecorteCronVar.'#13#10;
end;

class function TCronOper_sumaProductoConDurposTopeado.tipo: string;
begin
  Result := 'sumaProductoConDurposTopeado';
end;

function TCronOper_sumaProductoConDurposTopeado.referenciaCronVar(
  cronVar: TCronVar): boolean;
begin
  Result := inherited referenciaCronVar(cronVar) or (Self.resRecorte = cronVar);
end;

function TCronOper_sumaProductoConDurposTopeado.resultados: string;
begin
  if resRecorte <> nil then
    Result := inherited resultados + ', ' + resRecorte.nombre
  else
    Result := inherited resultados;
end;

function TCronOper_sumaProductoConDurposTopeado.parametrosAdicionales: string;
begin
  Result := 'TopeDe1= ' + FloatToStrF(TopeDe1, ffGeneral, 16, 10);
end;


function TCronOper_sumaProductoConDurposTopeado.serialize: string;
begin
  Result := inherited serialize + #9 + encomille(nombreCronVar(resRecorte)) +
    #9 + encomille(param1.nombreIndice) + #9 + FloatToStr(TopeDe1);

end;

//------------------------------------------------------
//Métodos de TCronOper_sumaDobleProductoConDurposTopeado
//======================================================

constructor TCronOper_sumaDobleProductoConDurposTopeado.Create(
  resSP, resRecorte: TCronVar; param1, param2: TVarIdxs; TopeDe2: NReal;
  modoComparativo, flg_AcumProducto: boolean);
begin
  inherited Create;
  self.res := resSP;
  self.resRecorte := resRecorte;
  self.param1 := param1;
  self.param2 := param2;
  self.TopeDe2 := TopeDe2;
  self.indices := nil;
  self.indices2 := nil;
  self.modoComparativo_ := modoComparativo;
  self.flg_acumProducto := flg_AcumProducto;
end;

procedure TCronOper_sumaDobleProductoConDurposTopeado.prepararse;
begin
  Assert(param1.simRes = param2.simRes);
  //Se asume que paramA y paramB son indices sobre el mismo simres
  res.inicializar(uSimResGlobs.nCronicasDelEstudio, uSimResGlobs.nPasosDelEstudio,
    uSimResGlobs.desde, param1.simRes.durPaso_);
  if resRecorte <> nil then
    resRecorte.inicializar(uSimResGlobs.nCronicasDelEstudio,
      uSimResGlobs.nPasosDelEstudio, uSimResGlobs.desde, param1.simRes.durPaso_);
  self.indices := param1.idxs;
  self.indices2 := param2.idxs;
end;

procedure TCronOper_sumaDobleProductoConDurposTopeado.Evaluar;
begin
  res[iPaso, iCronica] := param1.simRes.sumaDobleProductoConDurposTopeado(
    indices, indices2, TopeDe2, recorte, modoComparativo_, flg_acumProducto);
  if resRecorte <> nil then
    resRecorte[iPaso, iCronica] := recorte;
end;

class function TCronOper_sumaDobleProductoConDurposTopeado.ayudaCronOper: string;
begin
  Result :=
    '< sumaDobleProductoConDurposTopeado resSPCronVar resRecorteCronVar paramAIdxs paramBIdxs TopeDeB_NReal>'#13#10 + 'Calcula la suma producto de los valores seleccionados por paramAIdxs y paramBIdxs, considerando topeados'#13#10 + 'los valores B por el valor del parámetro TopeDeB.'#13#10 + 'Los resultados e cargan en resSPCronVar y los valores recortados se cargan en resRecorteCronVar.'#13#10 + 'Si no interesa asignar los recortes se puede poner "nil" en resRecorteCronVar.'#13#10 + 'Esta operación es útil para calcular remuneraciones al spot. Para ello poner en paramBIdxs los indices'#13#10 + 'que seleccionan los costos marginales de un nodo y en TopeDeB_NReal el tope puesto al precio spot.'#13#10;
end;

class function TCronOper_sumaDobleProductoConDurposTopeado.tipo: string;
begin
  Result := 'sumaDobleProductoConDurposTopeado';
end;

function TCronOper_sumaDobleProductoConDurposTopeado.referenciaCronVar(
  cronVar: TCronVar): boolean;
begin
  Result := inherited referenciaCronVar(cronVar) or (self.resRecorte = cronVar);
end;

function TCronOper_sumaDobleProductoConDurposTopeado.resultados: string;
begin
  if resRecorte <> nil then
    Result := inherited resultados + ', ' + resRecorte.nombre
  else
    Result := inherited resultados;
end;

function TCronOper_sumaDobleProductoConDurposTopeado.parametrosAdicionales: string;
begin
  Result := 'TopeDe2= ' + FloatToStrF(TopeDe2, ffGeneral, 16, 10);
end;

function TCronOper_sumaDobleProductoConDurposTopeado.serialize: string;
begin
  Result := inherited serialize + #9 + encomille(nombreCronVar(resRecorte)) +
    #9 + encomille(param1.nombreIndice) + #9 + encomille(param2.nombreIndice) +
    #9 + FloatToStr(TopeDe2) + #9 + BoolToStr(modoComparativo_, 'True', 'False') +
    #9 + BoolToStr(flg_acumProducto, 'True', 'False');

end;


//---------------------------
//Métodos de TCronOper_suma_m
//===========================

constructor TCronOper_suma_m.Create(res: TCronVar; params: TDAOfTVarIdxs);
begin
  inherited Create;
  self.res := res;
  self.params := params;
  self.indices := nil;
end;

procedure TCronOper_suma_m.prepararse;
var
  i: integer;
begin
  //Se asume que todos los params son indices sobre el mismo simRes
  res.inicializar(uSimResGlobs.nCronicasDelEstudio, uSimResGlobs.nPasosDelEstudio,
    uSimResGlobs.desde, params[0].simRes.durPaso_);
  SetLength(self.indices, length(params));
  for i := 0 to high(params) do
    indices[i] := params[i].idxs;
end;

procedure TCronOper_suma_m.evaluar;
begin
  res[iPaso, iCronica] := params[0].simRes.suma_m(indices);
end;

class function TCronOper_suma_m.ayudaCronOper: string;
begin
  Result := '<suma_m resCronVar; params: TDAOfTVarIdxs )'#13#10 +
    'Esta operación realiza la suma de un conjunto de variables especificadas como índices.'#13#10 + 'el primer parámetro tiene que ser un entero indicando la cantidad de índices que se sumarán.'#13#10 + 'el resto de los parámetros son los nombres de cada uno de los índices a sumar.'#13#10 + 'Por Ejemplo, si los índices iA_GWh e iB_GWh seleccionan las energias generadas por la central'#13#10 + 'A y la central B respectivamente en todos sus postes, la siguiente definicion guardaría'#13#10 + 'la energía generada por las dos centrales en la variabel sumE1E2 que tendría que definirse en (+CronVar)'#13#10 + 'suma_m sumE1E2 2 iA_GWh iB_GWh'#13#10;
end;

class function TCronOper_suma_m.tipo: string;
begin
  Result := 'suma_m';
end;

procedure TCronOper_suma_m.Free;
begin
  SetLength(indices, 0);
  inherited Free;
end;

function TCronOper_suma_m.serialize: string;
begin
  Result := inherited serialize + #9 + TDAOfTVarIdxsToStringConTamanio(params);
end;



//-------------------------------
//Métodos de TCronOper_promedio_m
//===============================

constructor TCronOper_promedio_m.Create(res: TCronVar; params: TDAOfTVarIdxs);
begin
  inherited Create;
  self.res := res;
  self.params := params;
  self.indices := nil;
end;

procedure TCronOper_promedio_m.prepararse;
var
  i: integer;
begin
  //Se asume que todos los params son indices sobre el mismo simRes
  res.inicializar(uSimResGlobs.nCronicasDelEstudio, uSimResGlobs.nPasosDelEstudio,
    uSimResGlobs.desde, params[0].simRes.durPaso_);
  SetLength(self.indices, length(params));
  for i := 0 to high(params) do
    indices[i] := params[i].idxs;
end;

procedure TCronOper_promedio_m.evaluar;
begin
  res[iPaso, iCronica] := params[0].simRes.promedio_m(indices);
end;

class function TCronOper_promedio_m.ayudaCronOper: string;
begin
  Result := '< promedio_m( res: TCronVar; params: TDAOfTVarIdxs ) >'#13#10;
end;

class function TCronOper_promedio_m.tipo: string;
begin
  Result := 'promedio_m';
end;

procedure TCronOper_promedio_m.Free;
begin
  SetLength(indices, 0);
  inherited Free;
end;

function TCronOper_promedio_m.serialize: string;
begin
  Result := inherited serialize + #9 + TDAOfTVarIdxsToStringConTamanio(params);
end;

//--------------------------------------------
//Métodos de TCronOper_sumaProductoConDurpos_m
//============================================

constructor TCronOper_sumaProductoConDurpos_m.Create(res: TCronVar;
  params: TDAOfTVarIdxs);
begin
  inherited Create;
  self.res := res;
  self.params := params;
  self.indices := nil;
end;

procedure TCronOper_sumaProductoConDurpos_m.prepararse;
var
  i: integer;
begin
  //Se asume que todos los params son indices sobre el mismo simRes
  res.inicializar(uSimResGlobs.nCronicasDelEstudio, uSimResGlobs.nPasosDelEstudio,
    uSimResGlobs.desde, params[0].simRes.durPaso_);
  SetLength(self.indices, length(params));
  for i := 0 to high(params) do
    indices[i] := params[i].idxs;
end;

procedure TCronOper_sumaProductoConDurpos_m.evaluar;
begin
  res[iPaso, iCronica] := params[0].simRes.sumaproductocondurpos_m(indices);
end;

class function TCronOper_sumaProductoConDurpos_m.ayudaCronOper: string;
begin
  Result := '< sumaProductoConDurpos_m( res: TCronVar; params: TDAOfTVarIdxs ) >'#13#10;
end;

class function TCronOper_sumaProductoConDurpos_m.tipo: string;
begin
  Result := 'sumaProductoConDurpos_m';
end;

procedure TCronOper_sumaProductoConDurpos_m.Free;
begin
  SetLength(indices, 0);
  inherited Free;
end;

function TCronOper_sumaProductoConDurpos_m.serialize: string;
begin
  Result := inherited serialize + #9 + TDAOfTVarIdxsToStringConTamanio(params);
end;


//--------------------------------------------
//Métodos de TCronOper_promedioPonderadoConDurpos_m
//============================================

constructor TCronOper_promedioPonderadoConDurpos_m.Create(res: TCronVar;
  params: TDAOfTVarIdxs);
begin
  inherited Create;
  self.res := res;
  self.params := params;
  self.indices := nil;
end;

procedure TCronOper_promedioPonderadoConDurpos_m.prepararse;
var
  i: integer;
begin
  //Se asume que todos los params son indices sobre el mismo simRes
  res.inicializar(uSimResGlobs.nCronicasDelEstudio, uSimResGlobs.nPasosDelEstudio,
    uSimResGlobs.desde, params[0].simRes.durPaso_);
  SetLength(self.indices, length(params));
  for i := 0 to high(params) do
    indices[i] := params[i].idxs;
end;

procedure TCronOper_promedioPonderadoConDurpos_m.evaluar;
begin
  res[iPaso, iCronica] := params[0].simRes.promedioPonderadoCondurPos_m(indices);
end;

class function TCronOper_promedioPonderadoConDurpos_m.ayudaCronOper: string;
begin
  Result := '< PromedioPonderadoConDurpos_m( res: TCronVar; params: TDAOfTVarIdxs ) >'#13#10;
end;

class function TCronOper_promedioPonderadoConDurpos_m.tipo: string;
begin
  Result := 'promedioPonderadoConDurpos_m';
end;

procedure TCronOper_promedioPonderadoConDurpos_m.Free;
begin
  SetLength(indices, 0);
  inherited Free;
end;


function TCronOper_promedioPonderadoConDurpos_m.serialize: string;
begin
  Result := inherited serialize + #9 + TDAOfTVarIdxsToStringConTamanio(params);
end;


//-----------------------------
//Métodos de TCronOper_Maximo_m
//=============================

constructor TCronOper_Maximo_m.Create(res: TCronVar; params: TDAOfTVarIdxs);
begin
  inherited Create;
  self.res := res;
  self.params := params;
  self.indices := nil;
end;

procedure TCronOper_Maximo_m.prepararse;
var
  i: integer;
begin
  //Se asume que todos los params son indices sobre el mismo simRes
  res.inicializar(uSimResGlobs.nCronicasDelEstudio, uSimResGlobs.nPasosDelEstudio,
    uSimResGlobs.desde, params[0].simRes.durPaso_);

  SetLength(self.indices, length(params));
  for i := 0 to high(params) do
    indices[i] := params[i].idxs;
end;

procedure TCronOper_Maximo_m.evaluar;
begin
  res[iPaso, iCronica] := params[0].simRes.maximo_m(indices);
end;

class function TCronOper_Maximo_m.ayudaCronOper: string;
begin
  Result := '<maximo_m resCronVar; params: TDAOfTVarIdxs )'#13#10 +
    'Esta operación obtiene el máximo valor de un conjunto de variables especificadas como índices.'#13#10 + 'El primero pámetro es la cronVar resultado.'#13#10 +
    'El segundo parámetro tiene que ser un entero indicando la cantidad de índices en que se buscará el máximo.'#13#10 + 'el resto de los parámetros son los nombres de cada uno de los índices a sumar.'#13#10 + 'Por Ejemplo, si los índices iA_GWh e iB_GWh seleccionan las energias generadas por la central'#13#10 + 'A y la central B respectivamente en todos sus postes, la siguiente definicion guardaría'#13#10 + 'la máxima energía generada entre las dos centrales en la variabel maxE1E2 que tendría que definirse en (+CronVar)'#13#10 + 'maximo_m maxE1E2 2 iA_GWh iB_GWh'#13#10;
end;

class function TCronOper_Maximo_m.tipo: string;
begin
  Result := 'maximo_m';
end;

procedure TCronOper_Maximo_m.Free;
begin
  SetLength(indices, 0);
  inherited Free;
end;

function TCronOper_Maximo_m.serialize: string;
begin
  Result := inherited serialize + #9 + TDAOfTVarIdxsToStringConTamanio(params);
end;

end.
