unit uHCGameStatusViewer;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes,
  System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, IPPeerClient,
  IPPeerServer, System.Tether.Manager, System.Tether.AppProfile, FMX.StdCtrls,
  FMX.Controls.Presentation, FMX.ScrollBox, FMX.Memo,
{$IFDEF MSWINDOWS}
  Windows,
{$ENDIF}
  uGameStatusTypeDefs;

type
  TfrmHCGameStatusViewer = class(TForm)
    tethMgr: TTetheringManager;
    tethPro: TTetheringAppProfile;
    memStats: TMemo;
    lblGameTime: TLabel;
    Button1: TButton;
    Timer1: TTimer;
    lblGameTimeLeft: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure tethProAcceptResource(const Sender: TObject;
      const AProfileId: string; const AResource: TCustomRemoteItem;
      var AcceptResource: Boolean);
    procedure tethProResourceReceived(const Sender: TObject;
      const AResource: TRemoteResource);
    procedure tethMgrNewManager(const Sender: TObject;
      const AManagerInfo: TTetheringManagerInfo);
    procedure tethMgrPairedFromLocal(const Sender: TObject;
      const AManagerInfo: TTetheringManagerInfo);
    procedure tethMgrPairedToRemote(const Sender: TObject;
      const AManagerInfo: TTetheringManagerInfo);
    procedure tethMgrRequestManagerPassword(const Sender: TObject;
      const ARemoteIdentifier: string; var Password: string);
    procedure tethMgrUnPairManager(const Sender: TObject;
      const AManagerInfo: TTetheringManagerInfo);
    procedure tethMgrRemoteManagerShutdown(const Sender: TObject;
      const AManagerIdentifier: string);
    procedure tethMgrAuthErrorFromLocal(const Sender: TObject;
      const AManagerIdentifier: string);
    procedure tethMgrAuthErrorFromRemote(const Sender: TObject;
      const AManagerIdentifier: string);
    procedure Button1Click(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure tethMgrEndAutoConnect(Sender: TObject);
  private
    { Private declarations }
{$IFDEF MSWINDOWS}
    MMF: TTGPMemMappedFile;
{$ENDIF}
    GameStatusPtr: PMMFGameStatus;
    strStats: String;
    procedure PrintGameStats(pGameStatus: TMMFGameStatus);
  public
    { Public declarations }
  end;

var
  frmHCGameStatusViewer: TfrmHCGameStatusViewer;

const
  version = 1; // ALE 20150820 TMMFGameStatus structure version

implementation

{$R *.fmx}

uses uHCDefines, uHCDateTime, uHCTypeDefs;

procedure TfrmHCGameStatusViewer.Button1Click(Sender: TObject);
var
  intC: Integer;
  stmMem: TMemoryStream;
begin
  stmMem := TMemoryStream.Create;
  stmMem.Write(GameStatusPtr^, SizeOf(TMMFGameStatus));
  for intC := 0 to tethMgr.RemoteProfiles.Count - 1 do
  begin
    tethPro.SendStream(tethMgr.RemoteProfiles[intC], 'GameStatsStream', stmMem);
    tethPro.SendString(tethMgr.RemoteProfiles[intC], 'GameStats',
      DateTimeToStr(Now()) + '\n' + strStats);
  end;
  stmMem.Free;
end;

procedure TfrmHCGameStatusViewer.FormCreate(Sender: TObject);
begin
{$IFDEF MSWINDOWS}
  if System.ParamStr(1) = '-server' then
  begin
    MMF := TTGPMemMappedFile.Create;
    Timer1.Enabled := True;
  end;
{$ENDIF}
  //tethMgr.AutoConnect();
  tethMgr.AutoConnect(2000);
end;

procedure TfrmHCGameStatusViewer.PrintGameStats(pGameStatus: TMMFGameStatus);
var
  i: NativeInt;
begin
  memStats.BeginUpdate;
  memStats.Lines.Clear;
  memStats.Lines.Add('            Blue    Red  Green');
  i := 0;
  memStats.Lines.Add(Format('Carriers   %5d  %5d  %5d',
    [pGameStatus.killcounts[i][BLUESIDE], pGameStatus.killcounts[i][REDSIDE],
    pGameStatus.killcounts[i][GREENSIDE]]));
  Inc(i);
  memStats.Lines.Add(Format('Ships      %5d  %5d  %5d',
    [pGameStatus.killcounts[i][BLUESIDE], pGameStatus.killcounts[i][REDSIDE],
    pGameStatus.killcounts[i][GREENSIDE]]));
  Inc(i);
  memStats.Lines.Add(Format('Subs       %5d  %5d  %5d',
    [pGameStatus.killcounts[i][BLUESIDE], pGameStatus.killcounts[i][REDSIDE],
    pGameStatus.killcounts[i][GREENSIDE]]));
  Inc(i);
  memStats.Lines.Add(Format('Planes     %5d  %5d  %5d',
    [pGameStatus.killcounts[i][BLUESIDE], pGameStatus.killcounts[i][REDSIDE],
    pGameStatus.killcounts[i][GREENSIDE]]));
  Inc(i);
  memStats.Lines.Add(Format('Heli       %5d  %5d  %5d',
    [pGameStatus.killcounts[i][BLUESIDE], pGameStatus.killcounts[i][REDSIDE],
    pGameStatus.killcounts[i][GREENSIDE]]));
  Inc(i);
  memStats.Lines.Add(Format('Bases      %5d  %5d  %5d',
    [pGameStatus.killcounts[i][BLUESIDE], pGameStatus.killcounts[i][REDSIDE],
    pGameStatus.killcounts[i][GREENSIDE]]));
  Inc(i);
  memStats.Lines.Add(Format('AD Fixed   %5d  %5d  %5d',
    [pGameStatus.killcounts[i][BLUESIDE], pGameStatus.killcounts[i][REDSIDE],
    pGameStatus.killcounts[i][GREENSIDE]]));
  Inc(i);
  memStats.Lines.Add(Format('AD Mobile  %5d  %5d  %5d',
    [pGameStatus.killcounts[i][BLUESIDE], pGameStatus.killcounts[i][REDSIDE],
    pGameStatus.killcounts[i][GREENSIDE]]));
  Inc(i);
  memStats.Lines.Add(Format('Armored    %5d  %5d  %5d',
    [pGameStatus.killcounts[i][BLUESIDE], pGameStatus.killcounts[i][REDSIDE],
    pGameStatus.killcounts[i][GREENSIDE]]));
  Inc(i);
  memStats.Lines.Add(Format('Unarmored  %5d  %5d  %5d',
    [pGameStatus.killcounts[i][BLUESIDE], pGameStatus.killcounts[i][REDSIDE],
    pGameStatus.killcounts[i][GREENSIDE]]));
  memStats.EndUpdate;
end;

procedure TfrmHCGameStatusViewer.tethMgrAuthErrorFromLocal
  (const Sender: TObject; const AManagerIdentifier: string);
begin
  memStats.Lines.Add('AuthErrorFromLocal');
end;

procedure TfrmHCGameStatusViewer.tethMgrAuthErrorFromRemote
  (const Sender: TObject; const AManagerIdentifier: string);
begin
  memStats.Lines.Add('AuthErrorFromRemote');
end;

procedure TfrmHCGameStatusViewer.tethMgrEndAutoConnect(Sender: TObject);
begin
  memStats.Lines.Add(Format('EndAutoConnect, Found %d Remote Managers',
                         [tethMgr.RemoteManagers.Count]));
end;

procedure TfrmHCGameStatusViewer.tethMgrNewManager(const Sender: TObject;
  const AManagerInfo: TTetheringManagerInfo);
begin
  memStats.Lines.Add('NewManager ' + AManagerInfo.ConnectionString);
end;

procedure TfrmHCGameStatusViewer.tethMgrPairedFromLocal(const Sender: TObject;
  const AManagerInfo: TTetheringManagerInfo);
begin
  memStats.Lines.Add('PairedFromLocal ' + AManagerInfo.ConnectionString);
end;

procedure TfrmHCGameStatusViewer.tethMgrPairedToRemote(const Sender: TObject;
  const AManagerInfo: TTetheringManagerInfo);
begin
  memStats.Lines.Add('PairedToRemote ' + AManagerInfo.ConnectionString);
end;

procedure TfrmHCGameStatusViewer.tethMgrRemoteManagerShutdown
  (const Sender: TObject; const AManagerIdentifier: string);
begin
  memStats.Lines.Add('RemoteManagerShutdown ' + AManagerIdentifier);
end;

procedure TfrmHCGameStatusViewer.tethMgrRequestManagerPassword
  (const Sender: TObject; const ARemoteIdentifier: string;
  var Password: string);
begin
  Password := 'HarpGamerRulz';
  TThread.Synchronize(TThread.CurrentThread,
    procedure
     begin
  memStats.Lines.Add('Sending password');
  end);
end;

procedure TfrmHCGameStatusViewer.tethMgrUnPairManager(const Sender: TObject;
  const AManagerInfo: TTetheringManagerInfo);
begin
  memStats.Lines.Add('UnPairManager ' + AManagerInfo.ConnectionString);
end;

procedure TfrmHCGameStatusViewer.tethProAcceptResource(const Sender: TObject;
  const AProfileId: string; const AResource: TCustomRemoteItem;
  var AcceptResource: Boolean);
begin
  AcceptResource := True;
  memStats.Lines.Add('AcceptResource');
end;

procedure TfrmHCGameStatusViewer.tethProResourceReceived(const Sender: TObject;
  const AResource: TRemoteResource);
var
  lGameStatus: TMMFGameStatus;
  dtNow: THCDateTimeRec;
begin
  if AResource.ResType = TRemoteResourceType.Stream then
  begin
    // memStats.Lines.Add('ResourceReceived ' + IntToStr(AResource.Value.AsStream.Size)
    // + ' ' + AResource.ToJsonString);
  {$IFDEF MSWINDOWS}
    AResource.Value.AsStream.Read(lGameStatus, SizeOf(TMMFGameStatus));
    if ((lGameStatus.version > 0) And (lGameStatus.version <> version))
    then
    begin
      MessageDlg
        (Format('Viewer Server (%d) and Viewer (%d) structure versions do not match, exiting',
        [lGameStatus.version, version]), System.UITypes.TMsgDlgType.mtError,
        [System.UITypes.TMsgDlgBtn.mbOK], 0);
      Application.Terminate;
    end;
    lblGameTimeLeft.Text := Format('GameTimeLeft: %d seconds',
      [lGameStatus.gametimeleft]);
    dtNow := HCDateTimeInc(lGameStatus.gamestartdatetime, lGameStatus.gametime);
    lblGameTime.Text := 'GameDateTime: ' +
      Format('%4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d',
      [dtNow.year, dtNow.month, dtNow.day, dtNow.hour, dtNow.minute,
      dtNow.second]);
    PrintGameStats(lGameStatus);
  {$ELSE}
    memStats.Lines.Add('ResourceReceived ' + IntToStr(AResource.Value.AsStream.Size)
     + ' ' + AResource.ToJsonString);
  {$ENDIF}
  end
  else
  begin
    // memStats.Lines.Add('ResourceReceived ' + AResource.ToJsonString);
  end;

end;

procedure TfrmHCGameStatusViewer.Timer1Timer(Sender: TObject);
var
  dtNow: THCDateTimeRec;
begin
{$IFDEF MSWINDOWS}
  Timer1.Enabled := False;
  GameStatusPtr := MMF.fPSharedData;
  if ((GameStatusPtr^.version > 0) And (GameStatusPtr^.version <> version)) then
  begin
    MessageDlg
      (Format('ExportDLL (%d) and Viewer (%d) structure versions do not match, exiting',
      [GameStatusPtr^.version, version]), System.UITypes.TMsgDlgType.mtError,
      [System.UITypes.TMsgDlgBtn.mbOK], 0);
    Application.Terminate;
  end;

  if (GameStatusPtr^.Read = False) then
  begin
    GameStatusPtr^.Read := True;
    lblGameTimeLeft.Text := Format('GameTimeLeft: %d seconds',
      [GameStatusPtr^.gametimeleft]);
    dtNow := HCDateTimeInc(GameStatusPtr^.gamestartdatetime,
      GameStatusPtr^.gametime);
    lblGameTime.Text := 'GameDateTime: ' +
      Format('%4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d',
      [dtNow.year, dtNow.month, dtNow.day, dtNow.hour, dtNow.minute,
      dtNow.second]);
    PrintGameStats(GameStatusPtr^);
    strStats := memStats.Text;
    Button1.OnClick(Self);
  end;
  Timer1.Enabled := True;
{$ENDIF}
end;

end.
