unit uhtml;

{$mode delphi}

interface


{La idea de esta unidad es hacer más ADME user friendly los objetos HTML
 de Pascal}

uses
  Classes, SysUtils, SAX_HTML, DOM_HTML, DOM,ujson, uparseutils, uauxiliares,uRobotHttpPost;

type


  TDAOFString = array of string;
  TDAOfDAofString = array of TDAOFString;

  { TDocumentoHTML }

  TDocumentoHTML = class
    documento: THTMLDocument;
    cuerpo: THTMLElement;
    constructor createFromString(str:string);
    procedure Free;
    // busca el tag el id y devuelve el value
    function getValueFromTagNameAndElementId(tagName, id: string): string;
    // trae los campos de validación de viewstate
    procedure getViewStateInfo(var viewStateStr, viewStateGeneratorStr,
      eventValidationStr: string);
    // busca el tag el id y devuelve el value que está selected dentro de un conjunto de opciones
    function getSelectedValueFromTagNameAndElementId(tagName, id: string
      ): string;
    {Trae una tabla en un arreglo de arreglo de strings,
    valores[kFila][kColumna], se asume que la primera fila está comupesta
    por encabezados (tag th) y el resto son datos (tag td)}
    function getTabla(id: string): TDAOfDAofString;
  end;


procedure cargarCamposConstantes(var rbthttp: TRobotHttpPost);



implementation

procedure cargarCamposConstantes(var rbthttp: TRobotHttpPost);
begin
  rbthttp.AddCampo('__EVENTARGUMENT', '');
  rbthttp.AddCampo('__LASTFOCUS', '');
  rbthttp.AddCampo('ctl00_TreeViewMain_ExpandState', 'nnnnnnnnnnnnnnnn');
  rbthttp.AddCampo('ctl00_TreeViewMain_SelectedNode', '');
  rbthttp.AddCampo('ctl00_TreeViewMain_PopulateLog', '');
end;

{ TDocumentoHTML }

constructor TDocumentoHTML.createFromString(str: string);
begin
  ReadHTMLFile(documento,TStringStream.Create(str));
  cuerpo:=documento.Body;
end;

procedure TDocumentoHTML.Free;
begin
  documento.Free;
end;

function TDocumentoHTML.getValueFromTagNameAndElementId(tagName,
  id: string): string;
var

  elementos: TDOMNodeList;
  encontro, fin:Boolean;
  kElemento: Integer;

begin

  elementos:=cuerpo.GetElementsByTagName(tagName);

  if elementos.count = 0 then
    raise Exception.Create('No hay elementos con el tag ' + tagName);

  encontro:=False;
  fin:=False;
  kElemento:=0;

  while(not encontro) and (not fin) do
  begin
    if TDOMElement(elementos[kElemento]).GetAttribute('id') = id then
    begin
      encontro:=true;
      Result:=TDOMElement(elementos[kElemento]).GetAttribute('value');
    end;
    inc(kElemento);
    if kElemento >= elementos.count then
      fin:=true;
  end;

  if fin then
    raise Exception.Create('No hay elementos con el id ' + id);

end;

function TDocumentoHTML.getSelectedValueFromTagNameAndElementId(tagName,
  id: string): string;
var
  elementos, subElementos: TDOMNodeList;
  encontro, fin, encontroSub, finSub:Boolean;
  kElemento, kSubelemento: Integer;

begin

  elementos:=cuerpo.GetElementsByTagName(tagName);

  if elementos.count = 0 then
    raise Exception.Create('No hay elementos con el tag ' + tagName);

  encontro:=False;
  fin:=False;
  kElemento:=0;
  while(not encontro) and (not fin) do
  begin
    if TDOMElement(elementos[kElemento]).GetAttribute('id') = id then
    begin
      encontro:=true;
      // aca tengo que traer las opciones
      subElementos:=elementos[kElemento].ChildNodes;

      encontroSub:=False;
      finSub:=False;
      kSubElemento:=0;

      while (not encontroSub) and (not finSub) do
      begin
        if TDOMElement(subElementos[kSubElemento]).GetAttribute('selected') = 'selected' then
        begin
          encontroSub:=true;
          Result:=TDOMElement(subElementos[kSubElemento]).GetAttribute('value');
        end;
      inc (kSubelemento);
      if kSubelemento > subElementos.count then
          finSub:=true;
      end;

      if finSub then
        raise Exception.Create('No hay elementos seleccionados');

    end;
    inc(kElemento);
    if kElemento > elementos.count then
      fin:=true;
  end;

  if fin then
    raise Exception.Create('No hay elementos con el id ' + id);
end;

function TDocumentoHTML.getTabla(id:string): TDAOfDAofString;
var
  tabla: TDOMElement;
  elementos, filas, encabezados, aFila: TDOMNodeList;
  encontro, fin: Boolean;
  kElemento: Integer;
  str: String;
  NFilas, kFila, NColumnas, kColumna: Integer;
  valores:TDAOfDAofString;
begin

  elementos:=cuerpo.GetElementsByTagName('table');

  encontro:=False;
  fin:=False;
  kElemento:=0;

  while (not encontro) and (not fin) do
  begin
    if TDOMElement(elementos[kElemento]).GetAttribute('id') = id then
    begin
      encontro:=true;
      tabla:=TDOMElement(elementos[kElemento]);
    end;
  inc (kElemento);
  if kElemento >= elementos.count then
      fin:=true;
  end;

  if fin then
    raise Exception.Create('No hay tabla con el id ' + id);

  {Ahora tengo la tabla en tabla, tendía que ir creando los recs y subirlos}
  {Tengo los renglones o filascomo trs}

  filas:=tabla.GetElementsByTagName('tr');

  encabezados:=TDOMElement(filas[0]).GetElementsByTagName('th');

  NFilas:=filas.Count;
  NColumnas:=encabezados.Count;

  setlength(valores, NFilas);

  for kFila:=0 to NFilas - 1 do
    setlength(valores[kFila], NColumnas);

  // Copio los encabezados en un array de nombres
  for kColumna:=0 to NColumnas - 1 do
    valores[0][kColumna]:=encabezados[kColumna].TextContent;

  // Copio los valores, fechas y horas por fila
  for kFila:=1 to NFilas - 1 do
  begin
    aFila:=TDOMElement(filas[kFila]).GetElementsByTagName('td');
    for kColumna:=0 to NColumnas - 1 do
      valores[kFila][kColumna]:=aFila[kColumna].TextContent;
  end;
  Result:=valores;
end;




procedure TDocumentoHTML.getViewStateInfo(var viewStateStr, viewStateGeneratorStr,
  eventValidationStr: string);
begin
  viewStateStr:=getValueFromTagNameAndElementId('input','__VIEWSTATE');
  viewStateGeneratorStr:=getValueFromTagNameAndElementId('input','__VIEWSTATEGENERATOR');
  eventValidationStr:=getValueFromTagNameAndElementId('input','__EVENTVALIDATION');
end;



end.

