unit configbrowser;

{$mode ObjFPC}{$H+}

interface

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

type

  { TConfigBrowserForm }

  TConfigBrowserForm = class(TForm)
    BackupConfigButton: TButton;
    ExportButton: TButton;
    ExportedFilesStringGrid: TStringGrid;
    MergeButton: TButton;
    RefreshBitBtn: TBitBtn;
    ExportedFilesGroupBox: TGroupBox;
    FileViewGroupBox: TGroupBox;
    FileViewListBox: TListBox;
    InConfigGroupBox: TGroupBox;
    OnDiskGroupBox: TGroupBox;
    ReplaceButton: TButton;
    SelectedSerialNumberGroupBox: TGroupBox;
    SerialDetailsListBox: TListBox;
    SerialListBox: TListBox;
    StoredSerialNumbersGroupBox: TGroupBox;
    OpenDialog1: TOpenDialog;
    StatusBar: TStatusBar;
    procedure BackupConfigButtonClick(Sender: TObject);
    procedure ExportButtonClick(Sender: TObject);
    procedure ExportedFilesStringGridClick(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure MergeButtonClick(Sender: TObject);
    procedure RefreshBitBtnClick(Sender: TObject);
    procedure ReplaceButtonClick(Sender: TObject);
    procedure SerialListBoxClick(Sender: TObject);
    procedure RefreshSerials();
  private

  public

  end;

var
  ConfigBrowserForm: TConfigBrowserForm;
  DisplayedSerialNumber:String;

implementation

uses
  Unit1, appsettings, StrUtils, FileUtil
  , LazFileUtils //Necessary for filename extraction
  , LCLType //MB_ buttons defined here
  ,header_utils
  ;
{ TConfigBrowserForm }

procedure TConfigBrowserForm.RefreshSerials();
var
  SectionString: String = '';
  SerialString: String = '';
  ConfSectionStringList: TStringList;
  i: Integer; {General purpose counter}
begin

    ConfSectionStringList:=TStringList.Create;

    {Load list box with serial numbers in .cfg file}
    SerialListBox.Clear;
    SerialDetailsListBox.Clear;
    vConfigurations.ReadSectionNames(ConfSectionStringList);
    for SectionString in ConfSectionStringList do begin
         if AnsiStartsText('Serial:',SectionString) then begin
           SerialString:=AnsiReplaceText(SectionString,'Serial:','');
           SerialListBox.Items.Add(SerialString);
         end;
    end;

    //{Highlight the selected serial number in the stored list}
    //for i := 0 to SerialListBox.Count-1 do begin
    //  if StrToInt(SerialListBox.Items[i])=StrToInt(Unit1.SelectedUnitSerialNumber) then begin
    //    SerialListBox.ItemIndex:=i;
    //  end;
    //end;
    //
    //{Populate from the selected}
    //SerialListBoxClick(Nil);

    ConfSectionStringList.Free;

end;

procedure TConfigBrowserForm.FormShow(Sender: TObject);
begin

  {Show location of config file}
  InConfigGroupBox.Caption:='In config: ' + ConfigFilePath;

  {Show location of logs directory}
  OnDiskGroupBox.Caption:='On disk: ' + LogsDirectory;

  {Populate stored serial numbers list}
  RefreshSerials();

  {Populate file list}
  RefreshBitBtnClick(Nil);

end;

procedure TConfigBrowserForm.MergeButtonClick(Sender: TObject);
var
  SelectedSerialString:String='';
  Reply: Integer;
  i: Integer;
  SeparatorPosition:Integer;
  KeyRecord:String;
  KeyString:String;
  KeyValue:String;

begin

  {Look for serial number in file view}
  if FileViewListBox.Count>0 then begin
    {Get selected serial number, and remove extra text.}
    SelectedSerialString:=FileViewListBox.Items[0];
    SelectedSerialString:=AnsiReplaceText(SelectedSerialString,'[Serial:','');
    SelectedSerialString:=AnsiReplaceText(SelectedSerialString,']','');

    {Warn that existing record will be deleted}
    StatusMessage('Attempting to import / merge serial '+SelectedSerialString+' config.');
    Reply:=Application.MessageBox(
       Pchar('Are you sure you want to merge any existing configuration for this serial number '+SelectedSerialString+' ?' + sLineBreak +
       'Cancel if not sure.'),'Import / merge ',MB_ICONWARNING + MB_OKCANCEL);
    if Reply=mrOK then begin
        StatusMessage('Import / merge serial '+SelectedSerialString+' config proceeding.');

        {Import}
        {Skip first line with section name}
        for i:=1 to FileViewListBox.Count-1 do begin
          KeyRecord:=FileViewListBox.Items[i];
          SeparatorPosition:=pos('=',FileViewListBox.Items[i]);
          KeyString:=AnsiLeftStr(FileViewListBox.Items[i],SeparatorPosition-1);
          KeyValue:=AnsiRightStr(FileViewListBox.Items[i],Length(KeyRecord)-SeparatorPosition);
          vConfigurations.WriteString('Serial:'+SelectedSerialString,KeyString,KeyValue);
        end;

        {Refresh list}
        RefreshSerials();

        {Select imported data}

    end
    else
      StatusMessage('Import / merge cancelled.');

  end;
end;

{Refresh exported files list}
procedure TConfigBrowserForm.RefreshBitBtnClick(Sender: TObject);
  //procedure TPlotterForm.AddFilesToList(FilePathName : String);
var
  FileSize : integer = 0; {Filesize, undetermined = 0}
  Row : integer = 1; {Start at row 1}
  FileName, FilePath, FileDate : string;
  sr : TSearchRec;
  FileFilter : String;
begin

  FileViewGroupBox.Caption:='File view:';
  FileViewListBox.Clear;

  FilePath := ExtractFilePath(LogsDirectory);
  FileFilter:='SN_*.txt';
  ExportedFilesStringGrid.RowCount:=1; {Reset file list}

  {Check if any files match criteria}
  if FindFirstUTF8(FilePath+FileFilter,faAnyFile,sr)=0 then
    repeat
      {Get formatted file properties}
      FileName := ExtractFileName(sr.Name);
      FileSize := sr.Size;
      FileDate:=DateTimeToStr(FileDateToDateTime(sr.Time),FDateSettings);
      {Display found filename and timestamp}
      ExportedFilesStringGrid.InsertRowWithValues(Row,[FileName, IntToStr(FileSize), FileDate ]);
      {Prepare for next file display}
      Row := Row + 1;
    until FindNextUTF8(sr)<>0;
  FindCloseUTF8(sr);

  {Initial sorting}
  ExportedFilesStringGrid.SortColRow(true, 0);

  {Deselect entry}
  ExportedFilesStringGrid.ClearSelections;
  ExportedFilesStringGrid.Options:=ExportedFilesStringGrid.Options - [goRowSelect];

end;

{Replace a section}
procedure TConfigBrowserForm.ReplaceButtonClick(Sender: TObject);
var
  SelectedSerialString:String='';
  Reply: Integer;
  i: Integer;
  SeparatorPosition:Integer;
  KeyRecord:String;
  KeyString:String;
  KeyValue:String;

begin

  {Look for serial number in file view}
  if FileViewListBox.Count>0 then begin
    {Get selected serial number, and remove extra text.}
    SelectedSerialString:=FileViewListBox.Items[0];
    SelectedSerialString:=AnsiReplaceText(SelectedSerialString,'[Serial:','');
    SelectedSerialString:=AnsiReplaceText(SelectedSerialString,']','');

    {Warn that existing record will be deleted}
    StatusMessage('Attempting to import / replace serial '+SelectedSerialString+' config.');
    Reply:=Application.MessageBox(
       Pchar('Are you sure you want to overwrtite any existing configuration for this serial number '+SelectedSerialString+' ?' + sLineBreak +
       'Cancel if not sure.'),'Import / replace ',MB_ICONWARNING + MB_OKCANCEL);
    if Reply=mrOK then begin
        StatusMessage('Import / replace serial '+SelectedSerialString+' config proceeding.');

        {Delete the section first}
        vConfigurations.EraseSection('Serial:'+SelectedSerialString);

        {Import}
        {Skip first line with section name}
        for i:=1 to FileViewListBox.Count-1 do begin
          KeyRecord:=FileViewListBox.Items[i];
          SeparatorPosition:=pos('=',FileViewListBox.Items[i]);
          KeyString:=AnsiLeftStr(FileViewListBox.Items[i],SeparatorPosition-1);
          KeyValue:=AnsiRightStr(FileViewListBox.Items[i],Length(KeyRecord)-SeparatorPosition);
          vConfigurations.WriteString('Serial:'+SelectedSerialString,KeyString,KeyValue);
        end;

        {Refresh list}
        RefreshSerials();

        {Select imported data}

    end
    else
      StatusMessage('Import / replace cancelled.');


  end;


end;

procedure TConfigBrowserForm.ExportButtonClick(Sender: TObject);
var
  filename: string;
  tfOut: TextFile;
  i:integer = 0;

begin

  {Filename: serial number + date . txt}
  filename:=RemoveMultiSlash(
    LogsDirectory+DirectorySeparator+
    'SN_'+
    DisplayedSerialNumber+
    '_'+
    FormatDateTime('yyyy-mm-dd"T"hh-nn-ss',Now()) +
    '.txt');

  // Set the name of the file that will be created
  AssignFile(tfOut, filename);

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

  // Embed the file creation in a try/except block to handle errors gracefully
  try
    // Create the file, write some text and close it.
    rewrite(tfOut);

    {Write first line replicating the sectionname}
    //writeln(tfOut, '[Serial:'+DisplayedSerialNumber+']');

    for i:=0 to SerialDetailsListBox.Count-1 do begin
      writeln(tfOut, SerialDetailsListBox.Items[i]);
    end;

    CloseFile(tfOut);

  except
    // If there was an error the reason can be found here
    on E: EInOutError do
      writeln('Export serial number details config : File handling error occurred. Details: ', E.ClassName, '/', E.Message);
  end;

  StatusBar.Panels.Items[0].Text:='Wrote file to:'+filename;

  RefreshBitBtnClick(Nil);

end;

{View file}
procedure TConfigBrowserForm.ExportedFilesStringGridClick(Sender: TObject);
var
  tfIn: TextFile;
  filename: String;
  s:String; {String read from file}
begin
  ExportedFilesStringGrid.Options:=ExportedFilesStringGrid.Options + [goRowSelect];

  {Open file dialog. Only show SN_*.txt files}
    filename:=LogsDirectory+DirectorySeparator+ExportedFilesStringGrid.Cells[0,ExportedFilesStringGrid.Row];
    FileViewGroupBox.Caption:='File view: '+filename;

    FileViewListBox.Clear;

    // Set the name of the file that will be read
    AssignFile(tfIn, filename);

    // Embed the file handling in a try/except block to handle errors gracefully
    try
      // Open the file for reading
      reset(tfIn);

      // Keep reading lines until the end of the file is reached
      while not eof(tfIn) do
      begin
        readln(tfIn, s);
        FileViewListBox.Items.Add(s);
        //writeln(s);
      end;

      // Done so close the file
      CloseFile(tfIn);

    except
      on E: EInOutError do
       writeln('File view handling error occurred. Details: ', E.Message);
    end;

    {Ask before overwriting existing: Merge, Replace, No-diff, Cancel}
    {Replace:}
    //vConfigurations.EraseSection('Serial:'+);
    {Cancel:}
    //Exit;
end;

{Make a backup copy}
procedure TConfigBrowserForm.BackupConfigButtonClick(Sender: TObject);
var
  DestFile: String;
begin
  DestFile:=AnsiReplaceText(ConfigFilePath,'udm.','udm'+FormatDateTime('_yyyy-mm-dd"T"hh-nn-ss',Now())+'.');
  CopyFile(ConfigFilePath, DestFile);
  StatusBar.Panels.Items[0].Text:='Copied original '+ConfigFilePath+' file to: '+DestFile;
end;

procedure TConfigBrowserForm.SerialListBoxClick(Sender: TObject);
var
  SectionNameString: String = '';
  FieldNameString: String = '';
  SerialDetailsStringList: TStringList; {For parsing list}
begin

  SerialDetailsStringList:=TStringList.Create;

  {Load list box with serial number details}
  SerialDetailsListBox.Clear;
  if SerialListBox.ItemIndex>=0 then begin
    DisplayedSerialNumber:=SerialListBox.items[SerialListBox.ItemIndex];
    SectionNameString:='Serial:'+DisplayedSerialNumber;
    vConfigurations.ReadSection(SectionNameString,SerialDetailsStringList);
    SerialDetailsListBox.Items.Add('['+SectionNameString+']');
    for FieldNameString in SerialDetailsStringList do begin
      SerialDetailsListBox.Items.Add(
        FieldNameString+
        '='+
        vConfigurations.ReadString(SectionNameString,FieldNameString,'')
        );
    end;
  end;
end;

initialization
  {$I configbrowser.lrs}

end.

