unit LogUtils;

interface

uses
  Classes;

type
  TLogUtils = class
  private
    FLogFolder: string;
    FLogFile: string;
    FExeVersion: string;
  public
    constructor Create;
    destructor Destroy; override;

    procedure AppendLogTo(const ALog: string);
  end;

  TTimeLog = class
  private
    FEndTime: TDateTime;
    FBeginTime: TDateTime;
    FName: string;
  public
    constructor Create(const AName: string);
    procedure EndLog;

    property Name: string read FName;
    property BeginTime: TDateTime read FBeginTime;
    property EndTime: TDateTime read FEndTime;
  end;

  TTimeLogManager = class
  private
    FLogFolder: string;
    FLogFile: string;
    FLogList: TList;

    function FindTimeLog(const AName: string): TTimeLog;
    function AddTimeLog(const AName: string): TTimeLog;
    function GetTimeLog(const AName: string): TTimeLog;

    procedure AppendLogTo(const ALog: string);
  public
    constructor Create;
    destructor Destroy; override;

    procedure ClearTimeLog;

    procedure BeginTime(const AName: string);
    procedure EndTime(const AName: string);
  end;

implementation

uses SysUtils, UtilMethods, Math, ZhAPI;


{ TLog }

procedure TLogUtils.AppendLogTo(const ALog: string);
var
  f: TextFile;
begin
  try
    AssignFile(f, FLogFile);
    if FileExists(FLogFile) then
      Append(f)
    else
      Rewrite(f);
    Writeln(f, Format('[Version: %s] %s %s', [FExeVersion, DateTimeToStr(Now), ALog]));
    Flush(f);
  finally
    CloseFile(f);
  end;
end;

constructor TLogUtils.Create;
var
  vFormatSetting: TFormatSettings;
begin
  vFormatSetting.ShortDateFormat := 'yyyy/MM/dd';
  vFormatSetting.DateSeparator := '-';
  FLogFolder := GetAppFilePath + 'log';
  if not DirectoryExists(FLogFolder) then
    CreateDirectoryInDeep(FLogFolder);
  FLogFile := FLogFolder + '\' + DateToStr(Date, vFormatSetting) + '.log';

  FExeVersion := GetExeFileVersion(ParamStr(0));
end;

destructor TLogUtils.Destroy;
begin
  inherited;
end;

{ TTimeLog }

constructor TTimeLog.Create(const AName: string);
begin
  FName := AName;
  FBeginTime := TickCount;
end;

procedure TTimeLog.EndLog;
begin
  FEndTime := TickCount;
end;

{ TTimeLogManager }

function TTimeLogManager.AddTimeLog(const AName: string): TTimeLog;
begin
  Result := TTimeLog.Create(AName);
  FLogList.Add(Result);
end;

procedure TTimeLogManager.AppendLogTo(const ALog: string);
var
  f: TextFile;
begin
  try
    AssignFile(f, FLogFile);
    if FileExists(FLogFile) then
      Append(f)
    else
      Rewrite(f);
    Writeln(f, ALog);
    Flush(f);
  finally
    CloseFile(f);
  end;
end;

procedure TTimeLogManager.BeginTime(const AName: string);
var
  vLog: TTimeLog;
begin
  vLog := GetTimeLog(AName);
end;

procedure TTimeLogManager.ClearTimeLog;
begin
  ClearObjects(FLogList);
end;

constructor TTimeLogManager.Create;
var
  vFormatSetting: TFormatSettings;
begin
  vFormatSetting.ShortDateFormat := 'yyyy/MM/dd';
  vFormatSetting.DateSeparator := '-';
  FLogFolder := GetAppFilePath + 'log';
  if not DirectoryExists(FLogFolder) then
    CreateDirectoryInDeep(FLogFolder);
  FLogFile := FLogFolder + '\' + DateToStr(Date, vFormatSetting) + '.log';
  FLogList := TList.Create;
end;

destructor TTimeLogManager.Destroy;
begin
  ClearTimeLog;
  FLogList.Free;
  inherited;
end;

procedure TTimeLogManager.EndTime(const AName: string);
var
  vLog: TTimeLog;
begin
  vLog := FindTimeLog(AName);
  if Assigned(vLog) then
  begin
    vLog.EndLog;
    AppendLogTo(Format('%s: %fms', [vLog.Name, vLog.EndTime - vLog.BeginTime]));
  end
  else
    AppendLogTo(Format('Time Log %s not Assigned', [AName]));
end;

function TTimeLogManager.FindTimeLog(const AName: string): TTimeLog;
var
  i: Integer;
begin
  Result := nil;
  for i := 0 to FLogList.Count - 1 do
  begin
    if (TTimeLog(FLogList.Items[i])).Name = AName then
    begin
      Result := TTimeLog(FLogList.Items[i]);
      Break;
    end;
  end;
end;

function TTimeLogManager.GetTimeLog(const AName: string): TTimeLog;
var
  vLog: TTimeLog;
begin
  vLog := FindTimeLog(AName);
  if not Assigned(vLog) then
    vLog := AddTimeLog(AName);
end;

end.
