unit dattimecorrect;

{$mode objfpc}

interface

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

type

  { Tdattimecorrectform }

  Tdattimecorrectform = class(TForm)
    CorrectButton: TBitBtn;
    FileSelectButton: TButton;
    InputFile: TLabeledEdit;
    OutGroupBox: TGroupBox;
    InGroupBox: TGroupBox;
    OutputFile: TLabeledEdit;
    OpenDialog1: TOpenDialog;
    StatusBar1: TStatusBar;
    TimeDifference: TLabeledEdit;
    procedure CorrectButtonClick(Sender: TObject);
    procedure FileSelectButtonClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { private declarations }
    procedure GetTimeDifference();
  public
    { public declarations }
  end;

var
  dattimecorrectform: Tdattimecorrectform;
  InFileName: String;
  Timediff: Int64;

implementation

uses
  appsettings //Required to read application settings (like locations).
  , dateutils //Required to convert logged UTC string to TDateTime
  , strutils //Required for checking lines in conversion file.
  , LazFileUtils //required for ExtractFileNameOnly
  ;

{ Tdattimecorrectform }

//Select file for correction
procedure Tdattimecorrectform.FileSelectButtonClick(Sender: TObject);
begin
  { Clear input filename in preparation for new selected filename}
  InputFile.Text:='';

  { Clear status bar }
  StatusBar1.Panels.Items[0].Text:='';

  OpenDialog1.Filter:='data log files|*.dat|All files|*.*';
  OpenDialog1.InitialDir := appsettings.LogsDirectory;

  { Get Input filename from user }
  if (OpenDialog1.Execute) then  begin
     InFileName:=OpenDialog1.FileName;
     InputFile.Text:=InFileName;

     { Create output file name }
     OutputFile.Text:= ExtractFilePath(InFileName) +
                       LazFileUtils.ExtractFileNameOnly (InFileName) +
                       '_TimeCorr' +
                       ExtractFileExt(InFileName);

     GetTimeDifference();

  end;
end;

procedure Tdattimecorrectform.FormCreate(Sender: TObject);
begin
  { Clear status bar }
  StatusBar1.Panels.Items[0].Text:='';
end;

{ Correct file }
procedure Tdattimecorrectform.CorrectButtonClick(Sender: TObject);
var
    InFile,OutFile: TextFile;
    Str: String;
    pieces: TStringList;

    index: Integer;

    UTCRecord :TDateTime;
    LocalRecord :TDateTime;
    ComposeString: String;
    //OutFileString: String;

    WriteAllowable: Boolean = True; //Allow output file to be written or not.

begin
     pieces := TStringList.Create;

     { Clear status bar }
     StatusBar1.Panels.Items[0].Text:='';


    //Start reading file.
    AssignFile(InFile, InFileName);
    AssignFile(OutFile, OutputFile.Text);
    if FileExists(OutputFile.Text) then begin
        if (MessageDlg('Overwrite existing file?','Do you want to overwrite the existing file?',mtConfirmation,[mbOK,mbCancel],0) = mrOK) then
            WriteAllowable:=True
        else
          WriteAllowable:=False;
      end;
    if WriteAllowable then begin
    {$I+}
    try
      Reset(InFile);

      Rewrite(OutFile); //Open file for writing

      StatusBar1.Panels.Items[0].Text:='Reading Input file';

      repeat
        // Read one line at a time from the file.
        Readln(InFile, Str);

        StatusBar1.Panels.Items[0].Text:='Processing : '+Str;

        //Ignore comment lines which have # as first character.
        if (AnsiStartsStr('#',Str)) then begin
          { Touch up time difference line }
          if AnsiStartsStr('# DL time difference (seconds)',Str) then
            WriteLn(OutFile,'# DL time difference (seconds): 0')
          else
           { Write untouched header line }
           WriteLn(OutFile,Str);
        end else begin
            //Separate the fields of the record.
            pieces.Delimiter := ';';
            pieces.DelimitedText := Str;

            //parse the fields, and convert as necessary.
            //Convert UTC string 'YYYY-MM-DDTHH:mm:ss.fff' into TDateTime
            UTCRecord:=ScanDateTime('yyyy-mm-dd"T"hh:nn:ss.zzz',pieces.Strings[0]);
            LocalRecord:=ScanDateTime('yyyy-mm-dd"T"hh:nn:ss.zzz',pieces.Strings[1]);
            //writeln(FormatDateTime('yyyy-mm-dd"T"hh:nn:ss.zzz',UTCRecord));

            { Correct UTC and Local times }
            ComposeString:=
                           FormatDateTime('yyyy-mm-dd"T"hh:nn:ss.zzz;',IncSecond(UTCRecord,-1*Timediff)) +
                           FormatDateTime('yyyy-mm-dd"T"hh:nn:ss.zzz',IncSecond(LocalRecord,-1*Timediff));

            { Compose remainderof string }
            for index:=2 to pieces.count-1 do begin
                           ComposeString:=ComposeString+';'+pieces.Strings[index];
            end;

            WriteLn(OutFile,ComposeString);

          end;
      until(EOF(InFile)); // EOF(End Of File) The the program will keep reading new lines until there is none.
      CloseFile(InFile);
      StatusBar1.Panels.Items[0].Text:='Finished';

    except
      on E: EInOutError do
      begin
       MessageDlg('Error', 'File handling error occurred. Details: '+E.ClassName+'/'+E.Message, mtError, [mbOK],0);
      end;
    end;
    Flush(OutFile);
    CloseFile(OutFile);

    end;//End of WriteAllowable check.

end;

// Get time difference listed in the input file
procedure Tdattimecorrectform.GetTimeDifference();
var
  InFile: TextFile;
  Str: String;
begin

  //Start reading file.
  AssignFile(InFile, InputFile.Text);
  {$I+}
  try
    Reset(InFile);

    repeat
      // Read one line at a time from the file.
      Readln(InFile, Str);

      // Get Time difference data from header.
      if AnsiStartsStr('# DL time difference (seconds)',Str) then begin

          //Remove comment from beginning of line.
          Timediff:=StrToIntDef(AnsiRightStr(Str,length(Str) - RPos(':',Str)),0);
          TimeDifference.Text := IntToStr(Timediff);

      end;
      until(EOF(InFile)); // EOF(End Of File) The the program will keep reading new lines until there is none.
      CloseFile(InFile);
      except
        on E: EInOutError do
        begin
         MessageDlg('Error', 'File handling error occurred. Details: '+E.ClassName+'/'+E.Message, mtError, [mbOK],0);
        end;
      end;

end;

initialization
  {$I dattimecorrect.lrs}

end.

