unit uDTResultados;

interface

uses
  xMatDefs, uFechas, SysUtils, classes, uCosa, uActores;

type
  TResumenActor = class
    public
      Clase: TClass;
      nombre, infoAd: String;
      Constructor Create(nombre, clase, infoAd: String);
  end;

  TDAOfResumenActor = array of TResumenActor;

  DTResultadoSim = class
    public
      archiSimRes: String;

      dtIniSim, FechaIni, FechaFin: TDateTime;
      nCronicas, nPasos, nPostes, nActores, nCols: Integer;
      durpos : TDAofNReal;
      durPaso: Integer;

      resumenActores : TDAOfResumenActor;

      encabActores: String;
      actoresPorColumnas: TStringList;

      encabUnidades: String;
      unidadesPorColumnas: TStringList;

      encabVariables: String;
      variablesPorColumnas: TStringList;

      cronicas: array of TDAOfDAofNReal;
      cronicasAsString: array of TDAofDAofString;

      Constructor Create(simres : String);

{     Carga los valores de
      dtIniSim, FechaIni, FechaFin,
      nActores, nCronicas, nPasos, nPostes, nVars,
      durpos, encabActores, actoresPorColumnas, encabVariables y
      variablesPorColumna}
      procedure read_DatosSim;

{     Carga los valores de cronicas y cronicasAsString}
      procedure read_ResultadosSim;

      procedure pararseEnCronicaI(iCronica: Integer; var f: TextFile);
      function esActorDeTipo(iColumna: Integer; tipo: TClaseDeActor) : boolean;

      procedure SplitNomVar(const s : String; var nomActor, nomVar, unidades : String);
      procedure JoinNomVar(const nomActor, nomVar, unidades : String ; var s : String);


      function nombreColumna(iColumna: Integer) : String; overload;
      procedure nomActUniVarColumna(iColumna: Integer; var nomActor, nomVar, unidades : String); overload;

      //Retornan el numero de la columna identificada por nomActor, nomVar y unidades
      //La primer versión recibe el id joineado con JoinNomVar, la segunda recibe
      //los valores por separado
      function columnaActUniVar(const idActUniVar : String) : integer; overload;
      function columnaActUniVar(const nomActor, nomVar, unidades : String) : integer; overload;

      procedure Free;
  end;

  TDescTraduccion = class
    public
      nombre: String;
      unidades: String;
      discretizaciones: TDAOfNReal;

      constructor Create(nombre, unidades : String; discretizaciones : TDAofNReal);
      procedure Free;
  end;

  TDescVar = class
    public
      nombre: String;
      nDiscs: Integer;
      unidades: String;
      discretizaciones: TDAOfNReal;

      //El estado seleccionado para la variable si esta fija
      pos: Integer;
      //Cantidad de columnas que hay que avanzar para incrementar el estado de la variable
      incEstadoCada: Integer;

      mostrarTraduccion: boolean;
      traduccion: TDescTraduccion;

      //retorna el nombre o el nombre traducido según mostrar traduccion
      function getNombre : String;
      //retorna las unidades o las unidades traducidas según mostrar traduccion
      function getUnidades : String;
      //retorna las discretizaciones o las discretizaciones según mostrar traduccion
      function getDiscretizaciones: TDAofNReal;

      constructor Create(nombre, unidades : String; discretizaciones : TDAofNReal; incEstadoCada: Integer);
      procedure storeOpt(var f : TextFile);
      procedure loadOpt(var f : TextFile);
      Procedure Free;
  end;

  TDAOfDescVar = array of TDescVar;

  DTResultadosOpt = class
    public
      archiOpt: String;

      fActPaso: NReal;
      nVarsContinuas, nVarsDiscretas, nEstrellasPorPuntoT, nPuntosT: Integer;

      descVars: TDAOfDescVar;

      //Es una matriz con nPuntosT filas y nEstrellasPorPuntoT + 1 columnas
      //En cada fila tiene en la posicion 0 la fecha del paso y en el resto los
      //datos del archivo
      datos: TDAOfDAofNReal;
      datosAsString: TDAofDAofString;

      Constructor Create(archiOpt : String);

      procedure readDatosOpt;
      procedure readResultadosOpt;

      //Retorna las filas final e inicial de los datos para el rango de fechas seleccionado
      procedure recalcRangoFechas(const fechaIni, fechaFin: TDateTime ; var filaIni, filaFin: Integer);
      function indiceDescVar(const nombreVar : String) : Integer;
      //Retorna el minimo y maximo del rango seleccionado
      procedure minMaxDatos(filaIni, filaFin : Integer; const cols: TDAofNInt; var Min, Max : NReal);

      //retorna el indice del estado de la variable iVar siendo iEstadoGlobal
      //el indice de estado dentro de un frame      
      function iEstadoVar(iVar, iEstadoGlobal: Integer): Integer;

      procedure Free;
  end;

//Retorna el texto que haya hasta el proximo tab o el final de linea
function nextTab(var s : String) : String;
function nextTabInt(var s : String) : Integer;
function nextTabNReal(var s : String) : NReal;

implementation

//------------------------
//Métodos de TResumenActor
//========================
Constructor TResumenActor.Create(nombre, clase, infoAd: String);
begin
  inherited Create();
  self.nombre:= nombre;
  self.infoAd:= infoAd;
  self.Clase:=  ucosa.getClaseOf( clase );
end;

//--------------------------
//Métodos de DTResultadoSim
//==========================

Constructor DTResultadoSim.Create(simres : String);
begin
  inherited Create;
  archiSimRes:= simres;

  durpos:= nil;
  cronicas:= nil;
  cronicasAsString:= nil;
  actoresPorColumnas:= nil;
  variablesPorColumnas:= nil;
end;

procedure DTResultadoSim.read_DatosSim;
var
  entrada: TextFile;
  i: Integer;
  linea, nomActor, tipoActor, infoActor: String;
begin
  try
    AssignFile(entrada, archiSimRes);
    Reset(entrada);

    //Inicio simulación:
    Readln(entrada, linea);
    nextTab(linea);
    dtIniSim:= IsoStrToDateTime(linea);

    //FechaIni FechaFin
    Readln(entrada, linea);
    nextTab(linea);
    FechaIni:= IsoStrToDateTime(nextTab(linea));
    nextTab(linea);
    FechaFin:= IsoStrToDateTime(nextTab(linea));
    //NCronicas
    Readln(entrada, linea);
    NextTab(linea);
    nCronicas:= StrToInt(NextTab(linea));
    //NPasos
    Readln(entrada, linea);
    NextTab(linea);
    nPasos:= StrToInt(NextTab(linea));
    //NPostes
    Readln(entrada, linea);
    NextTab(linea);
    nPostes:= StrToInt(NextTab(linea));
    SetLength(durPos, nPostes);
    //Durpos
    Readln(entrada, linea);
    NextTab(linea);
    for i:= 0 to nPostes - 1 do
      durPos[i]:= StrToFloat(NextTab(linea));
    durPaso:= round(vsum(durPos));
    //NActores
    Readln(entrada, linea);
    NextTab(linea);
    nActores:= StrToInt(NextTab(linea));
    SetLength(resumenActores, nActores);
    readln(entrada, linea);
    for i:= 0 to nActores -1 do
    begin
      Readln(entrada, linea);
      nomActor:= nextTab(linea);
      tipoActor:= nextTab(linea);
      infoActor:= nextTab(linea);
      resumenActores[i]:= TResumenActor.Create(nomActor, tipoActor, infoActor);
    end;
    readln(entrada, linea);

    //Cronica RandSeed
    Readln(entrada, linea);

    //Actores
    Readln(entrada, encabActores);
    linea:= Copy(encabActores, 0, length(encabActores));

    actoresPorColumnas:= TStringList.Create;
    //Como los -
    nCols:= 0;
    while linea <> '' do
    begin
      inc(nCols);
      actoresPorColumnas.Add(nextTab(linea));
    end;

    readln(entrada, encabUnidades);
    linea:= Copy(encabUnidades, 0, length(encabUnidades));
    unidadesPorColumnas:= TStringList.Create;
    unidadesPorColumnas.Capacity:= actoresPorColumnas.Count;

    //- -
    while linea <> '' do
      unidadesPorColumnas.Add(nextTab(linea));

    readln(entrada, encabVariables);
    linea:= Copy(encabVariables, 0, length(encabVariables));

    variablesPorColumnas:= TStringList.Create;
    variablesPorColumnas.Capacity:= actoresPorColumnas.Count;

    //Paso	FechaInicioDelPaso
    while linea <> '' do
      variablesPorColumnas.Add(nextTab(linea));
  finally
    CloseFile(entrada);
  end;
end;

procedure DTResultadoSim.read_ResultadosSim;
var
  cronicaI: TDAOfDAofNReal;
  pasoJCronicaI: TDAofNReal;
  cronicaIAsString: TDAofDAofString;
  pasoJCronicaIAsString: TDAofString;
  entrada: TextFile;
  i, j, k: Integer;
  linea: String;
begin
  try
    AssignFile(entrada, archiSimRes);
    Reset(entrada);

    //Inicio simulación:
    Readln(entrada, linea);
    //FechaIni FechaFin
    Readln(entrada, linea);
    //NActores
    Readln(entrada, linea);
    //NCronicas
    Readln(entrada, linea);
    //NPasos
    Readln(entrada, linea);
    //NPostes
    Readln(entrada, linea);
    //Durpos
    Readln(entrada, linea);
    readln(entrada, linea);

    SetLength(cronicas, nCronicas);
    SetLength(cronicasAsString, nCronicas);
    for i := 0 to nCronicas - 1 do
    begin
      //Cronica RandSeed
      Readln(entrada, linea);
      //Actores
      Readln(entrada, linea);
      //Variables
      readln(entrada, linea);

      SetLength(cronicasAsString[i], nPasos);
      SetLength(cronicas[i], nPasos);

      cronicaIAsString:= cronicasAsString[i];
      cronicaI:= cronicas[i];
      for j := 0 to nPasos - 1 do
      begin
        SetLength(cronicaIAsString[j], nCols + 1);
        SetLength(cronicaI[j], nCols + 1);

        pasoJCronicaIAsString:= cronicaIAsString[j];
        pasoJCronicaI:= cronicaI[j];

        readln(entrada, linea);
        //paso
        NextTab(linea);
        //fecha
        pasoJCronicaIAsString[0]:= NextTab(linea);
        pasoJCronicaI[0]:= IsoStrToDateTime(pasoJCronicaIAsString[0]);
        for k:= 1 to nCols do
        begin
          pasoJCronicaIAsString[k]:= NextTab(linea);
          pasoJCronicaI[k]:= StrToFloat(pasoJCronicaIAsString[k]);
        end;
        readln(entrada, linea);
      end;
    end;
  finally
    CloseFile(entrada);
  end;
end;

procedure DTResultadoSim.pararseEnCronicaI(iCronica: Integer; var f: TextFile);
var
  i, iPaso: Integer;
  basura : String;
begin
  for i := 0 to 7 + nActores + 1 do
    readln(f, basura);
  for i:= 1 to iCronica - 1 do
    for iPaso:= 0 to nPasos + 5 do
      readln(f, basura);
end;

function DTResultadoSim.esActorDeTipo(iColumna: Integer; tipo: TClaseDeActor) : boolean;
var
  i: Integer;
  res: boolean;
begin
  res:= false;
  for i:= 0 to high(resumenActores) do
  begin
    if resumenActores[i].nombre = actoresPorColumnas[iColumna] then
    begin
      res:= resumenActores[i].Clase.InheritsFrom(tipo);
      break;
    end;
  end;
  result:= res;
end;

procedure DTResultadoSim.SplitNomVar(const s : String; var nomActor, nomVar, unidades : String);
var
  posComa: Integer;
begin
  posComa:= Pos(', ', s);
  nomActor:= Copy(s, 0, posComa - 1);
  nomVar:= Copy(s, posComa + 2, Length(s) - posComa + 2);
  posComa:= Pos(', ', nomVar);
  unidades:= Copy(nomVar, posComa + 2, length(nomVar) - posComa + 2);
  nomVar:= copy(nomVar, 0, posComa - 1);
end;

procedure DTResultadoSim.JoinNomVar(const nomActor, nomVar, unidades : String ; var s : String);
begin
  s:= nomActor + ', ' + nomVar + ', ' + unidades;
end;

function DTResultadoSim.nombreColumna(iColumna: Integer) : String;
var
  res: String;
begin
  JoinNomVar(actoresPorColumnas[iColumna],
             variablesPorColumnas[iColumna],
             unidadesPorColumnas[iColumna],
             res);
  result:= res;
end;

procedure DTResultadoSim.nomActUniVarColumna(iColumna: Integer; var nomActor, nomVar, unidades : String);
begin
  nomActor:= actoresPorColumnas[iColumna];
  nomVar:= variablesPorColumnas[iColumna];
  unidades:= unidadesPorColumnas[iColumna];
end;

function DTResultadoSim.columnaActUniVar(const idActUniVar : String) : integer;
var
  nomAct, nomVar, unidades: String;
begin
  SplitNomVar(idActUniVar, nomAct, nomVar, unidades);
  result:= columnaActUniVar(nomAct, nomVar, unidades);
end;

function DTResultadoSim.columnaActUniVar(const nomActor, nomVar, unidades : String) : integer;
var
  res, i: Integer;
begin
  res:= -1;
  for i:= 0 to actoresPorColumnas.Count - 1 do
    if (actoresPorColumnas[i] = nomActor) and
       (variablesPorColumnas[i] = nomVar) and
       (unidadesPorColumnas[i] = unidades) then
    begin
      res:= i;
      break;
    end;
  result:= res;
end;

procedure DTResultadoSim.Free;
var
  i: Integer;
begin
  if durpos <> nil then
    SetLength(durpos, 0);
  if cronicas <> nil then
  begin
    for i:= 0 to nCronicas - 1 do
    begin
      SetLength(cronicasAsString[i], 0);
      SetLength(cronicas[i], 0);
    end;
    SetLength(cronicasAsString, 0);
    SetLength(cronicas, 0);
  end;
  if actoresPorColumnas <> nil then
    actoresPorColumnas.Free;
  if variablesPorColumnas <> nil then
    variablesPorColumnas.Free;
  inherited Free;
end;

//--------------------------
//Métodos de TDescTraduccion
//==========================

constructor TDescTraduccion.Create(nombre, unidades : String; discretizaciones : TDAofNReal);
begin
  inherited Create();
  self.nombre:= nombre;
  Self.unidades:= unidades;
  Self.discretizaciones:= discretizaciones;
end;

procedure TDescTraduccion.Free;
begin
  SetLength(discretizaciones, 0);
  inherited Free;
end;

//-------------------
//Métodos de TDescVar
//===================

constructor TDescVar.Create(nombre, unidades : String; discretizaciones : TDAofNReal ; incEstadoCada: Integer);
begin
  inherited Create();
  Self.nombre:= nombre;
  self.unidades:= unidades;
  self.discretizaciones:= discretizaciones;
  self.nDiscs:= length(discretizaciones);
  self.pos:= 0;
  self.incEstadoCada:= incEstadoCada;
  mostrarTraduccion:= false;
  traduccion:= NIL;
end;

procedure TDescVar.storeOpt(var f : TextFile);
begin
  //Nombre de la variable, solo para poder leer mejor el archivo
  writeln(f, self.nombre);
  Writeln(f, 'pos= ', pos);
  Writeln(f, 'mostrarTraduccion= ', BoolToStr(mostrarTraduccion));
end;

procedure TDescVar.loadOpt(var f : TextFile);
var
  val: String;
begin
  //Nombre de la variable
  readln(f, val);
  assert(val = self.nombre);
  //pos
  readln(f, val);
  val:= copy(val, system.pos('= ', val) + 2, MAXINT);
  pos:= StrToInt(val);
  //mostrarTraduccion
  readln(f, val);
  val:= copy(val, system.pos('= ', val) + 2, MAXINT);
  mostrarTraduccion:= StrToBool(val);
end;

procedure TDescVar.Free;
begin
  SetLength(discretizaciones, 0);
  inherited Free;
end;

function TDescVar.getNombre : String;
begin
  if not mostrarTraduccion then
    Result:= nombre
  else
    Result:= traduccion.nombre;
end;

function TDescVar.getUnidades : String;
begin
  if not mostrarTraduccion then
    Result:= unidades
  else
    Result:= traduccion.unidades;
end;

function TDescVar.getDiscretizaciones: TDAofNReal;
begin
  if not mostrarTraduccion then
    Result:= discretizaciones
  else
    Result:= traduccion.discretizaciones;
end;

//--------------------------
//Métodos de DTResultadosOpt
//==========================

Constructor DTResultadosOpt.Create(archiOpt: String);
begin
  inherited Create;
  self.archiOpt:= archiOpt;
  descVars:= nil;
end;

procedure DTResultadosOpt.readDatosOpt;
var
  f: TextFile;
  i, j: Integer;
  linea: String;
  incEstadoCada: Integer;
  nomVar, nomTraduccion, unidades, uniTraduccion: String;
  nDiscsVar: Integer;
  discVar, discVarTraduccion: TDAofNReal;
  descVar: TDescVar;
  tieneTraduccion: boolean;
begin
  try
    AssignFile(f, archiOpt);
    Reset(f);
    //fActPaso
    readln(f, linea);
    NextTab(linea);
    fActPaso:= StrToFloat(NextTab(linea));

    //nContinuas
    readln(f, linea);
    NextTab(linea);
    nVarsContinuas:= StrToInt(NextTab(linea));

    //nDiscretas
    readln(f, linea);
    NextTab(linea);
    nVarsDiscretas:= StrToInt(NextTab(linea));

    //nEstrellas/PuntoT
    readln(f, linea);
    NextTab(linea);
    nEstrellasPorPuntoT:= StrToInt(NextTab(linea));

    //nPuntosT
    readln(f, linea);
    NextTab(linea);
    if pos('optres', ExtractFileName(archiOpt)) <> 0 then
      nPuntosT:= StrToInt(NextTab(linea)) + 1
    else
      nPuntosT:= StrToInt(NextTab(linea));

    incEstadoCada:= 1;
    SetLength(descVars, nVarsContinuas + nVarsDiscretas);
    if nVarsContinuas > 0 then
    begin
      //-- Descripción variables contínuas --
      Readln(f, linea);

      for i:= 1 to nVarsContinuas do
      begin
        //Nombre
        readln(f, linea);
        NextTab(linea);
        nomVar:= NextTab(linea);
        if linea <> '' then
        begin
          tieneTraduccion:= true;
          nomTraduccion:= NextTab(linea);
        end
        else
          tieneTraduccion:= false;

        //Unidades
        readln(f, linea);
        NextTab(linea);
        unidades:= NextTab(linea);
        if tieneTraduccion then
          uniTraduccion:= NextTab(linea);

        //xmin, xmax
        readln(f, linea); readln(f, linea);

        //nPuntos
        readln(f, linea);
        NextTab(linea);
        nDiscsVar:= StrToInt(NextTab(linea));

        //x[...]
        readln(f, linea);
        NextTab(linea);
        SetLength(discVar, nDiscsVar);
        for j:= 0 to nDiscsVar - 1 do
          discVar[j]:= StrToFloat(NextTab(linea));
        if tieneTraduccion then
        begin
          //xT[...]
          readln(f, linea);
          NextTab(linea);
          SetLength(discVarTraduccion, nDiscsVar);
          for j:= 0 to nDiscsVar - 1 do
            discVarTraduccion[j]:= StrToFloat(NextTab(linea));
        end;

        descVar:= TDescVar.Create(nomVar, unidades, discVar, incEstadoCada);
        if tieneTraduccion then
          descVar.traduccion:= TDescTraduccion.Create(nomTraduccion, uniTraduccion, discVarTraduccion);
        descVars[i - 1]:= descVar;

        incEstadoCada:= incEstadoCada * nDiscsVar;
      end;
    end;

    if nVarsDiscretas > 0 then
    begin
      //-- Descripción variables discretas --
      Readln(f, linea);

      for i:= 1 to nVarsDiscretas do
      begin
        //Nombre
        readln(f, linea);
        NextTab(linea);
        nomVar:= NextTab(linea);
        if linea <> '' then
        begin
          tieneTraduccion:= true;
          nomTraduccion:= NextTab(linea);
        end
        else
          tieneTraduccion:= false;

        //Unidades
        readln(f, linea);
        NextTab(linea);
        unidades:= NextTab(linea);
        if tieneTraduccion then
          uniTraduccion:= NextTab(linea);

        //nPuntos
        readln(f, linea);
        NextTab(linea);
        nDiscsVar:= StrToInt(NextTab(linea));

        //x[...]
        readln(f, linea);
        NextTab(linea);
        SetLength(discVar, nDiscsVar);
        for j:= 0 to nDiscsVar - 1 do
          discVar[j]:= StrToFloat(NextTab(linea));
        if tieneTraduccion then
        begin
          //xT[...]
          readln(f, linea);
          NextTab(linea);
          SetLength(discVarTraduccion, nDiscsVar);
          for j:= 0 to nDiscsVar - 1 do
            discVarTraduccion[j]:= StrToFloat(NextTab(linea));
        end;

        descVar:= TDescVar.Create(nomVar, unidades, discVar, incEstadoCada);
        if tieneTraduccion then
          descVar.traduccion:= TDescTraduccion.Create(nomTraduccion, uniTraduccion, discVarTraduccion);
        descVars[nVarsContinuas + i - 1]:= descVar;

        incEstadoCada:= incEstadoCada * nDiscsVar;
      end;
    end;
  finally
    CloseFile(f);
  end;
end;

procedure DTResultadosOpt.readResultadosOpt;
var
  f: TextFile;
  linea: String;
  fila: TDAofNReal;
  filaAsString: TDAofString;
  i, j: Integer;
begin
  try
    AssignFile(f, archiOpt);
    Reset(f);

    //fActPaso
    readln(f, linea);
    //nContinuas
    readln(f, linea);
    //nDiscretas
    readln(f, linea);
    //nEstrellas/PuntoT
    readln(f, linea);
    //nPuntosT
    readln(f, linea);

    //Descripciones de las variables
    while linea <> '' do
      readln(f, linea);

    //Paso/Estado
    readln(f, linea);

    SetLength(datos, nPuntosT);
    SetLength(datosAsString, nPuntosT);
    for i:= nPuntosT - 1 downto 0 do
    begin
      SetLength(datos[i], nEstrellasPorPuntoT + 1);
      SetLength(datosAsString[i], nEstrellasPorPuntoT + 1);
      fila:= datos[i];
      filaAsString:= datosAsString[i];
      readln(f, linea);
      //Paso
      NextTab(linea);
      filaAsString[0]:= NextTab(linea);
      fila[0]:= uFechas.IsoStrToDateTime(filaAsString[0]);
      for j:= 1 to nEstrellasPorPuntoT do
      begin
        filaAsString[j]:= NextTab(linea);
        fila[j]:= StrToFloat(filaAsString[j]);
      end;
    end;
  finally
    CloseFile(f);
  end;
end;

procedure DTResultadosOpt.recalcRangoFechas(const fechaIni, fechaFin: TDateTime ; var filaIni, filaFin: Integer);
begin
  if (fechaIni < datos[0][0]) or (fechaFin > datos[nPuntosT -1][0]) then
    raise Exception.Create('El rango de fechas seleccionado esta fuera de los datos provistos.')
  else if fechaIni > fechaFin then
    raise Exception.Create('La fecha de inicio es posterior a la fecha de fin!');

  filaIni:= 0;
  while datos[filaIni][0] < fechaIni do
    inc(filaIni);
  filaFin:= filaIni;
  while datos[filaFin][0] < fechaFin do
    inc(filaFin);
end;

function DTResultadosOpt.indiceDescVar(const nombreVar : String) : Integer;
var
  i, res : Integer;
begin
  res:= -1;
  for i:= 0 to high(descVars) do
    if nombreVar = TDescVar(descVars[i]).nombre then
    begin
      res:= i;
      break;
    end;
  result:= res;
end;

procedure DTResultadosOpt.minMaxDatos(filaIni, filaFin : Integer; const cols: TDAofNInt; var Min, Max : NReal);
var
  iFila, iColumna: Integer;
  val: NReal;
  fila: TDAofNReal;
begin
  min:= MaxNReal; max := -MaxNReal;
  for iFila:= filaIni to filaFin do
  begin
    fila:= datos[iFila];
    for iColumna:= 0 to high(cols) do
    begin
      val:= fila[cols[iColumna]];
      if val < min then
        min:= val;
      if val > max then
        max:= val;
    end;
  end;
end;

function DTResultadosOpt.iEstadoVar(iVar, iEstadoGlobal: Integer): Integer;
begin
  result:= (iEstadoGlobal div descVars[iVar].incEstadoCada) mod descVars[iVar].nDiscs;
end;

procedure DTResultadosOpt.Free;
var
  i: Integer;
begin
  for i:= 0 to High(descVars) do
    descVars[i].Free;
  SetLength(descVars, 0);
  for i:= 0 to high(datos) do
  begin
    SetLength(datos[i], 0);
    SetLength(datosAsString[i], 0);
  end;
  SetLength(datos, 0);
  SetLength(datosAsString, 0);
  inherited Free;
end;

function nextTab(var s : String) : String;
var
  posTab: Integer;
  res: String;
begin
  posTab:= Pos(#9, s);
  if posTab <> 0 then
  begin
    res:= Copy(s, 1, posTab -1);
    delete(s, 1, posTab);
  end
  else
  begin
    res:= copy(s, 1, length(s));
    s:= '';
  end;
  result:= trim(res);
end;

function nextTabInt(var s : String) : Integer;
begin
  result:= StrToInt(nextTab(s))
end;

function nextTabNReal(var s : String) : NReal;
begin
  result:= StrToFloat(nextTab(s))
end;

end.
