unit Common.Logging;

interface

uses
  Generics.Collections;

type
  ILog = interface;
  ILogAppender = interface;

  ILogger = interface
    ['{4D667DD2-BE11-496B-B92A-C47E03520BD6}']
    procedure Log(logLevel: integer; Msg: string); overload;
    procedure Log(logLevel: integer; Log: ILog); overload;
    procedure AddAppender(ALogAppender: ILogAppender);
    function Appenders: TArray<ILogAppender>;
  end;

  ILogAppender = interface
    ['{A3B7D6FB-C75F-4BEF-8797-907B6FDAD5D2}']
    procedure Send(logLevel: integer; Log: ILog);
  end;

  ILog = interface
    ['{8E9C6580-C099-47C0-8B1B-6D7A28EC4FA3}']
    function GetMessage: string;
  end;

  TLogger = class( TInterfacedObject, ILogger )
  strict private
    FAppenders: TList<ILogAppender>;
  public
    constructor Create; overload;
    constructor Create(ALogger: ILogger); overload;
    destructor Destroy; override;
    procedure Log(logLevel: integer; Msg: string); overload;
    procedure Log(logLevel: integer; Log: ILog); overload;
    procedure AddAppender(ALogAppender: ILogAppender);
    function Appenders: TArray<ILogAppender>;
  end;

  TLogMessage = class( TInterfacedObject, ILog )
  private
    FMsg: string;
  public
    constructor Create(AMsg: string);
    function GetMessage: string;
  end;

  function Logger: ILogger;

implementation

var
  _Logger: ILogger;

function Logger: ILogger;
begin
  Result := _Logger;
end;

{ TLogMessage }

constructor TLogMessage.Create(AMsg: string);
begin
  FMsg := AMsg;
end;

function TLogMessage.GetMessage: string;
begin
  Result := FMsg;
end;

{ TLogger }

procedure TLogger.AddAppender(ALogAppender: ILogAppender);
begin
  FAppenders.Add(ALogAppender);
end;

function TLogger.Appenders: TArray<ILogAppender>;
var
  I: integer;
begin
  SetLength(Result, FAppenders.Count);
  for I := 0 to FAppenders.Count - 1 do
    Result[I] := FAppenders[I];
end;

constructor TLogger.Create(ALogger: ILogger);
var
  Appender: ILogAppender;
begin
  FAppenders := TList<ILogAppender>.Create;
  if ALogger <> nil then
    for Appender in ALogger.Appenders do
      AddAppender(Appender);
end;

constructor TLogger.Create;
begin
  Create(nil);
end;

destructor TLogger.Destroy;
begin
  FAppenders.Free;
  inherited;
end;

procedure TLogger.Log(logLevel: integer; Log: ILog);
var
  Appender: ILogAppender;
begin
  for Appender in FAppenders do
    Appender.Send(logLevel, Log);
end;

procedure TLogger.Log(logLevel: integer; Msg: string);
begin
  Log(logLevel, TLogMessage.Create(Msg));
end;

initialization
  _Logger := TLogger.Create;

end.