
unit FolderRepCommon;
 
interface
 
uses ComCtrls, Windows, SysUtils, FolderRepSync, Messages;
 
const
  ftFolder = 0001;
  ftFile = 0002;
  clGray1 = $00D8D8D8;
  clGray2 = $00A6A6A6;
  clDarkGray = $00969696;
  clGrayLine = $004C4C4C;
  clProgress = $0014AB45;
  FileDrawGridIndent = 19;
  WM_ICONRESPONSE = WM_USER + 1;
 
type
  TSwitchFilesDrawGrid = procedure(Enabled: Boolean);
 
  PFilePair = ^TFilePair;
  TFilePair = record
    FileType: Integer;
//    SourceRelativeFileName, DestinationRelativeFileName: String;
    RelativeFileName: String;
    FileName: String;
    SourceFileSize, DestinationFileSize: Int64;
    SourceFileModificationDate, DestinationFileModificationDate: TDateTime;
    Status: Integer;
  end;
 
  PTreeLeaf = ^TTreeLeaf;
  TTreeLeaf = record
    Parent: PTreeLeaf;
    Children: PTreeLeaf;
    Sibling: PTreeLeaf;
    FilePair: PFilePair;
  end;
 
  TTree = class(TObject)
  private
    Root: PTreeLeaf;
//    procedure AddLeafToTreeView(TreeView: TTreeView; Parent: TTreeNode; CurrentLeaf: PTreeLeaf);
    procedure ClearNode(Node: PTreeLeaf);
  public
    Count: Integer;
    InUpdate: Boolean;
    constructor Create;
    procedure Free;
    function Add(Parent: PTreeLeaf; FilePair: PFilePair): PTreeLeaf;
    function GetLeafFromRelativeFileName(RelativeFileName: String): PTreeLeaf;
    function GetChildByFileName(Parent: PTreeLeaf; FileName: String): PTreeLeaf;
    function GetNextChildByFileName(Parent: PTreeLeaf; FileName: String): PTreeLeaf;
    function InsertBefore(Sibling: PTreeLeaf; FilePair: PFilePair): PTreeLeaf;
//    procedure GenerateTreeView(TreeView: TTreeView);
    procedure Clear;
    function GetLeafLevel(Leaf: PTreeLeaf): Integer;
    function GetChildCount(Leaf: PTreeLeaf): Integer;
    function GetRoot: PTreeLeaf;
    function GetNext(Leaf: PTreeLeaf): PTreeLeaf;
  end;
 
  TFolderPair = class(TObject)
  public
    Description: String;
    Source: String;
    Destination: String;
    Status: Integer;
    Items: TTree;
    Lock: TSemaphore;
    constructor Create(Description, Source, Destination: String);
    procedure Free;
  end;
 
var
  GlobalEnding: Boolean;
 
implementation
 
constructor TFolderPair.Create(Description, Source, Destination: String);
begin
  inherited Create();
  Self.Description := Description;
  Self.Source := Source;
  Self.Destination := Destination;
  Items := TTree.Create;
  Lock := TSemaphore.Create(1, 1);
  Status := 0;
  Items.InUpdate := False;
end;
 
procedure TFolderPair.Free;
begin
  Lock.Ask;
  Items.Free;
  Lock.Release;
  Lock.Free;
  inherited Free;
end;
 
//******************************************************************************
//**  TTree  *******************************************************************
//******************************************************************************
 
constructor TTree.Create;
begin
  inherited Create;
  Count := 0;
end;
 
procedure TTree.Free;
begin
  Clear;
  inherited Free;
end;
 
function TTree.Add(Parent: PTreeLeaf; FilePair: PFilePair): PTreeLeaf;
var
  CurrentLeaf: PTreeLeaf;
begin
  if Parent = Nil then
  begin
    New(Root);
    Root^.Parent := Nil;
    Root^.Sibling := Nil;
    Root^.Children := Nil;
    Root^.FilePair := FilePair;
    Result := Root;
  end else
  begin
    if (Parent^.Children = Nil) then
    begin
      New(Parent^.Children);
      CurrentLeaf := Parent^.Children;
      CurrentLeaf^.Parent := Parent;
      CurrentLeaf^.Sibling := Nil;
      CurrentLeaf^.Children := Nil;
      CurrentLeaf^.FilePair := FilePair;
      Result := CurrentLeaf;
    end else
    begin
      CurrentLeaf := Parent^.Children;
      while (CurrentLeaf^.Sibling <> Nil) do
        CurrentLeaf := CurrentLeaf^.Sibling;
      New(CurrentLeaf^.Sibling);
      CurrentLeaf := CurrentLeaf^.Sibling;
      CurrentLeaf^.Parent := Parent;
      CurrentLeaf^.Sibling := Nil;
      CurrentLeaf^.Children := Nil;
      CurrentLeaf^.FilePair := FilePair;
      Result := CurrentLeaf;
    end;
  end;
  Count := Count + 1;
end;
 
function TTree.GetLeafFromRelativeFileName(RelativeFileName: String): PTreeLeaf;
var
  CurrentLeaf: PTreeLeaf;
begin
  CurrentLeaf := Root;
  while CurrentLeaf <> Nil do
  begin
    if (CurrentLeaf^.FilePair^.RelativeFileName = RelativeFileName) then Break;
    CurrentLeaf := GetNext(CurrentLeaf);
  end;
  Result := CurrentLeaf;
end;
 
function TTree.GetChildByFileName(Parent: PTreeLeaf; FileName: String): PTreeLeaf;
var
  CurrentLeaf: PTreeLeaf;
begin
  CurrentLeaf := Parent.Children;
  while CurrentLeaf <> Nil do
  begin
    if (CurrentLeaf^.FilePair^.FileName = FileName) then Break;
    CurrentLeaf := CurrentLeaf.Sibling;
  end;
  Result := CurrentLeaf;
end;
 
function TTree.GetNextChildByFileName(Parent: PTreeLeaf; FileName: String): PTreeLeaf;
var
  CurrentLeaf: PTreeLeaf;
begin
  CurrentLeaf := Parent.Children;
  while CurrentLeaf <> Nil do
  begin
    if (CurrentLeaf^.FilePair^.FileName > FileName) then Break;
    CurrentLeaf := CurrentLeaf.Sibling;
  end;
  Result := CurrentLeaf;
end;
 
 
function TTree.InsertBefore(Sibling: PTreeLeaf; FilePair: PFilePair): PTreeLeaf;
var
  InsertedLeaf: PTreeLeaf;
  Parent: PTreeLeaf;
begin
  if Parent = Nil then
  begin
    Result := Nil;
    Exit;
  end else
  begin
    if (Parent^.Children = Sibling) then
    begin
      New(InsertedLeaf);
      InsertedLeaf^.Parent := Parent;
      InsertedLeaf^.Sibling := Parent^.Children;
      InsertedLeaf^.Children := Nil;
      InsertedLeaf^.FilePair := FilePair;
      Parent^.Children := InsertedLeaf;
      Result := InsertedLeaf;
    end else
    begin
      New(InsertedLeaf);
      InsertedLeaf^.Parent := Parent;
      InsertedLeaf^.Sibling := Sibling^.Sibling;
      InsertedLeaf^.Children := Nil;
      InsertedLeaf^.FilePair := FilePair;
      Sibling^.Sibling := InsertedLeaf;
      Result := InsertedLeaf;
    end;
  end;
end;
 
procedure TTree.ClearNode(Node: PTreeLeaf);
begin
  if Node = Nil then Exit;
  if Node^.Sibling <> Nil then ClearNode(Node^.Sibling);
  if Node^.Children <> Nil then ClearNode(Node^.Children);
  if ((Node^.Sibling = Nil) and (Node^.Children = Nil)) then
    Dispose(Node);
end;
 
procedure TTree.Clear;
begin
  ClearNode(Root);
  Root := Nil;
  Count := 0;
end;
 
{procedure TTree.AddLeafToTreeView(TreeView: TTreeView; Parent: TTreeNode; CurrentLeaf: PTreeLeaf);
var
  CurrentNode: TTreeNode;
begin
  if Parent = Nil then
    CurrentNode := TreeView.Items.Add(Parent, CurrentLeaf^.FilePair^.FileName)
  else
    CurrentNode := TreeView.Items.AddChild(Parent, CurrentLeaf^.FilePair^.FileName);
  CurrentNode.Data := CurrentLeaf^.FilePair;
  if CurrentLeaf^.Children <> Nil then
  begin
    CurrentNode.ImageIndex := 0;
    CurrentNode.SelectedIndex := 0;
    AddLeafToTreeView(TreeView, CurrentNode, CurrentLeaf^.Children);
  end else
  begin
    CurrentNode.ImageIndex := 2;
    CurrentNode.SelectedIndex := 2;
  end;
  if CurrentLeaf^.Sibling <> Nil then
    AddLeafToTreeView(TreeView, Parent, CurrentLeaf^.Sibling);
end;
 
procedure TTree.GenerateTreeView(TreeView: TTreeView);
begin
  TreeView.Items.Clear;
  TreeView.Items.BeginUpdate;
  AddLeafToTreeView(TreeView, Nil, Root);
  TreeView.Items.EndUpdate;
  TreeView.Repaint;
end; }
 
function TTree.GetLeafLevel(Leaf: PTreeLeaf): Integer;
var
  CurrentLeaf: PTreeLeaf;
  I: Integer;
begin
  if Leaf = Nil then
  begin
    Result := -1;
    Exit;
  end;
  I := 0;
  CurrentLeaf := Leaf;
  while (CurrentLeaf^.Parent <> Nil) do
  begin
    CurrentLeaf := CurrentLeaf^.Parent;
    I := I + 1;
  end;
  Result := I;
end;
 
function TTree.GetChildCount(Leaf: PTreeLeaf): Integer;
var
  CurrentLeaf: PTreeLeaf;
  Count: Integer;
begin
  CurrentLeaf := Leaf^.Children;
  Count := 0;
  while CurrentLeaf <> Nil do
  begin
    CurrentLeaf := CurrentLeaf^.Sibling;
    Count := Count + 1;
  end;
  Result := Count;
end;
 
function TTree.GetRoot: PTreeLeaf;
begin
  Result := Root;
end;
 
function TTree.GetNext(Leaf: PTreeLeaf): PTreeLeaf;
var
  NextLeaf: PTreeLeaf;
begin
  if Leaf <> Nil then
  begin
    if Leaf^.Children <> Nil then
    begin
      Result := Leaf^.Children;
      Exit;
    end;
    if Leaf^.Sibling <> Nil then
    begin
      Result := Leaf^.Sibling;
      Exit;
    end;
    if ((Leaf^.Children = Nil) and (Leaf^.Sibling = Nil)) then
    begin
      NextLeaf := Leaf^.Parent;
      while ((NextLeaf <> Nil) and (NextLeaf^.Sibling = Nil)) do
        NextLeaf := NextLeaf^.Parent;
      if (NextLeaf = Nil) then
        Result := Nil
      else
        Result := NextLeaf^.Sibling;
    end;
  end else
    Result := Nil;
end;
 
initialization
  GlobalEnding := False;
end.
