program XDataMusicServer;

{$APPTYPE CONSOLE}

uses
  System.SysUtils,
  System.Classes,
  System.Generics.Collections,
  System.SyncObjs,
  Windows,
  Common.AureliusEntities in 'Common.AureliusEntities.pas',
  Common.DatabaseUtils in 'Common.DatabaseUtils.pas',
  Auth.Service.Interfaces in 'Auth.Service.Interfaces.pas',
  Auth.Service.Login in 'Auth.Service.Login.pas',
  Common.Logging in 'Common.Logging.pas',
  Common.Middleware.Logging in 'Common.Middleware.Logging.pas',
  Common.Config in 'Common.Config.pas',
  Auth.Server.Module in 'Auth.Server.Module.pas' {AuthServerModule: TDataModule},
  Api.Server.Module in 'Api.Server.Module.pas' {ApiServerModule: TDataModule},
  App.Server.Module in 'App.Server.Module.pas' {AppServerModule: TDataModule};

type
  TConsoleLogAppender = class( TInterfacedObject, ILogAppender )
  private
    FCriticalSection: TCriticalSection;
  public
    constructor Create;
    destructor Destroy; override;
    procedure Send(Log: ILog);
  end;

procedure StartServers;
var
  AuthServers: TDictionary<string, TAuthServerModule>;
  ApiServers: TDictionary<string, TApiServerModule>;
  AppServers: TDictionary<string, TAppServerModule>;
  I: Integer;
begin
  AuthServers := TObjectDictionary<string, TAuthServerModule>.Create([doOwnsValues]);
  ApiServers := TObjectDictionary<string, TApiServerModule>.Create([doOwnsValues]);
  AppServers := TObjectDictionary<string, TAppServerModule>.Create([doOwnsValues]);
  try
    // Create one server for each base URL in config. This allows for example,
    // start two servers that listen on both http and https urls
    // XDataMusicServer.exe http://+:80/tms/music https://+:443/tms/music
    for I := 0 to Length(ServerConfig.Urls) - 1 do
    begin
      if not AuthServers.ContainsKey(ServerConfig.Urls[I]) then
      begin
        AuthServers.Add(ServerConfig.Urls[I], TAuthServerModule.Create(nil));
        AuthServers[ServerConfig.Urls[I]].StartAuthServer(ServerConfig.Urls[I], AUTH_MODEL);
      end;

      if not ApiServers.ContainsKey(ServerConfig.Urls[I]) then
      begin
        ApiServers.Add(ServerConfig.Urls[I], TApiServerModule.Create(nil));
        ApiServers[ServerConfig.Urls[I]].StartApiServer(ServerConfig.Urls[I]);
      end;

      if ServerConfig.WebAppFolder <> '' then
      begin
        if not ApiServers.ContainsKey(ServerConfig.Urls[I]) then
        begin
          AppServers.Add(ServerConfig.Urls[I], TAppServerModule.Create(nil));
          AppServers[ServerConfig.Urls[I]].StartAppServer(ServerConfig.Urls[I]);
        end;
      end;
    end;
    Logger.Log('Servers started. Press ENTER to stop.');
    ReadLn;
  finally
    AuthServers.Free;
    ApiServers.Free;
    AppServers.Free;
  end;
end;

procedure PrintWelcomeMessage;
begin
  WriteLn('**********************************************************************');
  WriteLn('*                  Welcome to XDataMusicServer demo                  *');
  WriteLn('*                                                                    *');
  WriteLn('* The source code is given as is. The author is not responsible      *');
  WriteLn('* for any possible damage done due to the use of this code.          *');
  WriteLn('**********************************************************************');
  WriteLn('');
end;

{ TConsoleLogAppender }

constructor TConsoleLogAppender.Create;
begin
  FCriticalSection := TCriticalSection.Create;
end;

destructor TConsoleLogAppender.Destroy;
begin
  FCriticalSection.Free;
  inherited;
end;

procedure TConsoleLogAppender.Send(Log: ILog);
var
  FormatedMessage: string;
  Std: THandle;
  OrgColors, Colors: Word;
  Info: CONSOLE_SCREEN_BUFFER_INFO;
begin
  FCriticalSection.Acquire;
  try
    Std := GetStdHandle(STD_OUTPUT_HANDLE);
    OrgColors := 0;
    if GetConsoleScreenBufferInfo(Std, Info) then
      OrgColors := Info.wAttributes;
    Colors := OrgColors and not $f;

    FormatedMessage := FormatDateTime('[yyyy-mm-dd HH:nn:ss.zzz]', Now);

    SetConsoleTextAttribute(Std, Colors or $7);
    Write(FormatedMessage);

    Write(' ');

    SetConsoleTextAttribute(Std, Colors or $2);
    Write('[INFO]');

    Write(' ');

    SetConsoleTextAttribute(Std, Colors or $8);
    WriteLn(Log.GetMessage);

    SetConsoleTextAttribute(Std, OrgColors);
  finally
    FCriticalSection.Release;
  end;
end;

begin
  ReportMemoryLeaksOnShutdown := True;
  try
    PrintWelcomeMessage;
    LoadConfig;
    Logger.AddAppender(TConsoleLogAppender.Create);
    StartServers;
  except
    on E: Exception do
    begin
      WriteLn(E.Message);
      ReadLn;
    end;
  end;
end.

