unit uoddface_consultar;

{$mode delphi}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  ComCtrls, urosx, uDataSetGenerico, uauxiliares,
  unotificar, uconstantessimsee,
  xmatdefs, utipos_ga,
  uExcelFile,
  uoddface,
  uoddface_pam,
  uoddface_pig,
  uoddface_redcegh,
    {$IFDEF CALIBRAPARQUE}
  uoddface_calibraparque,
     {$ENDIF}
  uoddface_OptimA;

type

  { TConsultar }

  TConsultar = class(TForm)
    btConsultaToExcel: TButton;
    btBajarIndividuo: TButton;
    btConsultaToXLT: TButton;
    btAnalisisADN: TButton;
    cbAglutinarRedundantes: TCheckBox;
    enid_individuo: TEdit;
    eN: TEdit;
    eOFFSET: TEdit;
    eORDER_BY: TEdit;
    eFrom: TEdit;
    eSelect: TEdit;
    eWHERE: TEdit;
    GroupBox1: TGroupBox;
    Label1: TLabel;
    Label2: TLabel;
    Label21: TLabel;
    Label22: TLabel;
    Label23: TLabel;
    Label24: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    Memo1: TMemo;
    memo_ADN: TMemo;
    pg: TProgressBar;
    constructor Create(TheOwner: TComponent; dbconx: TDBrosxCon);
    procedure btAnalisisADNClick(Sender: TObject);
    procedure btConsultaToExcelClick(Sender: TObject);
    procedure btBajarIndividuoClick(Sender: TObject);
    procedure btConsultaToXLTClick(Sender: TObject);
    procedure cbAglutinarRedundantesChange(Sender: TObject);
  private
    { private declarations }

  public
    { public declarations }
    nidProblema: integer;
    dbcon: TDBrosxCon;
  end;


implementation

{$R *.lfm}

{ TConsultar }

type
  PRecResumen = ^TRecResumen;

  TRecResumen = record
    nid1: integer; // del primer representante
    f_Objetivo: NReal;
    cnt: integer;
    ADN: TCadenaADN;
    der, izq: PRecResumen;
  end;


function buscar_rec_resumen(const Lst: PRecResumen; const adn: TCadenaADN;
  var pos: integer): PRecResumen;
var
  iguales: boolean;
  buscando: boolean;
  p: PRecResumen;
begin
  p := lst;
  buscando := True;
  while buscando do
  begin
    pos := comparar_adn(p^.ADN, adn);
    case pos of
      -1: if p^.izq <> nil then
          p := p^.izq
        else
          buscando := False;
      0: buscando := False;
      1: if p^.der <> nil then
          p := p^.der
        else
          buscando := False;
    end; // case
  end;
  Result := p;
end;


function get_aprom(dbcon: TDBrosxCon; var tipoProblema: integer;
  nidProblema: integer; const carpeta_tmp: string): TProblema;
var
  aprom: TProblema;
  idEjecutor: integer;

begin
  tipoProblema := StrToInt(dbcon.sql_func(
    'SELECT tipo FROM ofe_problemas WHERE nid = ' + IntToStr(nidProblema)));

  // Calculamos un idEjecutor que sea diferente para cada tipo de problema
  // para que los archivos queden separados.
  idEjecutor := 10000 + tipoProblema;
  case tipoProblema of
    1: aprom := TPIG_Problema.CreateFromDB(dbcon, nidProblema, idEjecutor, carpeta_tmp);
    2: aprom := TPAM_Problema.CreateFromDB(dbcon, nidProblema, idEjecutor, carpeta_tmp);
    //3: PDETSimSEE Programación determinística oddface_det
    4: //  RedCEGHSimSEE Reductor de espacio de estado
      aprom := TRedCEGH_Problema.CreateFromDB(dbcon, nidProblema,
        idEjecutor, carpeta_tmp);
    5: // OptimA Optimizador de agendas de GNL.
      aprom := TOptimA_Problema.CreateFromDB(dbcon, nidProblema,
        idEjecutor, carpeta_tmp);
     {$IFDEF CALIBRAPARQUE}
    6: // Calibrador de parques eólicos
      aprom := TCalibraParque_Problema.CreateFromDB(dbcon, nidProblema,
        idEjecutor, carpeta_tmp);
     {$ENDIF}
    else
      aprom := nil;
  end;
  Result := aprom;
end;



procedure TConsultar.btConsultaToExcelClick(Sender: TObject);
var
  sql: string;
  r: TDataRecord;
  ds: TResultadoQuery;
  kRow, jCol: integer;
  ef: TExcelFile;
  horaDelServidor: string;
  tipoProblema: integer;

  aprom: TProblema;
  aindi: TIndividuo;

  carpeta: string;
  nidi: integer;

  RaizResumen: PRecResumen;
  aRecResumen: PRecResumen;
  res_decodificar: boolean;
  lst_Resumen: TList;

  f_Objetivo_: NReal;
  cnt_: integer;
  res_pos: integer;
  ADN_hexStr: string;

begin

  RaizResumen := nil;

  pg.Position := 0;


  {$IFDEF LINUX}
  carpeta := GetEnvironmentVariable('HOME') + DirectorySeparator +
    'SimSEE' + DirectorySeparator + 'OddFace';
  {$ELSE}
  carpeta := 'C:\SimSEE\Oddface';
  {$ENDIF}


  if not DirectoryExists(carpeta) then
    CreateDir(carpeta);

  carpeta := carpeta + '\problema_' + IntToStr(nidProblema);
  if not DirectoryExists(carpeta) then
    CreateDir(carpeta);

  horaDelServidor := dbcon.sql_func('SELECT now() FROM ofe_problemas ');

  uauxiliares.setSeparadoresGlobales;

  aprom := get_aprom(dbcon, tipoProblema, nidProblema, carpeta);
  if aprom = nil then
  begin
    unotificar.notificar('No hay soporte de consulta para el tipo de problema: ' +
      IntToStr(tipoProblema) + '. (falta implementar)');
    exit;
  end;

  unotificar.esperando_inicio('Aguarde mientras se descargan los datos ...');
  sql := 'SELECT nid, adn, f_Objetivo, cnt_evaluaciones';
  if trim(eSelect.Text) <> '' then
    sql := sql + ', ' + eSelect.Text;
  sql := sql + ' FROM ' + eFrom.Text + ' WHERE ' + eWHERE.Text +
    ' ORDER BY ' + eORDER_BY.Text + ' LIMIT ' + eOFFSET.Text + ', ' + eN.Text;
  ds := dbcon.sql_query(sql);


  unotificar.esperando_fin;
  if ds <> nil then
  begin
    //  unotificar.esperando_inicio('... Creando libro Excel ...');
    pg.Min := 0;
    pg.Max := ds.nrows - 1;
    pg.Step := 1;
    pg.Position := 0;

    ef := TExcelFile.Create('x', 'consulta_vates');
    ef.writeln(DateTimeToStr(now) + ', sql: ' + sql);


    for jCol := 0 to 3 do
      ef.Write(ds.FieldName(jCol));

    if not cbAglutinarRedundantes.Checked then
      for jCol := 4 to ds.nfields - 1 do
        ef.Write(ds.FieldName(jCol));

    if aprom <> nil then
    begin
      for jCol := 0 to high(aprom.DescriptoresE) do
        ef.Write(aprom.DescriptoresE[jcol].nombre + '_' + IntToStr(
          aprom.DescriptoresE[jcol].nbits));
      for jCol := 0 to high(aprom.DescriptoresR) do
        ef.Write(aprom.DescriptoresR[jcol].nombre + '_' + IntToStr(
          aprom.DescriptoresR[jcol].nbits));
    end;

    ef.writeln;

    if cbAglutinarRedundantes.Checked then
    begin
      RaizResumen := nil;
      lst_Resumen := TList.Create;
    end;

    for kRow := 0 to ds.nrows - 1 do
    begin
      r := ds.go(kRow);

      nidi := r.GetByNameAsInt('nid');
      cnt_ := r.GetByNameAsInt('cnt_evaluaciones');
      f_Objetivo_ := r.GetByNameAsFloat('f_Objetivo');

      //      aindi:= aprom.LeerIndividuo( nidi );
      aindi := TIndividuo.CreateFromADN_HexStr(dbcon, aprom,
        r.GetByNameAsString('adn'));
      res_decodificar := aprom.decodificar_adn(aindi);

      if cbAglutinarRedundantes.Checked then
      begin
        aprom.LimpiarResto(aindi);
        if not res_decodificar then
          aprom.codificar_adn(aindi);
        // lo vuelvo a codificar para tener el REPRESENTANTE PRINCIPAL

        if RaizResumen = nil then
        begin
          new(RaizResumen);
          RaizResumen.nid1 := nidi;
          RaizResumen.ADN := copy(aindi.ADN, 0, length(aindi.ADN));
          RaizResumen.cnt := cnt_;
          RaizResumen.f_Objetivo := f_Objetivo_;
          RaizResumen.izq := nil;
          RaizResumen.der := nil;
          lst_Resumen.add(RaizResumen);
        end
        else
        begin
          aRecResumen := buscar_rec_resumen(RaizResumen, aindi.ADN, res_pos);
          case res_pos of
            -1:
            begin
              new(aRecResumen^.izq);
              aRecResumen := aRecResumen^.izq;
              aRecResumen.nid1 := nidi;
              aRecResumen.ADN := copy(aindi.ADN, 0, length(aindi.ADN));
              aRecResumen.cnt := cnt_;
              aRecResumen.f_Objetivo := f_Objetivo_;
              aRecResumen.izq := nil;
              aRecResumen.der := nil;
              lst_Resumen.add(aRecResumen);
            end;
            0:
            begin
              aRecResumen^.f_Objetivo :=
                (aRecResumen^.f_Objetivo * aRecResumen^.cnt + f_Objetivo_ * cnt_) /
                (aRecResumen^.cnt + cnt_);
              aRecResumen^.cnt := aRecResumen^.cnt + cnt_;
            end;
            1:
            begin
              new(aRecResumen^.der);
              aRecResumen := aRecResumen^.der;
              aRecResumen.nid1 := nidi;
              aRecResumen.ADN := copy(aindi.ADN, 0, length(aindi.ADN));
              aRecResumen.cnt := cnt_;
              aRecResumen.f_Objetivo := f_Objetivo_;
              aRecResumen.izq := nil;
              aRecResumen.der := nil;
              lst_Resumen.add(aRecResumen);
            end;
          end;
        end;
      end
      else
      begin

        ef.Write(r.GetByIdAsString(0)); // nid
        ef.Write('''' + r.GetByIdAsString(1));
        ef.Write(r.GetByIdAsString(2));
        ef.Write(r.GetByIdAsString(3));

        for jCol := 4 to ds.nfields - 1 do
          ef.Write(r.GetByIdAsString(jCol));
        if aprom <> nil then
        begin
          for jCol := 0 to high(aprom.DescriptoresE) do
            ef.Write(aindi.XE.e(jcol + 1));
          for jCol := 0 to high(aprom.DescriptoresR) do
            ef.Write(aindi.XR.e(jcol + 1));
        end;
        ef.writeln;
      end;
      aindi.Free;
      pg.StepIt;
    end;

    // terminé el for sobre la db, si aglutiné, recorro la lista para imprimir.
    if cbAglutinarRedundantes.Checked then
    begin

      pg.Min := 0;
      pg.Max := lst_Resumen.Count - 1;
      pg.Step := 1;
      pg.Position := 0;


      for kRow := 0 to lst_Resumen.Count - 1 do
      begin
        aRecResumen := lst_Resumen.items[kRow];
        if dbcon.tipoServidor = CTS_MySQL then
          ADN_hexStr := BuffToHexStr_(aRecResumen^.ADN[0], aprom.nbytes_ADN)
        else
          ADN_hexStr := PG_BuffToHexStr(aRecResumen^.ADN[0], aprom.nbytes_ADN);

        aindi := TIndividuo.CreateFromADN_HexStr(dbcon, aprom, ADN_hexStr);
        res_decodificar := aprom.decodificar_adn(aindi);
        if not res_decodificar then
          raise Exception.Create('OJO; decodifcando resumen necesita ajuste!!!');
        ef.Write(aRecResumen.nid1);
        ef.Write('''' + ADN_hexStr);
        ef.Write(aRecResumen.f_Objetivo);
        ef.Write(aRecResumen.cnt);
        if aprom <> nil then
        begin
          for jCol := 0 to high(aprom.DescriptoresE) do
            ef.Write(aindi.XE.e(jcol + 1));
          for jCol := 0 to high(aprom.DescriptoresR) do
            ef.Write(aindi.XR.e(jcol + 1));
        end;
        ef.writeln;
        aindi.Free;
        // voy liberando la lista.
        setlength(aRecResumen.ADN, 0);
        dispose(aRecResumen);
        pg.StepIt;
      end;
      lst_Resumen.Free;
    end;


    if aprom <> nil then
      aprom.Free;

    unotificar.esperando_fin;
    ef.VisibleOn;

    ef.Free;
    ds.Free;

  end;
  uauxiliares.setSeparadoresLocales;

end;


constructor TConsultar.Create(TheOwner: TComponent; dbconx: TDBrosxCon);
begin
  inherited Create(TheOwner);
  dbcon := dbconx;
end;

procedure TConsultar.btAnalisisADNClick(Sender: TObject);
var
  sql: string;
  r: TDataRecord;
  ds: TResultadoQuery;
  kRow, jCol: integer;
  ef: TExcelFile;
  horaDelServidor: string;
  tipoProblema: integer;

  aprom: TProblema;
  aindi: TIndividuo;

  carpeta: string;
  nidi: integer;
  s: string;
begin
  uauxiliares.setSeparadoresGlobales;

  carpeta := 'c:\simsee\oddface';
  if not DirectoryExists(carpeta) then
    CreateDir(carpeta);

  carpeta := carpeta + '\problema_' + IntToStr(nidProblema);
  if not DirectoryExists(carpeta) then
    CreateDir(carpeta);

  horaDelServidor := dbcon.sql_func('SELECT now() FROM ofe_problemas');
  tipoProblema := StrToInt(dbcon.sql_func(
    'SELECT tipo FROM ofe_problemas WHERE nid = ' + IntToStr(nidProblema)));


  case tipoProblema of
    1: aprom := TPIG_Problema.CreateFromDB(dbcon, nidProblema, 1, carpeta);
    2: aprom := TPAM_Problema.CreateFromDB(dbcon, nidProblema, 2, carpeta);
    else
      aprom := nil;
  end;
  s := 'nbits_Justo: ' + IntToStr(aprom.nbits_ADN_Justo) + ', nbits_Resto: ' +
    IntToStr(aprom.nbits_ADN_Resto);
  memo_ADN.Lines.Add(s);

  unotificar.esperando_inicio('Aguarde mientras se descargan los datos ...');


  (*
  if (enid_individuo.Text <> '') and (enid_individuo.Text <> '0') then
    sql := 'SELECT nid, adn FROM ' + eFrom.Text + ' WHERE nid = ' +
      enid_individuo.Text '
  else
    sql := 'SELECT nid, adn FROM ' + eFrom.Text + ' WHERE 1 ';
  *)

  if (enid_individuo.Text <> '') and (enid_individuo.Text <> '0') then
    sql := 'SELECT * FROM ' + eFrom.Text + ' WHERE nid = ' + enid_individuo.Text
  else
    sql := 'SELECT * FROM ' + eFrom.Text + ' WHERE 1 ';


  ds := dbcon.sql_query(sql);
  unotificar.esperando_fin;

  if ds <> nil then
  begin
    r := ds.First;

    nidi := r.GetByNameAsInt('nid');
    aindi := TIndividuo.CreateFromRec(dbcon, aprom, r);

    //    aindi := TIndividuo.CreateFromADN_HexStr(aprom, r.GetByNameAsString('adn'));

    s := aindi.ADN_AsBinaryStr;
    memo_ADN.Lines.add(s);
    aprom.decodificar_adn(aindi);

    s := '';
    if aprom <> nil then
    begin
      for jCol := 0 to high(aprom.DescriptoresE) do
        s := s + ', ' + IntToStr(aindi.XE.e(jcol + 1));
      for jCol := 0 to high(aprom.DescriptoresR) do
        s := s + ', ' + FloatToStr(aindi.XR.e(jcol + 1));
    end;

    memo_ADN.Lines.Add(s);

    aprom.codificar_adn(aindi);
    s := aindi.ADN_AsBinaryStr;
    memo_ADN.Lines.add(s);

    aprom.LimpiarResto(aindi);
    s := aindi.ADN_AsBinaryStr;
    memo_ADN.Lines.add(s);



    s := 'nid: ' + IntToStr(aindi.nid);
    memo_ADN.Lines.add(s);
    s := 'cnt_evaluaciones: ' + IntToStr(aindi.cnt_evaluaciones);
    memo_ADN.Lines.add(s);
    s := 'f_VE: ' + FloatToStr(aindi.f_VE);
    memo_ADN.Lines.add(s);
    s := 'f_VaR: ' + FloatToStr(aindi.f_VaR);
    memo_ADN.Lines.add(s);
    s := 'f_CVaR: ' + FloatToStr(aindi.f_CVaR);
    memo_ADN.Lines.add(s);
    s := 'f_Objetivo: ' + FloatToStr(aindi.f_Objetivo);
    memo_ADN.Lines.add(s);
    s := 'f_Histo: ' + aindi.f_histo.serialize;
    memo_ADN.Lines.add(s);


    aindi.Free;


    if aprom <> nil then
      aprom.Free;

    ds.Free;

  end;
  uauxiliares.setSeparadoresLocales;

end;

procedure TConsultar.btBajarIndividuoClick(Sender: TObject);
var
  apl: string;
  params: array of string;

begin
  apl := dbcon.sql_func(' SELECT ' + '  apl ' + ' FROM ' +
    '  ofe_tipos_problema ' +
    '  LEFT JOIN ofe_problemas ON ofe_problemas.tipo = ofe_tipos_problema.nid ' +
    ' WHERE ofe_problemas.nid = ' + IntToStr(nidProblema) + ' LIMIT 1 ');


{$IFDEF LINUX}
  apl := getDir_bin + apl;
{$ELSE}
  apl := getDir_bin + apl + '.exe';
{$ENDIF}



  if fileexists(apl) then
  begin
    setlength(params, 4);
    params[0] := '12';
    params[1] := IntToStr(nidProblema);
    params[2] := '-1'; // el idNodo = -1 es para que no ejecute solo baje.
    params[3] := enid_individuo.Text;

    if not RunChildAndWAIT(apl, params) then
      raise Exception.Create('no puede correr la cmdopt');
  end
  else
    unotificar.notificar('No se encuentra la aplicación: ' + apl, True);

end;

procedure TConsultar.btConsultaToXLTClick(Sender: TObject);
var
  sql: string;
  r: TDataRecord;
  ds: TResultadoQuery;
  kRow, jCol: integer;
  horaDelServidor: string;
  tipoProblema: integer;

  aprom: TProblema;
  aindi: TIndividuo;

  carpeta: string;
  nidi: integer;
  archi_xlt: string;
  fsal: textfile;
  where_str: string;

begin
  uauxiliares.setSeparadoresGlobales;

  {$IFDEF WINDOWS}
  carpeta := 'c:\simsee\oddface';
  {$ELSE}
  carpeta := GetEnvironmentVariable('HOME') + '/SimSEE/oddface';
  {$ENDIF}
  if not DirectoryExists(carpeta) then
    CreateDir(carpeta);

  carpeta := carpeta + DirectorySeparator + 'problema_' + IntToStr(nidProblema);
  if not DirectoryExists(carpeta) then
    CreateDir(carpeta);


  horaDelServidor := dbcon.sql_func('SELECT now() FROM ofe_problemas');

  while pos('-', horaDelServidor) > 0 do
    Delete(horaDelServidor, pos('-', horaDelServidor), 1);
  while pos(':', horaDelServidor) > 0 do
    Delete(horaDelServidor, pos(':', horaDelServidor), 1);
  while pos(' ', horaDelServidor) > 0 do
    Delete(horaDelServidor, pos(' ', horaDelServidor), 1);
  archi_xlt := carpeta + DirectorySeparator + 'consulta_' + horaDelServidor + '.xlt';

  aprom := get_aprom(dbcon, tipoProblema, nidProblema, carpeta);
  if aprom = nil then
  begin
    unotificar.notificar('No hay soporte de consulta para el tipo de problema: ' +
      IntToStr(tipoProblema) + '. (falta implementar)');
    exit;
  end;

  unotificar.esperando_inicio('Aguarde mientras se descargan los datos ...');
  sql := 'SELECT nid, adn, f_Objetivo, cnt_evaluaciones';
  if trim(eSelect.Text) <> '' then
    sql := sql + ', ' + eSelect.Text;
  sql := sql + ' FROM ' + eFrom.Text;
  where_str := trim(eWHERE.Text);
  if (where_str <> '') and (where_str <> '1') then
    sql := sql + ' WHERE ' + where_str;
  sql := sql + ' ORDER BY ' + eORDER_BY.Text + ' LIMIT ' +
    eN.Text + ' OFFSET ' + eOFFSET.Text;
  ds := dbcon.sql_query(sql);
  unotificar.esperando_fin;

  if ds <> nil then
  begin
    //    unotificar.esperando_inicio('... Creando archivo: '+archi_xlt );

    assignfile(fsal, archi_xlt);
    rewrite(fsal);

    writeln(fsal, DateTimeToStr(now) + ', sql: ' + sql);


    for jCol := 0 to ds.nfields - 1 do
      Write(fsal, #9, ds.FieldName(jCol));

    if aprom <> nil then
    begin
      for jCol := 0 to high(aprom.DescriptoresE) do
        Write(fsal, #9, aprom.DescriptoresE[jcol].nombre + '_' +
          IntToStr(aprom.DescriptoresE[jcol].nbits));
      for jCol := 0 to high(aprom.DescriptoresR) do
        Write(fsal, #9, aprom.DescriptoresR[jcol].nombre + '_' +
          IntToStr(aprom.DescriptoresR[jcol].nbits));
    end;

    writeln(fsal);

    pg.Min := 0;
    pg.Max := ds.nrows - 1;
    pg.Step := 1;

    for kRow := 0 to ds.nrows - 1 do
    begin
      r := ds.Go(kRow);

      application.ProcessMessages;
      nidi := r.GetByNameAsInt('nid');
      //      aindi:= aprom.LeerIndividuo( nidi );
      aindi := TIndividuo.CreateFromADN_HexStr(dbcon, aprom, r.GetByNameAsString('adn'));
      aprom.decodificar_adn(aindi);

      for jCol := 0 to ds.nfields - 1 do
        Write(fsal, #9, r.GetByIdAsString(jCol));

      if aprom <> nil then
      begin
        for jCol := 0 to high(aprom.DescriptoresE) do
          Write(fsal, #9, aindi.XE.e(jcol + 1));
        for jCol := 0 to high(aprom.DescriptoresR) do
          Write(fsal, #9, aindi.XR.e(jcol + 1));
      end;

      writeln(fsal);

      aindi.Free;
      pg.StepIt;

    end;

    if aprom <> nil then
      aprom.Free;

    //    unotificar.esperando_fin;
    unotificar.notificar('Se creó el archivo: ' + archi_xlt);
    closefile(fsal);

    ds.Free;
  end;
  uauxiliares.setSeparadoresLocales;
end;

procedure TConsultar.cbAglutinarRedundantesChange(Sender: TObject);
begin
  eSelect.Enabled := not cbAglutinarRedundantes.Checked;
end;



end.
