unit LBRMRead;

interface

uses SysUtils, MyDates, Arrays, LBRMTypes;

function ReadConfigFile(CfgFileName : string;
                      var CfgInfo : TConfigInfo) : boolean;
function WriteConfigFile(CfgFileName : string;
                       var CfgInfo : TConfigInfo) : boolean;

function ReadParmFile(ParmFileName : string;
                      var ParmInfo : TParameterInfo) : boolean;
function WriteParmFile(ParmFileName : string;
                       var ParmInfo : TParameterInfo) : boolean;

function GetBoundCount(FileName : string;
                       SSeq, ESeq : longint;
                        var   BC : integer) : boolean;
function ReadBoundaryFile(FileName : string;
                          var BCond : TBoundaryInfo) : boolean;
function WriteBoundaryFile(FileName : string;
                           var BCond : TBoundaryInfo) : boolean;


function GetFLWStartEnd(FlwFileName : string;
                        var First, Last : longint) : boolean;
function ReadFlowFile(FlowFileName : string;
                      FSD, FED     : longint;
                      var FlowData : TMyArrayOfSingle) : boolean;

function GetMetStartEnd(MetFileName : string;
                        var First, Last : longint) : boolean;
function ReadMetFile(FName       : string;
                     First, Last : longint;
                     var MetData : TMetData) : boolean;

var
   ReadDataErrMessage : string;


implementation

{$RANGECHECKS OFF}

//--------------------------------------------------------------------------
procedure WriteErrMsg(S : string);
begin
   ReadDataErrMessage := S;
end;

//--------------------------------------------------------------------------
function ReadConfigFile(CfgFileName : string;
                      var CfgInfo : TConfigInfo) : boolean;
var
  I            : longint;
  S1, S2, Line : string;
  F            : TextFile;
begin
  Result := FALSE;    // default value in case of failure

  with CfgInfo do begin
    WorkDir   := '';
    ParmFile  := '';
    BoundFile := '';
    MetFile   := '';
    FlowFile  := '';
    LBRMFile  := '';
  end;

  if (not FileExists(CfgFileName)) then exit;
  try
    AssignFile(F, CfgFileName);
  except
    exit;
  end;

  //
  //  Read the file
  //
  try
    Reset(F);
    while (not eof(F)) do begin
       Readln(F, Line);
       I := Pos('=', Line);
       if (I > 0) then begin
          S1 := TRIM(Copy(Line,0,I-1));
          S2 := TRIM(Copy(Line,I+1,999));
          if (CompareText(S1,'PARMFILE') = 0) then CfgInfo.ParmFile  := S2;
          if (CompareText(S1,'BCFILE')   = 0) then CfgInfo.BoundFile := S2;
          if (CompareText(S1,'METFILE')  = 0) then CfgInfo.MetFile   := S2;
          if (CompareText(S1,'OUTFILE')  = 0) then CfgInfo.LBRMFile  := S2;
          if (CompareText(S1,'DATAFILE') = 0) then CfgInfo.FlowFile  := S2;
          if (CompareText(S1,'WORKDIR')  = 0) then CfgInfo.WorkDir   := S2;
       end;
    end;
  except
    CloseFile(F);
    exit;
  end;

  CloseFile(F);
  Result := TRUE;
end;

//--------------------------------------------------------------------------
function WriteConfigFile(CfgFileName : string;
                       var CfgInfo : TConfigInfo) : boolean;
var
  F : TextFile;
begin
  Result := FALSE;    // default value in case of failure

  try
    AssignFile(F, CfgFileName);
    ReWrite(F);
  except
    exit;
  end;

  try
    Writeln(F, 'PARMFILE=', CfgInfo.ParmFile);
    Writeln(F, 'BCFILE=',   CfgInfo.BoundFile);
    Writeln(F, 'METFILE=',  CfgInfo.MetFile);
    Writeln(F, 'DATAFILE=', CfgInfo.FlowFile);
    Writeln(F, 'OUTFILE=',  CfgInfo.LBRMFile);
    Writeln(F, 'WORKDIR=',  CfgInfo.WorkDir);
  except
    CloseFile(F);
    exit;
  end;

  CloseFile(F);
  Result := TRUE;
end;

//--------------------------------------------------------------------------
function ReadParmFile(ParmFileName : string;
                      var ParmInfo : TParameterInfo) : boolean;
var
  I, J, D, M, Y : longint;
  S, Line : string;
  F       : TextFile;
begin
  Result := FALSE;

  //
  // Initialize variables to "missing" in case of early exit from reading.
  //
  for I:=1 to 9 do begin
      ParmInfo.ParmNow[I] := -9.9e9;
      ParmInfo.ParmMin[I] := -9.9e9;
      ParmInfo.ParmMax[I] := -9.9e9;
      ParmInfo.ParmOpt[I] := -9.9e9;
      ParmInfo.DigitNow[I] := -9;
      ParmInfo.DigitMax[I] := -9;
  end;
  for I:=1 to 12 do begin
      ParmInfo.Insolation[I] := -9.9e9;
  end;
  ParmInfo.SDate := -9;
  ParmInfo.EDate := -9;
  ParmInfo.Area  := -9.9e9;
  ParmInfo.KCons := -9.9e9;
  ParmInfo.B1    := -9.9e9;
  ParmInfo.B2    := -9.9e9;
  ParmInfo.USZC  := -9.9e9;
  ParmInfo.CurrentParm := 1;

  for I:=1 to 50 do begin
     ParmInfo.Comments[I] := '';
  end;

  //
  // Open the parameter file
  //
  try
    AssignFile(F, ParmFileName);
  except
    exit;
  end;

  //
  //  Read the file
  //
  try
    Reset(F);
    Readln(F, ParmInfo.IDString);                    // ID string
    Readln(F, ParmInfo.Area, ParmInfo.Comments[1]);  // watershed area (sq meters)

    Readln(F, Line);
    S := Copy(Line, 1, 2);
    D := StrToInt(S);
    S := Copy(Line, 3, 2);
    M := StrToInt(S);
    S := Copy(Line, 5, 4);
    Y := StrToInt(S);
    DateSequence(D, M, Y, ParmInfo.SDate);   // desired simulation start date

    Line := Copy(Line, 9, 250);
    try
      S := Copy(Line, 1, 2);
      D := StrToInt(S);
      S := Copy(Line, 3, 2);
      M := StrToInt(S);
      S := Copy(Line, 5, 4);
      Y := StrToInt(S);
      DateSequence(D, M, Y, ParmInfo.CDate);   // desired calibration start date
      ParmInfo.Comments[2] := Copy(Line, 9, 200);
    except
      ParmInfo.CDate := 0;
      ParmInfo.Comments[2] := Line;
    end;

    Readln(F, Line);
    S := Copy(Line, 1, 2);
    D := StrToInt(S);
    S := Copy(Line, 3, 2);
    M := StrToInt(S);
    S := Copy(Line, 5, 4);
    Y := StrToInt(S);
    DateSequence(D, M, Y, ParmInfo.EDate);   // desired end date
    ParmInfo.Comments[3] := Copy(Line, 9, 200);

    //
    // Read the information for the 10 parameters.
    // PNow should always be there, but the rest are optional.
    //
    for I:=1 to 9 do begin

       //
       // Get ParmNow value
       //
       Readln(F, Line);
       S := Trim(Copy(Line, 1, 13));        // no leading/trailing blanks
       ParmInfo.ParmNow[I]  := StrToFloat(S);
       J := 13;

       //
       // Get DigitNow value
       //
       S := Copy(Line, J+1, 200);  // trim off the ParamNow[] value
       Line := TrimLeft(S) + ' ';  // trim off leading blanks
       J := Pos(' ', Line);
       S := Copy(Line, 1, J-1);
       ParmInfo.Comments[3+I] := Copy(Line, J, 200);
       ParmInfo.DigitNow[I] := -9;
       if (Length(S) > 0) then begin
          try
            ParmInfo.DigitNow[I] := StrToInt(S);
          except
            J := 99;    // force rest to fail
          end;
       end;

       //
       // Get DigitMax value
       //
       if (J < 99) then begin
          S := Copy(Line, J+1, 200);  // trim off the DigitNow[] value
          Line := TrimLeft(S) + ' ';  // trim off leading blanks
          J := Pos(' ', Line);
          S := Copy(Line, 1, J-1);
          ParmInfo.Comments[3+I] := Copy(Line, J, 200);
          ParmInfo.DigitMax[I] := -9;
          if (Length(S) > 0) then begin
             try
               ParmInfo.DigitMax[I] := StrToInt(S);
               ParmInfo.Comments[3+I] := Copy(Line, 3, 200);
             except
               J := 99;    // force rest to fail
             end;
          end;
       end;

       //
       // Get ParmMin value
       //
       if (J < 99) then begin
          S := Copy(Line, J+1, 200);   // trim off the DigitMax[] value
          Line := TrimLeft(S) + ' ';   // trim off leading blanks
          J := Pos(' ', Line);
          S := Copy(Line, 1, J-1);
          ParmInfo.Comments[3+I] := Copy(Line, J, 200);
          ParmInfo.ParmMin[I] := -9.9;
          if (Length(S) > 0) then begin
             try
               ParmInfo.ParmMin[I] := StrToFloat(S);
             except
               J := 99;    // force rest to fail
             end;
          end;
       end;

       //
       // Get ParmMax value
       //
       if (J < 99) then begin
          S := Copy(Line, J+1, 200);   // trim off the ParamMin[] value
          Line := TrimLeft(S) + ' ';   // trim off leading blanks
          J := Pos(' ', Line);
          S := Copy(Line, 1, J-1);
          ParmInfo.Comments[3+I] := Copy(Line, J, 200);
          ParmInfo.ParmMax[I] := -9.9;
          if (Length(S) > 0) then begin
             try
               ParmInfo.ParmMax[I] := StrToFloat(S);
             except
//               J := 99;    // force rest to fail
             end;
          end;
       end;

       //
       // Some "sanity checks"
       //
       if (ParmInfo.ParmMin[I] > ParmInfo.ParmNow[I]) then
           ParmInfo.ParmMin[I] := ParmInfo.ParmNow[I];

       if (ParmInfo.ParmMax[I] < ParmInfo.ParmNow[I]) then
           ParmInfo.ParmMax[I] := ParmInfo.ParmNow[I];

       if (ParmInfo.DigitNow[I] > 9) then ParmInfo.DigitNow[I] := -9;
       if (ParmInfo.DigitMax[I] > 9) then ParmInfo.DigitMax[I] := -9;
    end;

    //
    // Read the value of the constant (KCons)
    //
    Readln(F, Line);
    S := Trim(Copy(Line, 1, 13));        // no leading/trailing blanks
    ParmInfo.KCons := StrToFloat(S);
    ParmInfo.Comments[13] := Copy(Line, 14, 200);

    //
    // Read the 12 insolation values if available
    //
    for I:=1 to 12 do begin
       Readln(F, Line);
       S := Trim(Copy(Line, 1, 13));        // no leading/trailing blanks
       ParmInfo.Insolation[I] := StrToFloat(S);
       ParmInfo.Comments[13+I] := Copy(Line, 14, 200);
    end;

    //
    // Read the rest of the data
    //
    Readln(F, Line);
    S := Trim(Copy(Line, 1, 13));        // no leading/trailing blanks
    ParmInfo.B1 := StrToFloat(S);
    ParmInfo.Comments[26] := Copy(Line, 14, 200);

    Readln(F, Line);
    S := Trim(Copy(Line, 1, 13));        // no leading/trailing blanks
    ParmInfo.B2 := StrToFloat(S);
    ParmInfo.Comments[27] := Copy(Line, 14, 200);

    Readln(F, Line);
    S := Trim(Copy(Line, 1, 13));        // no leading/trailing blanks
    ParmInfo.USZC := StrToFloat(S);
    ParmInfo.Comments[28] := Copy(Line, 14, 200);

    //
    //  Get DOSDigit, RMSE, and Correlation (if possible)
    //
    try
       Readln(F, Line);
       S := Trim(Copy(Line, 1, 2));        // no leading/trailing blanks
       ParmInfo.Comments[29] := Copy(S, 1, 200);
       if (Length(S) > 0) then begin
          try
            ParmInfo.CurrentParm := StrToInt(S);
            J := 2;
          except
            J := 99;    // force rest to fail
          end;
       end;

       // RMSE
       if (J < 99) then begin
          S := Copy(Line, J+1, 200);   // trim off the DOSDigit value
          ParmInfo.Comments[29] := S;
          Line := TrimLeft(S) + ' ';   // trim off leading blanks
          J := Pos(' ', Line);
          S := Copy(Line, 1, J-1);
          ParmInfo.RMSE := 999.999;
          if (Length(S) > 0) then begin
             try
               ParmInfo.Comments[29] := Copy(Line, J, 200);
               ParmInfo.RMSE := StrToFloat(S);
             except
               J := 99;    // force rest to fail
             end;
          end;
       end;

       // Correlation
       if (J < 99) then begin
          S := Copy(Line, J+1, 200);   // trim off the RMSE value
          ParmInfo.Comments[29] := S;
          Line := TrimLeft(S) + ' ';   // trim off leading blanks
          J := Pos(' ', Line);
          S := Copy(Line, 1, J-1);
          ParmInfo.Correlation := -999.999;
          if (Length(S) > 0) then begin
             try
               ParmInfo.Comments[29] := Copy(Line, J, 200);
               ParmInfo.Correlation := StrToFloat(S);
             except
             end;
          end;
       end;
    except
      ParmInfo.Comments[29] := Line;
    end;

    I := 30;
    while (not eof(F) AND (I < 51)) do begin
       Readln(F, Line);
       ParmInfo.Comments[I] := Line;
       inc(I);
    end;

    CloseFile(F);
  except
    CloseFile(F);
    exit;
  end;

  Result := TRUE;
end;


//--------------------------------------------------------------------------
function WriteParmFile(ParmFileName : string;
                       var ParmInfo : TParameterInfo) : boolean;
var
  I, D, M, Y         : longint;
  S, SD, SM, SY      : string;
  S1, S2, S3, S4, S5 : string;
  F     : TextFile;
begin
  Result := FALSE;

  //
  // Open the parameter file
  //
  try
    AssignFile(F, ParmFileName);
  except
    exit;
  end;

  try
    //
    //  write the header line and watershed area
    //
    Rewrite(F);
    Writeln(F, ParmInfo.IDString);                     // ID string put in by text editor
    S := FormatFloat(' 0.000000E+00', ParmInfo.Area);  // watershed area (sq meters)
    Writeln(F, S, ParmInfo.Comments[1]);

    //
    //  write start and end dates for calibration period
    //
    SequenceDate(D, M, Y, ParmInfo.SDate);
    str(D:2, SD);
    str(M:2, SM);
    str(Y:4, SY);
    S1 := SD + SM + SY;
    SequenceDate(D, M, Y, ParmInfo.CDate);
    str(D:2, SD);
    str(M:2, SM);
    str(Y:4, SY);
    S2 := SD + SM + SY;
    Writeln(F, S1, S2, ParmInfo.Comments[2]);

    SequenceDate(D, M, Y, ParmInfo.EDate);
    str(D:2, SD);
    str(M:2, SM);
    str(Y:4, SY);
    Writeln(F, SD, SM, SY, ParmInfo.Comments[3]);

    //
    //  Write the parameter values (now, min, max, and digits)
    //
    for I:=1 to 9 do begin
       S1 := FormatFloat(' 0.000000E+00', ParmInfo.ParmNow[I]);
       S2 := FormatFloat(' 0', ParmInfo.DigitNow[I]);
       S3 := FormatFloat(' 0', ParmInfo.DigitMax[I]);
       S4 := FormatFloat(' 0.000000E+00;-0.000000E+00', ParmInfo.ParmMin[I]);
       S5 := FormatFloat(' 0.000000E+00;-0.000000E+00', ParmInfo.ParmMax[I]);
       Writeln(F, S1, S2, S3, S4, S5, ParmInfo.Comments[3+I]);
    end;

    //
    // Write the value of the constant (KCons)
    //
    S := FormatFloat(' 0.000000E+00', ParmInfo.KCons);
    Writeln(F, S, ParmInfo.Comments[13]);

    //
    // Write the 12 insolation values
    //
    for I:=1 to 12 do begin
       S := FormatFloat(' 0.000000E+00', ParmInfo.Insolation[I]);
       Writeln(F, S, ParmInfo.Comments[13+I]);
    end;

    //
    // Write the rest of the data
    //
    S := FormatFloat(' 0.000000E+00', ParmInfo.B1);
    Writeln(F, S, ParmInfo.Comments[26]);

    S := FormatFloat(' 0.000000E+00', ParmInfo.B2);
    Writeln(F, S, ParmInfo.Comments[27]);

    S := FormatFloat(' 0.000000E+00', ParmInfo.USZC);
    Writeln(F, S, ParmInfo.Comments[28]);

    Str(ParmInfo.CurrentParm:2, S1);
    S2 := FormatFloat(' 0.000000E+00;-0.000000E+00', ParmInfo.RMSE);
    S3 := FormatFloat(' 0.000000E+00;-0.000000E+00', ParmInfo.Correlation);
    Writeln(F, S1, S2, S3, ParmInfo.Comments[29]);

    for I:=30 to 50 do begin
       Writeln(F, ParmInfo.Comments[I]);
    end;

    CloseFile(F);
  except
    CloseFile(F);
    exit;
  end;

  Result := TRUE;
end;


//--------------------------------------------------------------------------
//  Get count of JUST THOSE WITHIN THE SPECIFIED PERIOD.
//
function GetBoundCount(FileName   : string;
                       SSeq, ESeq : longint;
                       var   BC   : integer) : boolean;
var
  D, M, Y, ICD : longint;
  S, Line : string;
  F       : TextFile;
begin
  Result := FALSE;

  //
  // Open the boundary conditions file
  //
  try
    AssignFile(F, FileName);
  except
    exit;
  end;

  try
    Reset(F);
    Readln(F);           // skip the two
    Readln(F);           // header lines
    BC := 0;
    while (not eof(F)) do begin
       Readln(F, Line);
       if (Length(Line) > 20) then begin
          S := Copy(Line, 1, 2);
          D := StrToInt(S);
          S := Copy(Line, 3, 2);
          M := StrToInt(S);
          S := Copy(Line, 5, 4);
          Y := StrToInt(S);
          DateSequence(D, M, Y, ICD);     // initial conditions date
          if ((ICD >= SSeq) AND (ICD <= ESeq)) then BC := BC + 1;
       end;
    end;
    CloseFile(F);
  except
    BC := 0;
    CloseFile(F);
    exit;
  end;

  Result := TRUE;
end;


//--------------------------------------------------------------------------
//  Read and save *ALL* of the boundary conditions, regardless of date.
//
function ReadBoundaryFile(FileName   : string;
                          var BCond  : TBoundaryInfo) : boolean;
var
  I, J, D, M, Y, ICD : longint;
  A       : array [1..5] of single;
  S, Line : string;
  F       : TextFile;
  BI      : TBoundInfo;
begin
  Result := FALSE;

  //
  // Open the boundary conditions file
  //
  try
    AssignFile(F, FileName);
  except
    exit;
  end;

  try
    Reset(F);
    BCond.Clear;
    Readln(F, BCond.HeaderLine1);           // read the two
    Readln(F, BCond.HeaderLine2);           // header lines
    while (not eof(F)) do begin
       Readln(F, Line);
       if (Length(Line) > 20) then begin
         S := Copy(Line, 1, 2);
         D := StrToInt(S);
         S := Copy(Line, 3, 2);
         M := StrToInt(S);
         S := Copy(Line, 5, 4);
         Y := StrToInt(S);
         DateSequence(D, M, Y, ICD);     // initial conditions date
         for I:=1 to 5 do begin
            J := 8 + (I-1)*13 + 1;
            S := TrimRight(TrimLeft(Copy(Line, J, 13)));   // no leading/trailing blanks
            A[I] := StrToFloat(S);
            if (A[I] < -9998) then A[I] := -9999.999;
         end;
         BI.SeqNum := ICD;
         BI.USZM   := A[1];
         BI.LSZM   := A[2];
         BI.GZM    := A[3];
         BI.Surf   := A[4];
         BI.Snow   := A[5];
         BCond.Add(BI);
       end;
    end;
    CloseFile(F);
  except
    CloseFile(F);
    exit;
  end;

  Result := TRUE;
end;

//--------------------------------------------------------------------------
function WriteBoundaryFile(FileName : string;
                           var BCond : TBoundaryInfo) : boolean;
var
  K, D, M, Y : longint;
  S, SD, SM, SY, Line   : string;
  S1, S2, S3, S4, S5    : string;
  F       : TextFile;
  BI      : TBoundInfo;
begin
  Result := FALSE;

  //
  // Open the boundary conditions file
  //
  try
    AssignFile(F, FileName);
  except
    exit;
  end;

  try
    ReWrite(F);
    K := 0;
    Writeln(F, BCond.HeaderLine1);
    Writeln(F, BCond.HeaderLine2);
    while (K < BCond.Count) do begin
       BI := TBoundInfo(BCond[K]);
       SequenceDate(D, M, Y, BI.SeqNum);
       S := Copy(Line, 1, 2);
       str(D:2, SD);
       str(M:2, SM);
       str(Y:4, SY);
       S1 := FormatFloat(' 0.000000E+00;-0.000000E+00', BI.USZM);
       S2 := FormatFloat(' 0.000000E+00;-0.000000E+00', BI.LSZM);
       S3 := FormatFloat(' 0.000000E+00;-0.000000E+00', BI.GZM);
       S4 := FormatFloat(' 0.000000E+00;-0.000000E+00', BI.Surf);
       S5 := FormatFloat(' 0.000000E+00;-0.000000E+00', BI.Snow);
       Writeln(F, SD, SM, SY, S1, S2, S3, S4, S5);
       inc(K);
    end;
    CloseFile(F);
  except
    CloseFile(F);
    exit;
  end;

  Result := TRUE;
end;

//--------------------------------------------------------------------------
// Get start/end dates from the measured flow data file.
//
function GetFLWStartEnd(FlwFileName : string;
                        var First, Last : longint) : boolean;
var
   D, M, Y  : integer;
   S, Line  : string;
   Fin      : TextFile;
begin
   Result := FALSE;     // default in case of early exit
   DateSequence(1, 1, 9999, First);
   DateSequence(1, 1,    1, Last);

   if (LENGTH(FlwFileName) = 0) then exit;
   try
      AssignFile(Fin, FlwFileName);
      Reset(Fin);
   except
      exit;
   end;

   try
      Readln(Fin);
      Readln(Fin);

      Readln(Fin, Line);
      S := Copy(Line, 1, 2);
      D := StrToInt(S);
      S := Copy(Line, 3, 2);
      M := StrToInt(S);
      S := Copy(Line, 5, 4);
      Y := StrToInt(S);
      DateSequence(D, M, Y, First);

      while (not eof(Fin)) do begin
         Readln(Fin, Line);
         S := Copy(Line, 1, 2);
         D := StrToInt(S);
         S := Copy(Line, 3, 2);
         M := StrToInt(S);
         S := Copy(Line, 5, 4);
         Y := StrToInt(S);
         DateSequence(D, M, Y, Last);
      end;

      CloseFile(Fin);
   except
      CloseFile(Fin);
      exit;
   end;

   Result := TRUE;
end;

//--------------------------------------------------------------------------
//  Read the flow data from the specified text file.
//  It will attempt to read the data for the entire specified period.  If it
//  cannot it will fail and just return FALSE.
//
function ReadFlowFile(FlowFileName : string;
                      FSD, FED     : longint;
                      var FlowData : TMyArrayOfSingle) : boolean;
var
   I, J, K, D, M, Y, Seq, SSeq, ESeq  : longint;
   Flw      : single;
   Line, S  : string;
   Fin      : TextFile;
begin
   Result := FALSE;     // default in case of early exit

   if (not FileExists(FlowFileName)) then begin
      WriteErrMsg('Error: File ' + FlowFileName + ' does not exist!');
      exit;
   end;

   //
   // Read the start/end dates.  Just use the function already created
   // for this purpose.
   //
   if (not GetFLWStartEnd(FlowFileName, SSeq, ESeq)) then exit;
   if ((SSeq > FSD) OR (ESeq < FED)) then begin
      WriteErrMsg('Error: Not enough data in file ' + FlowFileName + '!');
      exit;
   end;

   //
   // Open the input flow data file
   //
   try
      AssignFile(Fin, FlowFileName);
      Reset(Fin);
   except
      WriteErrMsg('Error attempting to read data from ' + FlowFileName);
      exit;
   end;

   //
   // Skip lines we don't need
   //
   try
      Readln(Fin);
      Readln(Fin);
   except
      CloseFile(Fin);
      WriteErrMsg('Error attempting to read data from ' + FlowFileName);
      exit;
   end;

   //
   // Read the data needed for comparison
   //   Flow values in the file are centimeters over the land surface.
   //   Convert to cubic meters per second.
   //
   I := FED - FSD + 1;

   FlowData.SetSize(I);
   for J:=0 to I-1 do FlowData[J] := -9999.99;

   try
      while (not eof(Fin)) do begin
          Readln(Fin, Line);
          S := Copy(Line, 1, 2);
          D := StrToInt(S);
          S := Copy(Line, 3, 2);
          M := StrToInt(S);
          S := Copy(Line, 5, 4);
          Y := StrToInt(S);
          DateSequence(D, M, Y, Seq);
          J := Seq - FSD;

          S := Copy(Line, 9, 11);
          Val(S, Flw, K);                   // Flw is in cm
          if (K = 0) then FlowData[J] := Flw;
      end;
   except
      CloseFile(Fin);
      WriteErrMsg('Error attempting to read data from ' + FlowFileName);
      exit;
   end;

   CloseFile(Fin);

   Result := TRUE;
end;


//--------------------------------------------------------------------------
// Get start and end dates from the MET file.
//
function GetMetStartEnd(MetFileName : string;
                        var First, Last : longint) : boolean;
var
   D, M, Y, Seq  : integer;
   S, Line       : string;
   Fin           : TextFile;
begin
   Result := FALSE;     // default in case of early exit
   DateSequence(1, 1, 9999, First);
   DateSequence(1, 1,    1, Last);

   if (LENGTH(MetFileName) = 0) then exit;
   try
      AssignFile(Fin, MetFileName);
      Reset(Fin);
   except
      exit;
   end;

   try
      Readln(Fin);
      Readln(Fin);
      while (not eof(Fin)) do begin
          Readln(Fin, Line);
          if (Length(Line) > 15) then begin
             S := Copy(Line, 1, 2);
             D := StrToInt(S);
             S := Copy(Line, 3, 2);
             M := StrToInt(S);
             S := Copy(Line, 5, 4);
             Y := StrToInt(S);
             DateSequence(D, M, Y, Seq);
             if (Seq < First) then First := Seq;
             if (Seq > Last) then Last := Seq;
          end;
      end;
      CloseFile(Fin);
   except
      CloseFile(Fin);
      exit;
   end;

   Result := TRUE;
end;


//--------------------------------------------------------------------------
//  Read the meteorological data from the specified text file.
//  It will attempt to read the data for the entire specified period.  If it
//  cannot it will fail and just return FALSE.
//
function ReadMetFile(FName       : string;
                     First, Last : longint;
                     var MetData : TMetData) : boolean;
var
   I, Dy, Mn, Yr, LNum : longint;
   Seq, SSeq, ESeq     : longint;
   S, S2, Line         : string;
   Fin  : TextFile;
begin
   Result := FALSE;     // default in case of early exit

   if (not GetMetStartEnd(FName, SSeq, ESeq)) then begin
      WriteErrMsg('Error: Not enough data in file ' + FName + '!');
      exit;
   end;

   I := ESeq - SSeq + 1;
   MetData[1].SetSize(I);

   //
   // Open the input met data file
   //
   try
      AssignFile(Fin, FName);
      Reset(Fin);
   except
      WriteErrMsg('Error attempting to open met data file ' + FName);
      exit;
   end;

   //
   // Read the file.
   //
   LNum := 1;
   try
     Readln(Fin);
     inc (LNum);
     Readln(Fin);
     inc (LNum);
     while (not eof(Fin)) do begin
        Readln(Fin, Line);
        if (Length(Line) > 15) then begin
           Dy := StrToInt(Copy(Line, 1, 2));
           Mn := StrToInt(Copy(Line, 3, 2));
           Yr := StrToInt(Copy(Line, 5, 4));
           DateSequence(Dy, Mn, Yr, Seq);
           I := Seq - First;
           if (I >= 0) then begin                 // on/after desired start date
              if (I <= Last-First) then begin     // on/before desired end date
                 S := Copy(Line, 9, 99);
                 S2 := TRIM(Copy(S, 1, 5));
                 MetData[1][I] := StrToInt(S2);    // TMin - tenths of C
                 S2 := TRIM(Copy(S, 6, 5));
                 MetData[2][I] := StrToInt(S2);    // TMax - tenths of C
                 S2 := TRIM(Copy(S, 11, 5));
                 MetData[3][I] := StrToInt(S2);    // Prec - tenths of mm
              end;
           end;
        end;
        inc (LNum);
     end;
     CloseFile(Fin);

   except
     Line := 'Error at line ' + IntToStr(LNum) + ' of met data file ' + FName;
     WriteErrMsg(Line);
     CloseFile(Fin);
     exit;
   end;

   Result := TRUE;
end;


end.
