unit uAcumuladorVars;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, xMatDefs, uFechas, uSeleccionarArchivo, uDTResultados,
  //uExcelFile,
  uAuxiliares,
  ComCtrls,
  uverdoc;

type
  TAcumuladorVars = class(TForm)
    LBDisponibles: TListBox;
    LBSeleccionadas: TListBox;
    BAddRemove: TButton;
    BGenerar: TButton;
    PB: TProgressBar;
    BAyuda: TButton;
    LVarsDisp: TLabel;
    LVarsSelec: TLabel;
    CBSeleccionarPoste: TCheckBox;
    procedure LBDisponiblesClick(Sender: TObject);
    procedure LBSeleccionadasClick(Sender: TObject);
    procedure BAddRemoveClick(Sender: TObject);
    procedure BGenerarClick(Sender: TObject);
    procedure BAyudaClick(Sender: TObject);
    procedure LBDisponiblesDblClick(Sender: TObject);
    procedure LBSeleccionadasDblClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    archivo: String;
    datosSim: DTResultadoSim;

    //retorna el indice de columna en el archivo original del string actVar
    function indicesColsSeleccionadas : TDAofNInt;

    procedure sumarVars(archivoEntrada, archivoSalida: String);

    //Inserta la etiqueta de variable s en listaDestino respetando el orden en
    //que estaban en el archivo
    procedure insertarEnOrden(listaDestino: TlistBox; s : String);

    //Retorna la lista de nombre de variables (sin actor, ni unidades) para todos los postes
    function variablesDelPoste(cadena : String) : TStringList;

    procedure swapVar(listaOrigen, listaDestino: TListBox);
  public
    Constructor Create(owner : TComponent ; nArch: String); reintroduce;
    class function filtrosDeArchivos: String;
    class function filtrosDeArchivosSave: String;
  end;

var
  AcumuladorVars: TAcumuladorVars;

implementation

uses uconstantesSimSEE;

{$R *.dfm}

Constructor TAcumuladorVars.Create(owner : TComponent ; nArch: String);
var
  i: Integer;
  linea: String;
begin
  inherited Create(owner);
  archivo:= nArch;
  Self.Caption:= 'Acumulador de Variables - ' + nArch;
  datosSim:= DTResultadoSim.Create(archivo);
  datosSim.read_DatosSim;
  for i:= 2 to datosSim.actoresPorColumnas.Count - 1 do
  begin
    datosSim.JoinNomVar(datosSim.actoresPorColumnas[i], datosSim.variablesPorColumnas[i], datosSim.unidadesPorColumnas[i], linea);
    LBDisponibles.Items.Add(linea);
  end;
end;

class function TAcumuladorVars.filtrosDeArchivos: String;
begin
  result:= 'Archivos de Resultado de Simulación (simres_*.xlt)|simres_*.xlt|Todos los Archivos (*.*)|*.*';
end;

class function TAcumuladorVars.filtrosDeArchivosSave: String;
begin
  result:= 'Plantilla (*.xlt)|*.xlt|Archivos de Texto (*.txt)|*.txt|Todos los Archivos (*.*)|*.*';
end;

procedure TAcumuladorVars.FormDestroy(Sender: TObject);
begin
  datosSim.Free;
  inherited;
end;

function SortByIndiceActVar(Item1, Item2: Pointer) : Integer;
var
  i1, i2 : Integer;
begin
  i1:= AcumuladorVars.datosSim.columnaActUniVar(String(Item1));
  i2:= AcumuladorVars.datosSim.columnaActUniVar(String(Item2));
  if i1 < i2 then
    result:= -1
  else if i1 = i2 then
    result:= 0
  else result:= 1;
end;

procedure TAcumuladorVars.BAddRemoveClick(Sender: TObject);
begin
  if BAddRemove.Caption = '->' then
    swapVar(LBDisponibles, LBSeleccionadas)
  else
    swapVar(LBSeleccionadas, LBDisponibles);
end;

procedure TAcumuladorVars.swapVar(listaOrigen, listaDestino: TListBox);
var
  index, i: Integer;
  cadena: String;
  varsPostes: TStringList;
begin
  index:= listaOrigen.ItemIndex;
  if index >= 0 then
  begin
    cadena:= listaOrigen.Items[index];
    if CBSeleccionarPoste.Checked then
    begin
      varsPostes:= variablesDelPoste(cadena);
      for i:= 0 to varsPostes.Count -1 do
      begin
        if listaDestino.Items.IndexOf(varsPostes[i]) = -1 then
        begin
          insertarEnOrden(listaDestino, varsPostes[i]);
          listaOrigen.Items.Delete(listaOrigen.Items.IndexOf(varsPostes[i]));
        end;
      end;
      varsPostes.Free;
    end
    else
    begin
      insertarEnOrden(listaDestino, cadena);
      listaOrigen.Items.Delete(index);
    end;
    if listaOrigen.Count <> 0 then
      listaOrigen.ItemIndex:= index;
    listaDestino.ItemIndex:= -1;
  end;
end;

procedure TAcumuladorVars.BAyudaClick(Sender: TObject);
begin
  verdoc( 'procesador-resultados-AcumuladorVars', 'Ayuda del Acumulador de Variables');
end;

procedure TAcumuladorVars.BGenerarClick(Sender: TObject);
var
  archivoSalida: String;
  fSelect: TSeleccionarArchivo;
begin
  if LBSeleccionadas.Count <> 0 then
  begin
    fSelect:= TSeleccionarArchivo.Create(self, TAcumuladorVars.filtrosDeArchivosSave, ExtractFilePath(archivo), true);
    if fSelect.ShowModal = mrOk then
    begin
      archivoSalida:= fSelect.getFileName;
      fSelect.Free;
      LBDisponibles.Enabled:= false;
      LBSeleccionadas.Enabled:= false;
      BAddRemove.Enabled:= false;
      sumarVars(archivo, archivoSalida);
      LBDisponibles.Enabled:= true;
      LBSeleccionadas.Enabled:= true;
      BAddRemove.Enabled:= true;
    end
    else
      fSelect.Free
  end
  else
    ShowMessage('No selecciono ninguna variable!')
end;

function TAcumuladorVars.indicesColsSeleccionadas : TDAofNInt;
var
  res: TDAofNInt;
  i: Integer;
begin
  SetLength(res, LBSeleccionadas.Items.Count);
  for i:= 0 to high(res) do
    res[i]:= datosSim.columnaActUniVar(LBSeleccionadas.Items[i]);
  QuickSort_Creciente(res);
  result:= res;
end;

procedure TAcumuladorVars.sumarVars(archivoEntrada, archivoSalida: String);
var
  entrada, salida: TextFile;

  iPaso, iCronica, ivar, icol: Integer;
  colsSeleccionadas: TDAofNInt;
  fila: TDAofNReal;
  matrRes: array of TDAofNReal;

  invNCronicas, invNPasos: NReal;
  promPaso: NReal;
  promediosPorCronica, promediosPorPaso : TDAofNReal;
  linea: String;
begin
  try
    AssignFile(entrada, archivoEntrada);
    Reset(entrada);
    try
      AssignFile(salida, archivoSalida);
      Rewrite(salida);

      PB.Min:= 0;
      PB.Position:= 0;
      PB.Max:= datosSim.nCronicas + 2;//de 0 a nCronicas-1 por las que leo del archivo,
                                      //1 mas para promediar y 1 mas para guardar los
                                     //resultados
      PB.Step:= 1;

      colsSeleccionadas:= indicesColsSeleccionadas;
      SetLength(matrRes, datosSim.nPasos);
      for iPaso:= 0 to datosSim.nPasos -1 do
      begin
        SetLength(matrRes[iPaso], datosSim.nCronicas);
        fila:= matrRes[iPaso];
        for iCronica := 0 to high(fila) do
          fila[iCronica]:= 0;
      end;

      //Leo hasta antes del primer paso
      for ivar:= 0 to 7 + datosSim.nActores + 5 do
        readln(entrada, linea);

      for iCronica:= 0 to datosSim.nCronicas - 1 do
      begin
        for iPaso:= 0 to datosSim.nPasos - 1 do
        begin
          readln(entrada, linea);
          icol:= 0;
          for ivar:= 0 to high(colsSeleccionadas) do
          begin
            while icol < colsSeleccionadas[ivar] do
            begin
              inc(icol);
              nextTab(linea);
            end;
            matrRes[iPaso][iCronica]:= matrRes[iPaso][iCronica] + StrToFloat(nextTab(linea));
            inc(icol);
          end;
        end;
        //leo 5 lineas que no se usan
        if not EoF(entrada) then readln(entrada, linea);
        if not EoF(entrada) then readln(entrada, linea);
        if not EoF(entrada) then readln(entrada, linea);
        if not EoF(entrada) then readln(entrada, linea);
        if not EoF(entrada) then readln(entrada, linea);
        PB.StepIt;
        Application.ProcessMessages;
      end;

      SetLength(promediosPorPaso, datosSim.nPasos);
{      for iPaso:= 0 to high(promediosPorPaso) do
        promediosPorPaso[iPaso]:= 0;}
      SetLength(promediosPorCronica, datosSim.nCronicas);
      for iCronica:= 0 to high(promediosPorCronica) do
        promediosPorCronica[iCronica]:= 0;

      invNCronicas:= 1 / datosSim.nCronicas;
      for iPaso:= 0 to high(promediosPorPaso) do
      begin
        fila:= matrRes[ipaso];
        promPaso:= 0;
        for iCronica:= 0 to high(promediosPorCronica) do
        begin
          promPaso:= promPaso + fila[iCronica];
          promediosPorCronica[iCronica]:= promediosPorCronica[iCronica] + fila[iCronica];
        end;
        promediosPorPaso[iPaso]:= promPaso * invNCronicas;
      end;
      PB.StepIt;
      Application.ProcessMessages;

      linea:= 'Suma a traves de las crónicas de: ';
      for icol:= 0 to LBSeleccionadas.Items.Count - 1 do
        linea:= linea + LBSeleccionadas.Items[icol];
      writeln(salida, linea);

      invNPasos:= 1 / datosSim.nPasos;
      for iCronica:= 0 to high(promediosPorCronica) do
        promediosPorCronica[iCronica]:= promediosPorCronica[iCronica] * invNPasos;

      write(salida, 'Paso\Cronica' + #9);
      for iCronica:= 1 to datosSim.nCronicas do
        Write(salida, IntToStr(iCronica) + #9);
      writeln(salida, 'Promedio_del_Paso');

      for iPaso:= 0 to datosSim.nPasos - 1 do
      begin
        Write(salida, IntToStr(iPaso + 1) + #9);
        fila:= matrRes[iPaso];
        for iCronica := 0 to high(fila) do
          Write(salida, FloatToStr(fila[iCronica]) + #9);
        writeln(salida, FloatToStr(promediosPorPaso[iPaso]));
      end;
      write(salida, 'Promedio_de_la_Cronica' + #9);
      for iCronica:= 0 to high(promediosPorCronica) do
        write(salida, FloatToStr(promediosPorCronica[iCronica]) + #9);
      PB.StepIt;
      Application.ProcessMessages;
    finally
      CloseFile(salida);
    end;
  finally
    CloseFile(entrada);
  end;
end;

procedure TAcumuladorVars.insertarEnOrden(listaDestino: TlistBox; s : String);
var
  i, indicesS: Integer;
begin
  indicesS:= datosSim.columnaActUniVar(s);
  i:= 0;
  while (i < listaDestino.Items.Count) and
        (datosSim.columnaActUniVar(listaDestino.Items[i]) < indicesS) do
    inc(i);
  listaDestino.Items.Insert(i, s)
end;

function TAcumuladorVars.variablesDelPoste(cadena : String) : TStringList;
var
  ok: boolean;
  pos_P, iPoste: Integer;
  nombreSinNroPoste, nroPoste, nomActor, nomVar, unidades: String;
  res: TStringList;
begin
  ok:= false;
  nombreSinNroPoste:= '';
  datosSim.SplitNomVar(cadena, nomActor, nomVar, unidades);
  repeat
    pos_P:= pos('_P', nomVar);
    if pos_P <> 0 then
    begin
      nombreSinNroPoste:= nombreSinNroPoste + Copy(nomVar, 1, pos_P + 1);
      nroPoste:= copy(nomVar, pos_P + 2, Length(nomVar) - pos_P + 2);
      try
        StrToInt(nroPoste);
        ok:= true;
      except
        on EConvertError do
        begin
          delete(nomVar, 1, pos_P + 2);
        end;
      end;
    end
  until ok or (pos_P = 0);
  res:= TStringList.Create;
  if ok then
  begin
    res.Capacity:= datosSim.nPostes;
    for iPoste:= 1 to datosSim.nPostes do
    begin
      datosSim.JoinNomVar(nomActor, nombreSinNroPoste + IntToStr(iPoste), unidades, cadena);
      res.Add(cadena);
    end;
  end
  else
    res.Add(cadena);
  result:= res;
end;

procedure TAcumuladorVars.LBDisponiblesClick(Sender: TObject);
begin
  BAddRemove.Caption:= '->';
end;

procedure TAcumuladorVars.LBDisponiblesDblClick(Sender: TObject);
begin
  BAddRemoveClick(self);
end;

procedure TAcumuladorVars.LBSeleccionadasClick(Sender: TObject);
begin
  BAddRemove.Caption:= '<-'
end;

procedure TAcumuladorVars.LBSeleccionadasDblClick(Sender: TObject);
begin
  BAddRemoveClick(self);
end;

end.
