unit ulistadopaginado_sql;
{$mode delphi}
interface
uses
  Classes, SysUtils,
  uDataSetGenerico,
  ugraficador,
  Math,
  Graphics,
  urosx,
  u_sql_buscar,
  uvisordetabla;

type

  TColListadoPaginado_SQL = class
    caption: string;
    ordenable: boolean;
    buscable: boolean;
    campo: string;
    maxNChars: integer;
    flg_IsNum: boolean;

    constructor Create(caption, campo, campo_sql_select_: string; ordenable,
      buscable: boolean; maxNChars: integer; flg_isNum: boolean=false);
    function BuscarStr: string;

  private
    xcampo_select: string;
    function get_campo_select: string;
    procedure set_campo_select( s: string );
  public
    property campo_select: string read get_campo_select write set_campo_select;

  end;

  TColumnasListadoPaginado_SQL = class( TList )
    function Col( i: integer ): TColListadoPaginado_SQL;
    function AddCol(  caption, campo, campo_sql_select: string;
      ordenable, buscable: boolean;
      maxNChars: integer ): TColListadoPaginado_SQL;
    function CamposSelectStr: string;
  end;

  TBotonRec = class
    iid: integer;
    hint: string;
    constructor Create( iid: integer; hint: string );
  end;

  { TListadoScada }

  { TListadoPaginado_SQL }

  TListadoPaginado_SQL = class(TTabla)

  public
    columnas: TColumnasListadoPaginado_SQL;
    botones: TList;
    flg_populate: boolean;
    flg_ocultarInactivos: boolean;
    dbcon: TDBrosxCon;
    BuscarStr: string;
    camposBuscar: TStringList;
    FromStr, WhereStr, OrderByStr, ActivoStr: string;

    jCol_ordenada: integer;
    flg_Creciente: boolean;
    kPag: integer;
    nrpp: integer;
    nPags: integer;

    constructor Create(
      AOwner: TComponent; Name: string; dbconx: TDBrosxCon;
      nrpp: integer;
      From_str: string;
      Campo_SortBy: string;
      ActivoStr: string // Condición de Activo. Ej: 'activo > 0'. Si está vacío no juega.
      ); reintroduce;

    procedure OrdenarPor_OnClick(nidRec: string; kFila: integer); override;
    procedure OrdenadoAZ_OnClick(nidRec: string; kFila: integer); override;
    procedure OrdenadoZA_OnClick(nidRec: string; kFila: integer); override;

    procedure Paint; override;
    procedure Populate; virtual;

    procedure AgregarBoton( iid_Boton: integer; sHint: string );
    function AgregarColumnaTxt(  caption, campo, campo_sql_select: string;
      ordenable, buscable: boolean;
      maxNChars: integer ): TColListadoPaginado_SQL;
    function AgregarColumnaNum(  caption, campo, campo_sql_select: string;
      ordenable, buscable: boolean;
      maxNChars: integer ): TColListadoPaginado_SQL;
  private
    procedure CambiarOrderBy(sCol: string; Creciente: boolean);
    procedure writeBotonera(snid: string; kfil, jcol: integer);
    procedure WriteSortBtn(jCol: integer);
  end;


function sLEFT(s: string; maxLength: integer): string;

implementation

function sLEFT(s: string; maxLength: integer): string;
var
  res: string;
begin
  res := trim(s);
  if length(res) > maxLength then
    res := copy(s, 1, maxLength - 3) + '...';
  Result := res;
end;


constructor TBotonRec.Create( iid: integer; hint: string );
begin
  self.iid:= iid;
  self.hint:= hint;
end;


constructor TColListadoPaginado_SQL.Create(
    caption, campo, campo_sql_select_: string;
    ordenable, buscable: boolean;
    maxNChars: integer;
    flg_isNum: boolean = false);
begin
  self.caption:= caption;
  self.ordenable:= ordenable;
  self.buscable:= buscable;
  self.campo:= campo;
  campo_select:= campo_sql_select_;
  self.maxNChars:= maxNChars;
  self.flg_isNum:= flg_isNum;
end;

function TColListadoPaginado_SQL.BuscarStr: string;
begin
  if flg_isNum then
    result:= 'to_char( '+campo_select+', ''999999'')'
  else
    result:= campo_select;
end;


function TColListadoPaginado_SQL.get_campo_select: string;
begin
  if xcampo_select = '' then
    result:= campo
  else
    result:= xcampo_select;
end;

procedure TColListadoPaginado_SQL.set_campo_select( s: string );
begin
  xcampo_select:= s;
end;

function TColumnasListadoPaginado_SQL.Col( i: integer ): TColListadoPaginado_SQL;
begin
  result:= TColListadoPaginado_SQL( items[i] );
end;


function TColumnasListadoPaginado_SQL.AddCol(
    caption, campo, campo_sql_select: string;
    ordenable, buscable: boolean;
    maxNChars: integer ): TColListadoPaginado_SQL;
var
  aColDef: TColListadoPaginado_SQL;
begin
  aColDef:= TColListadoPaginado_SQL.Create(
            caption, campo, campo_sql_select,
            ordenable, buscable, maxNChars );
  result:= items[add( aColDef )];

end;


function TColumnasListadoPaginado_SQL.CamposSelectStr: string;
var
  res: string;
  aCol: TColListadoPaginado_SQL;
  k: integer;
begin
  res:= '';
  for k:= 0 to count - 1 do
  begin
    aCol:= col( k );
    if res <> '' then res:= res+', ';
    if ( aCol.campo_select <> aCol.campo ) then
       res:= res+ aCol.Campo_select+' AS '+aCol.Campo
    else
      res:= res+ aCol.campo;
  end;
  result:= res;
end;

{ TListadoPaginado_SQL }

procedure TListadoPaginado_SQL.CambiarOrderBy(sCol: string; Creciente: boolean);
begin
  jCol_ordenada := StrToInt(sCol);
  flg_Creciente := Creciente;
  OrderByStr := Columnas.col( jCol_ordenada ).campo_select;

  if not flg_Creciente then
    OrderByStr := OrderByStr + ' DESC';

  flg_populate := True;
  invalidate;
end;

procedure TListadoPaginado_SQL.WriteSortBtn(jCol: integer);
begin
  if jCol = jCol_ordenada then
    if flg_Creciente then
      wrBitBtn('btns_' + IntToStr(jCol) + '_' + IntToStr(iid_OrdenadoAZ),
        0, jCol, iid_OrdenadoAZ, 'Invertir orden.')
    else
      wrBitBtn('btns_' + IntToStr(jCol) + '_' + IntToStr(iid_OrdenadoZA), 0,
        jCol, iid_OrdenadoZA, 'Invertir orden.')
  else
    wrBitBtn('btns_' + IntToStr(jCol) + '_' + IntToStr(iid_OrdenadoZA), 0,
      jCol, iid_OrdenarPor, 'Ordenar por.');
end;

constructor TListadoPaginado_SQL.Create(AOwner: TComponent; Name: string;
  dbconx: TDBrosxCon; nrpp: integer;
  From_str: string; Campo_SortBy: string; ActivoStr: string);

var
  aCol: TColListadoPaginado_SQL;
  k: integer;

begin
  inherited Create(AOwner, Name, 4, 1, 0);
  columnas:= TColumnasListadoPaginado_SQL.Create;
  botones:= TList.Create;
  CamposBuscar := TStringList.Create;

  flg_populate := True;
  dbcon := dbconx;
  jCol_ordenada := 0;
  BuscarStr := '';
  WhereStr := '';
  self.FromStr:= From_str;
  self.nrpp:= nrpp;
  Self.ActivoStr:= ActivoStr;
  kpag:= 0;
  npags:= -1;

  self.FromStr:= FromStr;
  k:= pos( ' DESC', Campo_SortBy );
  if k > 0 then
  begin
   OrderByStr:= copy( Campo_SortBy, 1, k-1 );
   flg_Creciente:= false;
  end
  else
  begin
   OrderByStr := Campo_SortBy;
   flg_Creciente := True;
  end;
end;

procedure TListadoPaginado_SQL.OrdenarPor_OnClick(nidRec: string; kFila: integer
  );
begin
  if kFila = 0 then
    cambiarOrderBy(nidRec, flg_Creciente);
end;



procedure TListadoPaginado_SQL.OrdenadoAZ_OnClick(nidRec: string; kFila: integer
  );
begin
  if kFila = 0 then
    cambiarOrderBy(nidRec, false);
end;

procedure TListadoPaginado_SQL.OrdenadoZA_OnClick(nidRec: string; kFila: integer
  );
begin
  if kFila = 0 then
    cambiarOrderBy(nidRec, true);
end;

procedure TListadoPaginado_SQL.Paint;
begin
  if flg_populate then
    Populate;
  inherited Paint;
end;



procedure TListadoPaginado_SQL.writeBotonera( snid: string; kfil, jcol: integer );
var
  aRec: TBotonRec;
  k: integer;
  iids: array of integer;
  hints: array of string;
begin
  setlength( iids, botones.count );
  setlength( hints, botones.count );

  for k:= 0 to botones.Count-1 do
  begin
   aRec:= botones.items[k];
   iids[k]:= aRec.iid;
   hints[k]:= aRec.hint;
  end;
  wrBotonera( snid, kfil, jcol, iids, hints );
end;

procedure TListadoPaginado_SQL.Populate;
var
  k: integer;
  snid: string;
  ds: TResultadoQuery;
  r: TDataRecord;
  condicion_activo: boolean;
  sqlstr: string;
  sql_from_where: string;
  total_rows: integer;
  kCol: integer;
  aCol: TColListadoPaginado_SQL;
  sVal: string;
  jFilaEncab: integer;

begin
  Visible:= false;

  BuscarStr := trim(BuscarStr);
  if BuscarStr <> '' then
    WhereStr := construirFiltroBusquedaTexto(BuscarStr, camposBuscar)
  else
    WhereStr := '';

  if ActivoStr <> '' then
    if flg_ocultarInactivos then
      if WhereStr <> '' then
        WhereStr := WhereStr + ' AND '+ ActivoStr
      else
        WhereStr := ActivoStr;

  flg_populate := False;


  sql_from_where:= ' FROM '+ FromStr;
  if WhereStr <> '' then
    sql_from_where := sql_from_where + ' WHERE ' + WhereStr + ' ';

  if ( nrpp > 0 ) then
  begin
    sqlstr:='SELECT count(*) '+sql_from_where;
    total_rows := StrToInt( dbcon.sql_func( sqlstr ) );
    nPags:= Ceil( total_rows / nrpp );
    if kPag <= 0 then
     kPag:= 0
    else
      if kPag >= nPags then
        kPag:= nPags-1;
  end;


  sqlstr := 'SELECT '+ columnas.CamposSelectStr;
  if ActivoStr <> '' then
    sqlstr := sqlstr+', '+ActivoStr+' AS hxy_activo_yxh';
  sqlstr := sqlstr+' '+sql_from_where+ ' ORDER BY ' + OrderByStr;

  if ( nrpp > 0 ) then
    sqlstr:= sqlstr + ' LIMIT '+IntToStr( nrpp )+' OFFSET '+IntToStr( kPag * nrpp );

  ds := dbcon.Query(sqlstr);
  if ds = nil then
    raise Exception.Create(dbcon.ultimoError);

  ClearRedim(ds.nrows + 1 , Columnas.Count +1);


  jFilaEncab:= 0;
  // fila encabezado
  for kCol:= 0 to Columnas.Count -1 do
  begin
    aCol:= Columnas.col( kCol );
    wrTexto('', jFilaEncab, kCol, aCol.caption);
    if aCol.ordenable then WriteSortBtn( kCol );
    AlinearCelda(jFilaEncab, kCol, CAH_Izquierda, CAV_Centro);
  end;
  Self.SetBgColorFila(jFilaEncab, clNavy);
  Self.SetFontColorFila(jFilaEncab, clYellow);
  Self.SetBgColorCelda(jFilaEncab, 0, clNavy);
  Self.SetBgColorCelda(jFilaEncab, 1, clNavy);



  k := jFilaEncab + 1;
  r := ds.First;
  while not ds.EOF do
  begin
    snid := r.GetByIdAsString(0);

    if ActivoStr <> '' then
       condicion_activo := r.GetByNameAsBoolean('hxy_activo_yxh')
    else
       condicion_activo:= true;


    for kCol:= 0 to columnas.count -1 do
    begin
      aCol:= columnas.col( kCol );
      sVal:= r.GetByNameAsString( aCol.campo );
      if ( aCol.maxNChars > 0 ) then
       sVal:= sLEFT( sVal, aCol.maxNChars);
      wrTexto('', k, kCol, sVal);
      AlinearCelda(k, kCol, CAH_Izquierda, CAV_Centro);
    end;

    // ahora la botonera en la última columna

    writeBotonera( snid, k, columnas.count );

    if (k mod 2) = 0 then
      if condicion_activo then
       SetBgColorFila(k, clFondoFilaPar_Activa)
      else
        SetBgColorFila(k, clFondoFilaPar_Inactiva)
    else


    if condicion_activo then
      SetBgColorFila(k, clFondoFilaImpar_Activa)
    else
      SetBgColorFila(k, clFondoFilaImpar_Inactiva);

    Inc(k);
    r := ds.Next;
  end;


  reposicionar;
  Visible:= true;
end;


procedure TListadoPaginado_SQL.AgregarBoton( iid_Boton: integer; sHint: string );
var
  aBotonRec : TBotonRec;
begin
  aBotonRec:= TBotonRec.Create( iid_Boton, sHint );
  botones.Add( aBotonRec );
end;

function TListadoPaginado_SQL.AgregarColumnaTxt(  caption, campo, campo_sql_select: string;
  ordenable, buscable: boolean;
  maxNChars: integer ): TColListadoPaginado_SQL;
var
  aCol: TColListadoPaginado_SQL;
begin
  aCol:= TColListadoPaginado_SQL.Create( caption, campo, campo_sql_select, ordenable, buscable, maxNChars, false);
  if aCol.buscable then
      CamposBuscar.Add( aCol.buscarStr );
  columnas.add( aCol );
end;

function TListadoPaginado_SQL.AgregarColumnaNum(  caption, campo, campo_sql_select: string;
  ordenable, buscable: boolean;
  maxNChars: integer ): TColListadoPaginado_SQL;
var
  aCol: TColListadoPaginado_SQL;
begin
  aCol:= TColListadoPaginado_SQL.Create( caption, campo, campo_sql_select, ordenable, buscable, maxNChars, true);
  if aCol.buscable then
      CamposBuscar.Add( aCol.buscarStr );
  columnas.add( aCol );
end;

end.
