unit FileList;

interface

uses
  Classes, SysUtils, FileUtil, LazFileUtils, Generics.Collections,
  Generics.Defaults;

type
  TFileList = class;

  { TFileItem }

  TFileItem = class
  private
    function GetNameOnly: string;
    procedure SetNameOnly(AValue: string);
  public
    FileName: string;
    Size: Integer;
    DateTime: TDateTime;
    List: TFileList;
    property NameOnly: string read GetNameOnly write SetNameOnly;
  end;

  { TFileList }

  TFileList = class(TObjectList<TFileItem>)
  public
    SharedDir: string;
    UserHomeDir: string;
    FileFilter: string;
    InsertFirstItem: string;
    SortByName: Boolean;
    function AddNew(FileName: string; Size: Integer; DateTime: TDateTime
      ): TFileItem;
    procedure Load;
    procedure SortItems;
    procedure AssignToStrings(List: TStrings);
    function IndexOfNameOnly(NameOnly: string): Integer;
  end;


implementation

function ComparerFileItemNameOnly(constref Item1, Item2: TFileItem): Integer;
begin
  Result := CompareText(Item1.NameOnly, Item2.NameOnly);
end;

function ComparerFileItemTime(constref Item1, Item2: TFileItem): Integer;
begin
  if Item1.DateTime > Item2.DateTime then Result := 1
  else if Item1.DateTime < Item2.DateTime then Result := -1
  else Result := 0;
end;

{ TFileItem }

function TFileItem.GetNameOnly: string;
begin
  Result := ExtractFileNameOnly(FileName);
end;

procedure TFileItem.SetNameOnly(AValue: string);
begin
  FileName := ExtractFileDir(FileName) + DirectorySeparator + AValue +
    ExtractFileExt(FileName);
end;

{ TFileList }

function TFileList.AddNew(FileName: string; Size: Integer; DateTime: TDateTime
  ): TFileItem;
begin
  Result := TFileItem.Create;
  Result.FileName := FileName;
  Result.Size := Size;
  Result.DateTime := DateTime;
  Result.List := Self;
  Add(Result);
end;

procedure TFileList.Load;
var
  F: TSearchRec;
  FileItem: TFileItem;
begin
  Clear;

  if FindFirst(UserHomeDir + DirectorySeparator + FileFilter, $21, F) = 0 then
    repeat
      AddNew(UserHomeDir + DirectorySeparator + F.Name, F.Size, F.TimeStamp);
    until FindNext(F) <> 0;
  FindClose(F);

  if FindFirst(SharedDir + DirectorySeparator + FileFilter, $21, F) = 0 then
    repeat
      if IndexOfNameOnly(ExtractFileNameOnly(F.Name)) = -1 then
        AddNew(SharedDir + DirectorySeparator + F.Name, F.Size, 0);
    until FindNext(F) <> 0;
  FindClose(F);

  if InsertFirstItem <> '' then begin
    FileItem := TFileItem.Create;
    FileItem.FileName := InsertFirstItem;
    FileItem.DateTime := -1;
    FileItem.List := Self;
    Insert(0, FileItem);
  end;

  SortItems;
end;

procedure TFileList.SortItems;
begin
  if SortByName then Sort(TComparer<TFileItem>.Construct(ComparerFileItemNameOnly))
    else Sort(TComparer<TFileItem>.Construct(ComparerFileItemTime));

  if InsertFirstItem <> '' then begin
    Move(IndexOfNameOnly(InsertFirstItem), 0);
  end;
end;

procedure TFileList.AssignToStrings(List: TStrings);
var
  I: Integer;
begin
  List.Clear;
  List.Capacity := Count;
  for I := 0 to Count - 1 do
    List.AddObject(Items[I].NameOnly, Items[I]);
end;

function TFileList.IndexOfNameOnly(NameOnly: string): Integer;
var
  I: Integer;
begin
  I := 0;
  while (I < Count) and (Items[I].NameOnly <> NameOnly) do Inc(I);
  if I < Count then Result := I
  else Result := -1;
end;

end.

