unit FilterSunMoonUnit;

{$mode ObjFPC}{$H+}

interface

uses
  Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls,
  Buttons, ExtCtrls, ComCtrls;

type

  { TFilterSunMoonForm }

  TFilterSunMoonForm = class(TForm)
    Button1: TButton;
    CloudAlgorithmCutoffEdit: TLabeledEdit;
    CorrectionForAgingSQMEdit: TLabeledEdit;
    CorrectionForWeatherproofCoverEdit: TLabeledEdit;
    GalacticLatitudeElevationAngleEdit: TLabeledEdit;
    MaxMPSASAllowedEdit: TLabeledEdit;
    MoonElevationAngleCutoffEdit: TLabeledEdit;
    ParametersGroupBox: TGroupBox;
    ProgressGroupBox: TGroupBox;
    HelpGroupBox: TGroupBox;
    Memo1: TMemo;
    ProgressBar1: TProgressBar;
    ProgressMemo: TMemo;
    SolarElevationAngleCutoffEdit: TLabeledEdit;
    SourceFileDialog: TOpenDialog;
    SourceFileButton: TBitBtn;
    SourceFileEdit: TEdit;
    SparseCutoffEdit: TLabeledEdit;
    StatusBar1: TStatusBar;
    procedure Button1Click(Sender: TObject);
    procedure CloudAlgorithmCutoffEditChange(Sender: TObject);
    procedure CorrectionForAgingSQMEditChange(Sender: TObject);
    procedure CorrectionForWeatherproofCoverEditChange(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure GalacticLatitudeElevationAngleEditChange(Sender: TObject);
    procedure MaxMPSASAllowedEditChange(Sender: TObject);
    procedure MoonElevationAngleCutoffEditChange(Sender: TObject);
    procedure SolarElevationAngleCutoffEditChange(Sender: TObject);
    procedure SourceFileButtonClick(Sender: TObject);
    procedure SparseCutoffEditChange(Sender: TObject);
    procedure ProgressMessage(MessageText: String);
    procedure ProgressParameterMessage(MessageText: String);

  private

  public

  end;

var
  FilterSunMoonForm: TFilterSunMoonForm;

implementation

{ TFilterSunMoonForm }
uses
  appsettings,
  header_utils,
  Unit1;

Const
Section='FilterSunMoonTool';

var

  solar_elev_cutoff, lunar_elev_cutoff, cloud_cutoff, milky_way_cutoff, mags_max_allowed   : double;
  cover_correction   : double;
  aging_per_year     : double;
  cutoff_limit       : integer;
  ReadingSettings    : Boolean = False;  //Flag that suppresses saving changed entry while reading settings.
  SourceFileName: String;
  fdata,
  fdataout1,
  fdataout2,
  fdataout3          : TextFile;
  SQM_Location       : String;
  right_ascension,SQM_Lat,SQM_Long,J2000_days,J2000_days_first: Double;
  //Galactic_Elevation,
  Galactic_Lat,Galactic_Long: Double;
  RSE                : Double;
  dMsas,
  dVolts,dCelsius: double;
  dMoonPhase,dMoonElev,dMoonIllum,dSunElev: double;
  //msas_Sum,msas_Count
  msas_Avg           : double;
  dStatus            : integer;
  Udate, Utime, Ldate, Ltime : TDateTime;

procedure TFilterSunMoonForm.ProgressMessage(MessageText: String);
begin
  ProgressMemo.Append(MessageText);
  Application.ProcessMessages;
end;

procedure TFilterSunMoonForm.ProgressParameterMessage(MessageText: String);
begin
  WriteLn(fdataout3,MessageText);
  ProgressMemo.Append(MessageText);
  Application.ProcessMessages;
end;

procedure TFilterSunMoonForm.Button1Click(Sender: TObject);
var
  //i,j,k
  m,
  minutes_since_3pm : integer;
  //dUyear,dUmonth,dUday,dUhour,dUminute,dUseconds,
  //dyear,dmonth,dday,dhour,dminute,dseconds
  //dMsas_Corr,
  NameIn,NameOut1,NameOut2,NameOut3    : String;
  Str                                 : String;
  //nfile,slength,
  days: integer;
  //,ret2,Start,Last
  //ret: integer;
  //len2,len3 : integer;
  //FoundOne           : integer;
  q,r,s                 : integer;
  //kk,jj                 : integer;
  grid               : array[0..460, 0..288] of integer;
  xLoc,yLoc: integer;
  //yAbove1,yBelow1,
  //yAbove2,yBelow2            : integer;
  xx,yy             : array[0..12] of integer;
  x,y,sumZero            : integer;

  //sd1,sd2,
  mean1,mean2,dMsasSum1,dMsasMax1,dMsasMin1 : double;
  dMsasSum2,dMsasMax2,dMsasMin2 : double;

//  Termination        : &goto;

  pieces: TStringList;

  teststring: string;

begin
  pieces := TStringList.Create;
  pieces.Delimiter := ',';
  pieces.StrictDelimiter := True; //Do not parse spaces.


  ProgressMemo.Clear;

    {$I+}    // Use exceptions to catch errors (this is the default so not absolutely requried)


{ Run this program by specifying the program name, followed by seven parameters:
 *   1) Name of a file of SQM data which has been output from 'addSQMattributes' or from UDMs option for sun-moon-clouds }
     StatusMessage('Running FilterSunMoon tool.');

      //Check validity of inputs

    { writeln(format(' The input csv filename on reading is: -%s- which has %d characters. ',[ParamStr(1), len2-1]));}
      NameIn:= SourceFileEdit.Text;
      If ((Length(NameIn) = 0)) then begin
          StatusMessage(' Input file not defined');
          Exit;
      end;
      ProgressMessage(format(' The input csv filename is: %s',[NameIn]));
      ProgressMessage(format(' The solar elevation angle cutoff is: %.6f',[solar_elev_cutoff]));
      ProgressMessage(format(' The lunar elevation angle cutoff is: %.6f',[lunar_elev_cutoff]));
      ProgressMessage(format(' The cloud parameter cutoff is: %.6f',[cloud_cutoff]));
      ProgressMessage(format(' The Galactic latitude angle cutoff is: %.6f',[milky_way_cutoff]));
      ProgressMessage('Note that we filter out measurements taken within that angle of the zenith, both positive and negative angle.');
      { insure that the milky_way_cutoff value is positive, to accommodate our algorithm later }
      milky_way_cutoff := abs(milky_way_cutoff);
      ProgressMessage(format(' The SQM cover correction value that we subtract is: %.6f',[cover_correction]));
      ProgressMessage(format(' The SQM aging adjustment parameter is: %.6f',[aging_per_year]));
      ProgressMessage(format(' The maximum Mags per arc second squared value allowed is: %.6f',[mags_max_allowed]));
      ProgressMessage(format(' The sparse cutoff value is: %d',[cutoff_limit]));


    { Open the input file }
    ProgressMessage(' About to open the Input csv Data File');
    AssignFile(fdata, NameIn);    // Set the name of the file that will be read
    try
      reset(fdata);
    except
      ProgressMessage(Format('Failed to open the csv Data File: %s',[NameIn]));
      Exit;
    end;
    ProgressMemo.Append(Format('Opened the Input csv Data File: %s',[NameIn]));


{ Open an output file to hold the output data file 1, tack on '_Dense.csv' }
    NameOut1 := NameIn + '_Dense.csv';
    ProgressMessage(format('The First Output Data Filename is %s ',[NameOut1]));
    AssignFile(fdataout1, NameOut1);    // Set the name of the file that will be created
    try
      Rewrite(fdataout1);
    except
      ProgressMessage(Format('Failed to open the first output data file: %s',[NameOut1]));
      Exit;
    end;
    ProgressMessage(Format('Opened the First Output Data File ',[NameOut1]));

{ Open an output file to hold the output data file 2, tack on '_Sparse.csv' }
    NameOut2 := NameIn + '_Sparse.csv';
    ProgressMessage(format('The Second Output Data Filename is %s ',[NameOut2]));
    AssignFile(fdataout2, NameOut2);    // Set the name of the file that will be created
    try
      Rewrite(fdataout2);
    except
      ProgressMessage(Format('Failed to open the second output data file: %s',[NameOut2]));
      Exit;
    end;
    ProgressMessage(Format('Opened the First Output Data File ',[NameOut2]));

{ Open an output file to hold the parameters and other text information }
{ tack on '_parameters.txt' }
    NameOut3 := NameIn + '_parameters.txt';
    ProgressMessage(format('The third Output Data Filename is %s ',[NameOut3]));
    AssignFile(fdataout3, NameOut3);    // Set the name of the file that will be created
    try
      Rewrite(fdataout3);
    except
      ProgressMessage(Format('Failed to open the second output data file: %s',[NameOut2]));
      Exit;
    end;

  ProgressMessage(Format('Opened the Text Parameter Output File.',[NameOut3]));

   WriteLn(fdataout3,' ');
   WriteLn(fdataout3,Format(' The input csv filename is: %s',[NameIn]));
   WriteLn(fdataout3,Format(' The solar elevation angle cutoff is: %.6f',[solar_elev_cutoff]));
   WriteLn(fdataout3,Format(' The lunar elevation angle cutoff is: %.6f',[lunar_elev_cutoff]));
   WriteLn(fdataout3,Format(' The cloud parameter cutoff is: %.6f',[cloud_cutoff]));
   WriteLn(fdataout3,Format(' The Galactic latitude angle cutoff is: %.6f',[milky_way_cutoff]));
   WriteLn(fdataout3,'   Note that we filter out measurements taken within that angle of the zenith, both positive and negative angle.');
   WriteLn(fdataout3,Format(' The SQM cover correction value that we subtract is: %.6f',[cover_correction]));
   WriteLn(fdataout3,Format(' The SQM aging adjustment parameter is: %.6f',[aging_per_year]));
   WriteLn(fdataout3,Format(' The maximum Mags per arc second squared value allowed is: %.6f',[mags_max_allowed]));
   WriteLn(fdataout3,Format(' The sparse cutoff value is: %d',[cutoff_limit]));
   WriteLn(fdataout3,' ');
   WriteLn(fdataout3,' ');

   { initialize the grid array }
     for yLoc := 0 to 459 do
     begin
       for xLoc := 0 to 287 do
       begin
          grid[yLoc][xLoc] := 0;
       end;
     end;

    { initialize the sum for mean calculation later}
    dMsasSum1 := 0;
    dMsasSum2 := 0;

    { Write a header record to each of the output files }
    WriteLn(fdataout1,'Location,Lat,Long,UTC_Date,UTC_Time,Local_Date,Local_Time,Celsius,Volts,Msas,Status,MoonPhase,MoonElev,MoonIllum,SunElev,MinSince3pmStdTime,Msas_Avg,NightsSince_1118,RightAscensionHr,Galactic_Lat,Galactic_Long,J2000days,ResidStdErr');
    WriteLn(fdataout2,'Location,Lat,Long,UTC_Date,UTC_Time,Local_Date,Local_Time,Celsius,Volts,Msas,Status,MoonPhase,MoonElev,MoonIllum,SunElev,MinSince3pmStdTime,Msas_Avg,NightsSince_1118,RightAscensionHr,Galactic_Lat,Galactic_Long,J2000days,ResidStdErr');

    { Read the data file }
    { Read the first header record and throw it away }
    { Note that the string read format statement, reads up to the first carriage return in the input file, then reads the carriage return itself }
    //Read first line
    Readln(fdata, Str);

{ m counts the total number of SQM records that we read }
    m := 0;
{ q counts the number of valid SQM records that we end up with, after filtering for sun, moon, clouds, milky way, max allowed }
   q := 0;
{ initialize the min and max dMsas values }
   dMsasMax1 := -10.;
   dMsasMin1 := 25.;

    { Note that the string read format statement listed first, reads up to the first comma in the input file }
    { read date and times as strings and then pull out the desired year, month, day, hour, minute, second values }
    while not eof(fdata) do  begin

     Readln(fdata, Str);
     pieces.DelimitedText := Str;
     SQM_Location:=pieces[0];
     SQM_Lat:=StrToFloat(pieces[1]);
     SQM_Long:=StrToFloat(pieces[2]);
     teststring:=pieces[3];
     Udate:=StrToDate(pieces[3],'yyyy-mm-dd','-');
     Utime:=StrToTime(pieces[4]);
     Ldate:=StrToDate(pieces[5],'yyyy-mm-dd','-');
     Ltime:=StrToTime(pieces[6]);
     dCelsius:=StrToFloat(pieces[7]);
     dVolts:=StrToFloat(pieces[8]);
     dMsas:=StrToFloat(pieces[9]);
     dStatus:=StrToInt(pieces[10]);
     dMoonPhase:=StrToFloat(pieces[11]);
     dMoonElev:=StrToFloat(pieces[12]);
     dMoonIllum:=StrToFloat(pieces[13]);
     dSunElev:=StrToFloat(pieces[14]);
     minutes_since_3pm:=StrToInt(pieces[15]);
     msas_Avg:=StrToFloat(pieces[16]);
     days:=StrToInt(pieces[17]);
     right_ascension:=StrToFloat(pieces[18]);
     Galactic_Lat:=StrToFloat(pieces[19]);
     Galactic_Long:=StrToFloat(pieces[20]);
     J2000_days:=StrToFloat(pieces[21]);
     RSE:=StrToFloat(pieces[22]);

      { increment the counter }
    m := m +1;
{ get the first day of the data set. We use this later to calculate the aging of the SQM }
    if m = 1 then begin
        J2000_days_first := J2000_days;
      end;
{ apply the correction for the SQM weatherproof cover }
   dMsas := dMsas - cover_correction;
{ apply the aging correction for the SQM }
   dMsas := dMsas - ((J2000_days - J2000_days_first) * aging_per_year/365.0);
{ Apply filters }
{ The milky way filter is different than the other filters. Earlier, we took the absolute value of the MW filter value to eliminate a problem if the
 * user had entered a negative MW cutoff value. Here we include
 * a) any data points which are greater than or equal to the positive MW filter value and Also,
 * b) we include any data points which are less than or equal to the negative MW filter value.
 * This therefore eliminates any data points which are within the MW filter value of the zenith }
{ make sure we don't go to zero or negative }
    if dMsas < 0.1 then { if here we are throwing out this point,which is very close to zero } continue else
    if dSunElev >= solar_elev_cutoff then continue else
    if dMoonElev >= lunar_elev_cutoff then continue else
    if RSE >= cloud_cutoff then continue else
    if dMsas >= mags_max_allowed then continue else
{ note that we use > and < in the next statement, which enforces our keeping of any data >= and <= the specified MW cutoff }
    if ((Galactic_Lat < milky_way_cutoff)  and  (Galactic_Lat > (milky_way_cutoff * -1.0))) then continue;

    begin
           { if here, we have a valid record, so increment our count and go read another }
           q := q +1;
{ sum the dMsas values to allow calculation of the mean later }
        dMsasSum1 := dMsasSum1 + dMsas;
{ track the min and max values }
        if dMsas > dMsasMax1 then dMsasMax1:= dMsas;
        if dMsas < dMsasMin1 then dMsasMin1:= dMsas;
{ we add this valid value to the 2D 'grid' array }
{ figure out where to stash this value }
{ we use 288 bins in the x-dimension which has a range of 1440 minutes (24 hours).
 * So each bin is 5 minutes wide, beginning at 0 minutes. Use the nearest integer to find the correct bin,
 * and subtract one for c-language arrays (which begin at zero). }
       xLoc := trunc((double(minutes_since_3pm)*288.0/2880.0) + 0.5) - 1;
       if xLoc < 0 then xLoc:= 0;
       if xLoc > 287 then xLoc:= 287;
{ we use 460 bins in the y-dimension. use the nearest integer to find the correct bin,
 * we consider valid values from msas of 0.0 to 23.0, which is a range of 23.0
 * and subtract one for c-language arrays (which begin at zero). }
       yLoc := trunc(((dMsas - 0.0)*460.0/23.0) + 0.5) - 1;
       if yLoc < 0 then yLoc:= 0;
       if yLoc > 459 then yLoc:= 459;
{ store this value in the grid array }
       grid[yLoc][xLoc] := grid[yLoc][xLoc] + 1;
      end;
    end;

  { we reached the end of the input file, we know how many valid records are present }
   ProgressMessage(format(' End of first read loop. We read in -%d- records.',[m]));
   ProgressMessage(format(' Of those, -%d- records pass the sun, moon, clouds, milky way and max value allowed filtering criteria.',[q]));
   ProgressMessage('Proceeding to apply the sparseness filter...');
   ProgressMessage('');
   WriteLn(fdataout3,Format(' End of first read loop. We read in -%d- records.',[m]));
   WriteLn(fdataout3,Format(' Of those, -%d- records pass the sun, moon, clouds, milky way and max value allowed filtering criteria.',[q]));
   WriteLn(fdataout3,' Proceeding to apply the sparseness filter...');
   WriteLn(fdataout3,'');

{ calculate the mean of those records which pass the filter so far }
   mean1 := dMsasSum1/double(q);

 { set up integer r which counts the number of records that we write to the first output file }
   r := 0;

 { set up integer s which counts the number of records that we write to the second (sparse) output file }
   s := 0;

{ initialize the min and max dMsas values for the dense group }
   dMsasMax2 := -10.;
   dMsasMin2 := 25.;

{ first rewind the input data file }
{ we are at the end of the input .csv file. Position it at the beginning again}
  FileSeek(GetFileHandle(fdata),fsFromBeginning,0);
{ Read the first header record and throw it away }
{ Note that the string read format statement, reads up to the first carriage return in the input file, then reads the carriage return itself }
 Readln(fdata, Str);
{ this is the begining of the second reading loop }
{ r counts the number of records that we write out }
{ Read a record }
{ Note that the string read format statement listed first, reads up to the first comma in the input file }
{ read date and times as strings and then pull out the desired year, month, day, hour, minute, second values }
    while not eof(fdata) do  begin
      Readln(fdata, Str);
      pieces.DelimitedText := Str;
      SQM_Location:=pieces[0];
      SQM_Lat:=StrToFloat(pieces[1]);
      SQM_Long:=StrToFloat(pieces[2]);
      Udate:=StrToDate(pieces[3],'yyyy-mm-dd','-');
      Utime:=StrToTime(pieces[4]);
      Ldate:=StrToDate(pieces[5],'yyyy-mm-dd','-');
      Ltime:=StrToTime(pieces[6]);
      dCelsius:=StrToFloat(pieces[7]);
      dVolts:=StrToFloat(pieces[8]);
      dMsas:=StrToFloat(pieces[9]);
      dStatus:=StrToInt(pieces[10]);
      dMoonPhase:=StrToFloat(pieces[11]);
      dMoonElev:=StrToFloat(pieces[12]);
      dMoonIllum:=StrToFloat(pieces[13]);
      dSunElev:=StrToFloat(pieces[14]);
      minutes_since_3pm:=StrToInt(pieces[15]);
      msas_Avg:=StrToFloat(pieces[16]);
      days:=StrToInt(pieces[17]);
      right_ascension:=StrToFloat(pieces[18]);
      Galactic_Lat:=StrToFloat(pieces[19]);
      Galactic_Long:=StrToFloat(pieces[20]);
      J2000_days:=StrToFloat(pieces[21]);
      RSE:=StrToFloat(pieces[22]);

     { apply the correction for the SQM weatherproof cover }
   dMsas := dMsas - cover_correction;
{ apply the aging correction for the SQM }
   dMsas := dMsas - ((J2000_days - J2000_days_first) * aging_per_year/365.0);
{ Apply filters }
{ The milky way filter is different for northern and southern hemispheres }
{ If we have a positive cutoff value for the milky way, we assume that we are in the northern hemisphere, and we throw out any values less than or equal to that positive value }
{ If we have a negative cutoff value for the milky way, we assume that we are in the southern hemisphere, and we throw out any values greater than or equal to that negative value }
{ make sure we don't go to zero or negative }
    if dMsas < 0.1 then continue else{ if here we are throwing out this point,which is very close to zero }
    if dSunElev >= solar_elev_cutoff then continue else
    if dMoonElev >= lunar_elev_cutoff then continue else
    if RSE >= cloud_cutoff then continue else //no
    if dMsas >= mags_max_allowed  then continue;
{ note that we use > and < in the next statement, which enforces our keeping of any data >= and <= the specified MW cutoff }
    if ((Galactic_Lat < milky_way_cutoff)  and  (Galactic_Lat > (milky_way_cutoff * -1.0))) then continue;

    begin
        { Now we do the desired work of this program - namely we check to see if this data point
         * is in a sparse location in the scatterplot }
        { Figure out which cell of the grid array to evaluate }
        { we use 288 bins in the x-dimension which has a range of 2880 minutes (24 hours). use the nearest integer to find the correct bin,
         * and subtract one for c-language arrays (which begin at zero). }
               xLoc := trunc((double(minutes_since_3pm)*288./2880.0) + 0.5) - 1;
               if xLoc < 0 then xLoc:= 0;
               if xLoc > 287 then xLoc:= 287;
        { we use 460 bins in the y-dimension. use the nearest integer to find the correct bin,
         * we consider valid values from msas of 0.0 to 23.0, which is a range of 23.0
         * and subtract one for c-language arrays (which begin at zero). }
               yLoc := trunc(((dMsas - 0.0)*460./23.0) + 0.5) - 1;
               if yLoc < 0 then yLoc:= 0;
               if yLoc > 459 then yLoc:= 459;
        { Check the 12 grid cells 3 above and 3 below this one, and the 3 to left column and 3 to right column. If the majority of the 12 are empty, we consider this target point to be sparse.  If there is a tie, we call it dense. }
       yy[0] := yLoc -3;
       yy[1] := yLoc -2;
       yy[2] := yLoc -1;
       yy[3] := yLoc -1;
       yy[4] := yLoc -1;
       yy[5] := yLoc;
       yy[6] := yLoc;
       yy[7] := yLoc +1;
       yy[8] := yLoc +1;
       yy[9] := yLoc +1;
       yy[10] := yLoc +2;
       yy[11] := yLoc +3;
       for y := 0 to 11 do begin
          if yy[y] < 0 then yLoc:= 0;
          if yy[y] > 459 then yLoc:= 459;
       end;
       xx[0] := xLoc;
       xx[1] := xLoc;
       xx[2] := xLoc -1;
       xx[3] := xLoc;
       xx[4] := xLoc +1;
       xx[5] := xLoc -1;
       xx[6] := xLoc +1;
       xx[7] := xLoc -1;
       xx[8] := xLoc;
       xx[9] := xLoc +1;
       xx[10] := xLoc;
       xx[11] := xLoc;
       for x := 0 to 11 do begin
          if xx[x] < 0 then xLoc:= 0;
          if xx[x] > 287 then xLoc:= 287;
       end;
       sumZero := 0;
{ sum the counts in the cells }
       for y := 0 to 11 do
         sumZero := sumZero + grid[yy[y]][xx[y]];

{ we have 12 points in the array around the target point. If the sum is less than or equal to the cutoff_limit, we have a sparse point }
         if sumZero <= cutoff_limit then begin
            { if here, we have a sparse record, so increment our 's' count and write out the record to the second output file}
            s := s +1;

            { print out the sparse record to the second output file }
            { Note, we need to output two numbers for each of hour, minute and seconds. If only one digit is output,
               Spotfire, and other programs, will take the digit as a ten's value, insted of a one's value}

            //Write(fdataout2, Format('%d, %d,',[sumZero,cutoff_limit]));
            Write(fdataout2, Format('%s,',[SQM_Location]));
            Write(fdataout2, Format('%12.7f,%12.7f,',[SQM_Lat, SQM_Long]));
            Write(fdataout2, Format('%s,%s,%s,%s,',[FormatDateTime('yyyy-mm-dd',Udate), FormatDateTime('hh:nn:ss',Utime) , FormatDateTime('yyyy-mm-dd',Ldate), FormatDateTime('hh:nn:ss',Ltime)]));
            Write(fdataout2, Format('%.1f,%.2f,%.2f,%1d,',[dCelsius, dVolts, dMsas, dStatus]));
            Write(fdataout2, Format('%.1f,%.3f,%.1f,%.3f,',[dMoonPhase, dMoonElev, dMoonIllum, dSunElev]));
            WriteLn(fdataout2, Format('%.4d,%.6f,%.4d,%12.7f,%12.7f,%10.5f,%.6f,%.6f',[minutes_since_3pm, msas_Avg, days, right_ascension,  Galactic_Lat, Galactic_Long, J2000_days, RSE]));
         end else begin
              { if here, we have a valid dense record, so increment our count and write out the record }
              r := r +1;

              { sum the dMsas values to allow calculation of the mean of these records that are considered dense, later }
              dMsasSum2 := dMsasSum2 + dMsas;
              { track the min and max values }
              if dMsas > dMsasMax2 then dMsasMax2:= dMsas;
              if dMsas < dMsasMin2 then dMsasMin2:= dMsas;

              { Write out this valid record to the output file }
              { Note, we need to output two numbers for each of hour, minute and seconds. If only one digit is output,
                 Spotfire, and other programs, will take the digit as a ten's value, insted of a one's value}
              //Write(fdataout1, Format('%d, %d,',[sumZero,cutoff_limit]));
              Write(fdataout1, Format('%s,',[SQM_Location]));
              Write(fdataout1, Format('%12.7f,%12.7f,',[SQM_Lat, SQM_Long]));
              Write(fdataout1, Format('%s,%s,%s,%s,',[FormatDateTime('yyyy-mm-dd',Udate), FormatDateTime('hh:nn:ss',Utime) , FormatDateTime('yyyy-mm-dd',Ldate), FormatDateTime('hh:nn:ss',Ltime)]));
              Write(fdataout1, Format('%.1f,%.2f,%.2f,%1d,',[dCelsius, dVolts, dMsas, dStatus]));
              Write(fdataout1, Format('%.1f,%.3f,%.1f,%.3f,',[dMoonPhase, dMoonElev, dMoonIllum, dSunElev]));
              WriteLn(fdataout1, Format('%.4d,%.6f,%.4d,%12.7f,%12.7f,%10.5f,%.6f,%.6f',[minutes_since_3pm, msas_Avg, days, right_ascension,  Galactic_Lat, Galactic_Long, J2000_days, RSE]));
        end;

        { this is the end of the if filter check on second read of the input file }
        end;
{ this is the end of the while loop on second read of the input file }
   end;
{ calculate the mean of those records which pass the sun, moon, MW, clouds and density filter }
mean2 := dMsasSum2/double(r);

ProgressParameterMessage('    ');
ProgressParameterMessage(format(' End of second loop.  We wrote out -%d- dense records to the _Dense.csv file.',[r]));
ProgressParameterMessage(format('                      We wrote out -%d- sparse records to the _Sparse.csv file.',[s]));
ProgressParameterMessage('    ');
ProgressParameterMessage('    ');
ProgressParameterMessage(' Msas statistics of the records that pass the sun, moon, milky way and clouds filter: ');
ProgressParameterMessage(format('     Mean= %.6f  Minimum= %.6f  Maximum= %.6f',[mean1, dMsasMin1, dMsasMax1]));
ProgressParameterMessage('          ');
ProgressParameterMessage(' Msas statistics of the records that pass the sun, moon, milky way, clouds and sparseness filter: ');
ProgressParameterMessage('     These are the records that we wrote into the _Dense.csv output file. ');
ProgressParameterMessage(format('     Mean= %.6f  Minimum= %.6f  Maximum= %.6f',[mean2, dMsasMin2, dMsasMax2]));
ProgressParameterMessage('          ');
ProgressParameterMessage('    ');

      if cover_correction > 0.0 then begin
  ProgressParameterMessage('            Attention Attention Attention ');
  ProgressParameterMessage(' Remember that the SQM Mags/Arc Second Squared data in the Dense and Sparse output files ');
  ProgressParameterMessage(' has already been corrected for the Weatherproof cover! ');
  ProgressParameterMessage(format(' We already subtracted the value of %.6f ',[cover_correction]));
  ProgressParameterMessage(' Don''t apply the correction again in subsequent processing! ');
  ProgressParameterMessage('            Attention Attention Attention ');
  ProgressParameterMessage('    ');
  ProgressParameterMessage('    ');
end;

if aging_per_year > 0.0 then begin
  ProgressParameterMessage('            Attention Attention Attention ');
  ProgressParameterMessage(' Remember that the SQM Mags/Arc Second Squared data in the Dense and Sparse output files ');
  ProgressParameterMessage(' has already been corrected for the Aging of the SQM! ');
  ProgressParameterMessage(format(' We already applied the aging per year value of %.6f ',[aging_per_year]));
  ProgressParameterMessage(' Don''t apply the correction again in subsequent processing! ');
  ProgressParameterMessage('            Attention Attention Attention ');
  ProgressParameterMessage('    ');
  ProgressParameterMessage('    ');
end;

{ insert a dummy statement to make the Termination label work }
//Termination: k=k+1;
CloseFile(fdata);
CloseFile(fdataout1);
CloseFile(fdataout2);
CloseFile(fdataout3);
ProgressMessage('Done.');

end;


procedure TFilterSunMoonForm.FormCreate(Sender: TObject);
begin
  {Load in saved values and defaults}

    ReadingSettings:=True;
    //Sun elevation angle cutoff in degrees, less than or equal to this value (recommend -18.)
    solar_elev_cutoff:=StrToFloatDef(vConfigurations.ReadString(Section,'SolarElevationCutoff'), -18.0);
    SolarElevationAngleCutoffEdit.Text:=Format('%0.2f',[solar_elev_cutoff]);

    //  Moon elevation angle cutoff in degree, less than or equal to this value (recommend -10.)
    lunar_elev_cutoff:=StrToFloatDef(vConfigurations.ReadString(Section,'LunarElevationCutoff'), -10.0);
    MoonElevationAngleCutoffEdit.Text:=Format('%0.2f',[lunar_elev_cutoff]);

    //  Cloud algorithm cutoff, less than or equal to this value (recommend 20.)
    cloud_cutoff:=StrToFloatDef(vConfigurations.ReadString(Section,'CloudAlgorithmCutoff'), 20.0);
    CloudAlgorithmCutoffEdit.Text:=Format('%0.2f',[cloud_cutoff]);

    //  Galactic Latitude elevation angle in degrees, cutoff to eliminate Milky Way from FOV, less than or equal to (recommend 0.)
    milky_way_cutoff:=StrToFloatDef(vConfigurations.ReadString(Section,'MilkyWayCutoff'), 0.0);
    GalacticLatitudeElevationAngleEdit.Text:=Format('%0.2f',[milky_way_cutoff]);

    //  Correction for weatherproof cover. this value is subtracted from the Mags/arc sec sq value (recommend 0.11)
    cover_correction:=StrToFloatDef(vConfigurations.ReadString(Section,'CoverCorrection'), 0.11);
    CorrectionForWeatherproofCoverEdit.Text:=Format('%0.2f',[cover_correction]);

    //  Correction for aging of the SQM. This values is the increase of brightness reading per year due to aging (0.018973938)
    //     This is based on our two-SQM assessment of aging of the SQM.
    //     = Max(0,Msas_CoverCorrected_MinZero - ((J2000days - First(J2000days)) * .018973938 / 365.))
    aging_per_year:=StrToFloatDef(vConfigurations.ReadString(Section,'AgingPerYear'), 0.018973938);
    CorrectionForAgingSQMEdit.Text:=Format('%0.9f',[aging_per_year]);

    //  Max Magnitudes per Arc Second Squared allowed, less than or equal to this value (recommend 22.0)
    mags_max_allowed:=StrToFloatDef(vConfigurations.ReadString(Section,'MagsMaxAllowed'), 22.0);
    MaxMPSASAllowedEdit.Text:=Format('%0.2f',[mags_max_allowed]);

    //  Sparse cutoff - the sum of 2D histogram values around the target point has to be equal or larger than this to be considered "dense" (recommend 15)
    cutoff_limit:=StrToIntDef(vConfigurations.ReadString(Section,'SparseCutoff'), 15);
    SparseCutoffEdit.Text:=Format('%d',[cutoff_limit]);

    ReadingSettings:=False;
end;

procedure TFilterSunMoonForm.FormShow(Sender: TObject);
begin
    SourceFileName:=RemoveMultiSlash(vConfigurations.ReadString(Section, 'SourceFileName', ''));
    SourceFileEdit.Text:=SourceFileName;

end;

procedure TFilterSunMoonForm.SolarElevationAngleCutoffEditChange(Sender: TObject
  );
begin
    if not ReadingSettings then begin
        solar_elev_cutoff:=StrToFloatDef(SolarElevationAngleCutoffEdit.Text,0);
        vConfigurations.WriteString(Section,'SolarElevationCutoff', Format('%0.2f',[solar_elev_cutoff]));
    end;
end;

procedure TFilterSunMoonForm.SourceFileButtonClick(Sender: TObject);
begin
  
  SourceFileDialog.FileName:=SourceFileName;
  if SourceFileDialog.Execute then begin
    SourceFileName:=RemoveMultiSlash(SourceFileDialog.FileName);
    SourceFileEdit.Text:=SourceFileName;
  end;

  //Save directory name in registry
  vConfigurations.WriteString(Section,'SourceFileName',SourceFileName);

end;

procedure TFilterSunMoonForm.MoonElevationAngleCutoffEditChange(Sender: TObject
  );
begin
    if not ReadingSettings then begin
        lunar_elev_cutoff:=StrToFloatDef(MoonElevationAngleCutoffEdit.Text,0);
        vConfigurations.WriteString(Section,'LunarElevationCutoff', Format('%0.2f',[lunar_elev_cutoff]));
    end;
end;

procedure TFilterSunMoonForm.CloudAlgorithmCutoffEditChange(Sender: TObject);
begin
    if not ReadingSettings then begin
        cloud_cutoff:=StrToFloatDef(CloudAlgorithmCutoffEdit.Text,0);
        vConfigurations.WriteString(Section,'CloudAlgorithmCutoff', Format('%0.2f',[cloud_cutoff]));
    end;
end;

procedure TFilterSunMoonForm.GalacticLatitudeElevationAngleEditChange(
  Sender: TObject);
begin
    if not ReadingSettings then begin
        milky_way_cutoff:=StrToFloatDef(GalacticLatitudeElevationAngleEdit.Text,0);
        vConfigurations.WriteString(Section,'MilkyWayCutoff', Format('%0.2f',[milky_way_cutoff]));
    end;
end;

procedure TFilterSunMoonForm.CorrectionForWeatherproofCoverEditChange(
  Sender: TObject);
begin
    if not ReadingSettings then begin
        cover_correction:=StrToFloatDef(CorrectionForWeatherproofCoverEdit.Text,0);
        vConfigurations.WriteString(Section,'CoverCorrection', Format('%0.2f',[cover_correction]));
    end;
end;

procedure TFilterSunMoonForm.CorrectionForAgingSQMEditChange(Sender: TObject);
begin
    if not ReadingSettings then begin
        aging_per_year:=StrToFloatDef(CorrectionForAgingSQMEdit.Text,0);
        vConfigurations.WriteString(Section,'AgingPerYear', Format('%0.9f',[aging_per_year]));
    end;
end;

procedure TFilterSunMoonForm.MaxMPSASAllowedEditChange(Sender: TObject);
begin
    if not ReadingSettings then begin
        mags_max_allowed:=StrToFloatDef(MaxMPSASAllowedEdit.Text,0);
        vConfigurations.WriteString(Section,'MagsMaxAllowed', Format('%0.2f',[mags_max_allowed]));
    end;
end;

procedure TFilterSunMoonForm.SparseCutoffEditChange(Sender: TObject);
begin
    if not ReadingSettings then begin
        cutoff_limit:=StrToIntDef(SparseCutoffEdit.Text,0);
        vConfigurations.WriteString(Section,'SparseCutoff', Format('%d',[cutoff_limit]));
    end;
end;


initialization
  {$I FilterSunMoonUnit.lrs}


end.

