unit uFileInfo;
{$INCLUDE 'DirSync3.inc'}

interface

uses
  Windows, SysUtils, Classes, Generics.Collections, Generics.Defaults,
  {$IFDEF FAR3} Plugin3, {$ELSE} PluginW, {$ENDIF} FarKeysW, FarColor,
  uSystem, uFiles, uFAR, uLog;

type
  TBaseFileInfo = class
  private
  protected
    function GetFileName: string; virtual; abstract;
    function GetFileSize: int64; virtual; abstract;
    function GetFileDate: TDateTime; virtual; abstract;
    function GetFileAttributes: DWORD; virtual; abstract;
    function GetSelected: boolean; virtual; abstract;
    procedure SetSelected(const Value: boolean); virtual; abstract;
  public
    constructor Create;
    destructor Destroy; override;
    property FileName: string read GetFileName;
    property FileSize: Int64 read GetFileSize;
    property FileDate: TDateTime read GetFileDate;
    property FileAttributes: DWORD read GetFileAttributes;
    property Selected: boolean read GetSelected write SetSelected;
  end;

  TFileInfoFromPanels = class(TBaseFileInfo)
  private
    fPanelItem: TFarPanelItem;
  protected
    function GetFileName: string; override;
    function GetFileSize: int64; override;
    function GetFileDate: TDateTime; override;
    function GetFileAttributes: DWORD; override;
    function GetSelected: boolean; override;
    procedure SetSelected(const Value: boolean); override;
  public
    constructor Create(APanelItem: TFarPanelItem);
    destructor Destroy; override;
  end;

  TFileInfoFromFileSystem = class(TBaseFileInfo)
  private
    fFileName: string;
    fFileSize: Int64;
    fFileDate: TDateTime;
    fFileAttributes: DWORD;
    fSelected: boolean;
  protected
    function GetFileName: string; override;
    function GetFileSize: int64; override;
    function GetFileDate: TDateTime; override;
    function GetFileAttributes: DWORD; override;
    function GetSelected: boolean; override;
    procedure SetSelected(const Value: boolean); override;
  public
    constructor Create(const SearchRec: TSearchRec);
    destructor Destroy; override;
  end;

  TPanelFilterMethod = procedure (Sender: TObject; PanelItem: TFarPanelItem; UserData: Pointer; var Accept: boolean) of object;
  TDirectoryFilterMethod = procedure (Sender: TObject; const SearchRec: TSearchRec; UserData: Pointer; var Accept: boolean) of object;

  TFileInfoList = class(TObjectList<TBaseFileInfo>)
  public
    procedure SortByFileName;
    procedure SortByFileNameDescending;
    procedure LoadFromDirectory(const Path: string; DirectoryFilter: TDirectoryFilterMethod = nil; UserData: Pointer = nil);
    procedure LoadFromPanel(const Panel: TFarPanelInfo; PanelFilter: TPanelFilterMethod = nil; UserData: Pointer = nil);
  end;

implementation

{ TDirSyncFile }

constructor TBaseFileInfo.Create;
begin
  inherited Create;
end;

destructor TBaseFileInfo.Destroy;
begin
  inherited;
end;

{ TDirSyncFiles }

procedure TFileInfoList.LoadFromDirectory(const Path: string; DirectoryFilter: TDirectoryFilterMethod; UserData: Pointer);
var
  Mask: string;
  SR: TSearchRec;
  Accept: boolean;
begin
  //Log('Loading directory "%s\*.*"', [Path]);
  Clear;
  Mask := IncludeTrailingPathDelimiter({TFarUtils.FullFileName}(Path)) + '*.*';
  if FindFirst(Mask, faAnyFile, SR) = 0 then
    try
      repeat
        if (SR.Name <> '.') and (SR.Name <> '..') then begin
          Accept := True;
          if Assigned(DirectoryFilter) then
            DirectoryFilter(Self, SR, UserData, Accept);
          if Accept then
            Add(TFileInfoFromFileSystem.Create(SR));
        end;
      until FindNext(SR) <> 0;
    finally
      SysUtils.FindClose(SR);
    end;
end;

procedure TFileInfoList.LoadFromPanel(const Panel: TFarPanelInfo; PanelFilter: TPanelFilterMethod; UserData: Pointer);
var
  i: integer;
  Item: TFarPanelItem;
  Accept: boolean;
begin
  Clear;
  if Panel <> nil then
    for i := 0 to Pred(Panel.Items.Count) do begin
      Item := Panel.Items[i];
      Accept := Item.FileName <> '..';
      if Assigned(PanelFilter) then
        PanelFilter(Self, Item, UserData, Accept);
      if Accept then
        Add(TFileInfoFromPanels.Create(Item));
    end;
end;

procedure TFileInfoList.SortByFileName;
begin
  Sort(TComparer<TBaseFileInfo>.Construct(
    function (const L, R: TBaseFileInfo): integer
      begin
        Result := AnsiCompareText(L.FileName, R.FileName);
      end
  ));
end;

procedure TFileInfoList.SortByFileNameDescending;
begin
  Sort(TComparer<TBaseFileInfo>.Construct(
    function (const L, R: TBaseFileInfo): integer
      begin
        Result := AnsiCompareText(R.FileName, L.FileName);
      end
  ));
end;

{ TDirSyncFileFromPanels }

constructor TFileInfoFromPanels.Create(APanelItem: TFarPanelItem);
begin
  inherited Create;
  fPanelItem := APanelItem;
end;

destructor TFileInfoFromPanels.Destroy;
begin
  fPanelItem := nil;
  inherited;
end;

function TFileInfoFromPanels.GetFileAttributes: DWORD;
begin
  Result := fPanelItem.FileAttributes;
end;

function TFileInfoFromPanels.GetFileDate: TDateTime;
var
  SysTime: TSystemTime;
begin
  if FileTimeToSystemTime(fPanelItem.LastWriteTime, SysTime) then
    Result := EncodeDate(SysTime.wYear, SysTime.wMonth, SysTime.wDay) + EncodeTime(SysTime.wHour, SysTime.wMinute, SysTime.wSecond, SysTime.wMilliseconds)
  else
    Result := 0;
end;

function TFileInfoFromPanels.GetFileName: string;
begin
  Result := fPanelItem.FileName;
end;

function TFileInfoFromPanels.GetFileSize: int64;
begin
  Result := fPanelItem.FileSize;
end;

function TFileInfoFromPanels.GetSelected: boolean;
begin
  Result := fPanelItem.Selected;
end;

procedure TFileInfoFromPanels.SetSelected(const Value: boolean);
begin
  fPanelItem.Selected := Value;
end;

{ TDirSyncFileFromFileSystem }

constructor TFileInfoFromFileSystem.Create(const SearchRec: TSearchRec);
begin
  inherited Create;
  fFileName := SearchRec.Name;
  fFileSize := SearchRec.Size;
  fFileDate := {$IFDEF DELPHIXE2_UP} SearchRec.TimeStamp {$ELSE} FileDateToDateTime(SearchRec.Time) {$ENDIF} ;
  fFileAttributes := SearchRec.Attr;
end;

destructor TFileInfoFromFileSystem.Destroy;
begin
  inherited;
end;

function TFileInfoFromFileSystem.GetFileAttributes: DWORD;
begin
  Result := fFileAttributes;
end;

function TFileInfoFromFileSystem.GetFileDate: TDateTime;
begin
  Result := fFileDate;
end;

function TFileInfoFromFileSystem.GetFileName: string;
begin
  Result := fFileName;
end;

function TFileInfoFromFileSystem.GetFileSize: int64;
begin
  Result := fFileSize;
end;

function TFileInfoFromFileSystem.GetSelected: boolean;
begin
  Result := fSelected;
end;

procedure TFileInfoFromFileSystem.SetSelected(const Value: boolean);
begin
  fSelected := Value;
end;

end.
