unit UGameProtocol;

{$mode delphi}

interface

uses
  Classes, SysUtils, UGame, UVarBlockSerializer, UCommPin, SpecializedList;

type
  TCommand = (cmdTextMessage, cmdTurnStart, cmdTurnEnd, cmdGameStart, cmdGameEnd,
    cmdSurrender, cmdNextPlayer, cmdParametersChanged);
  TCommandEvent = procedure (Command: TCommand; DataIn, DataOut: TStream);

  TCommandTextMessage = record
    Text: string;
  end;

  { TGameProtocolClient }

  TGameProtocolClient = class
  private
    FOnGameEnd: TNotifyEvent;
    FOnGameStart: TNotifyEvent;
    FOnNextPlayer: TNotifyEvent;
    FOnParametersChanged: TNotifyEvent;
    FOnTurnStart: TNotifyEvent;
    procedure Receive(Sender: TCommPin; Stream: TListByte);
    procedure SendCmd(Command: TCommand);
  public
    Pin: TCommPin;
    procedure TurnEnd;
    procedure Surrender;
    procedure SendMessage(Text: string);
    constructor Create;
    destructor Destroy; override;
    property OnGameStart: TNotifyEvent read FOnGameStart write FOnGameStart;
    property OnGameEnd: TNotifyEvent read FOnGameEnd write FOnGameEnd;
    property OnTurnStart: TNotifyEvent read FOnTurnStart write FOnTurnStart;
    property OnNextPlayer: TNotifyEvent read FOnNextPlayer write FOnNextPlayer;
    property OnParametersChanged: TNotifyEvent read FOnParametersChanged
      write FOnParametersChanged;
  end;

  TSendMessageEvent = procedure (Text: string) of object;

  { TGameProtocolServer }

  TGameProtocolServer = class
  private
    FOnSendMessage: TSendMessageEvent;
    FOnSurrender: TNotifyEvent;
    FOnTurnEnd: TNotifyEvent;
    procedure Receive(Sender: TCommPin; Stream: TListByte);
    procedure SendCmd(Command: TCommand);
  public
    Pin: TCommPin;
    constructor Create;
    destructor Destroy; override;
    procedure GameStart;
    procedure GameEnd;
    procedure TurnStart;
    procedure ParametersChanged;
    procedure NextPlayer;
    property OnSendMessage: TSendMessageEvent read FOnSendMessage
      write FOnSendMessage;
    property OnTurnEnd: TNotifyEvent read FOnTurnEnd write FOnTurnEnd;
    property OnSurrender: TNotifyEvent read FOnSurrender write FOnSurrender;
  end;


implementation

{ TGameProtocolServer }

procedure TGameProtocolServer.Receive(Sender: TCommPin; Stream: TListByte);
var
  Data: TVarBlockSerializer;
  Command: Integer;
begin
  Data := TVarBlockSerializer.Create;
  Data.WriteVarList(Stream);
  Data.Stream.Position := 0;
  Command := Data.ReadVarUInt;
  try
    if Command = Integer(cmdTextMessage) then begin
      if Assigned(FOnSendMessage) then FOnSendMessage(Data.ReadVarString);
    end else
    if Command = Integer(cmdTurnEnd) then begin
      if Assigned(FOnTurnEnd) then FOnTurnEnd(Self);
    end else
    if Command = Integer(cmdSurrender) then begin
      if Assigned(FOnSurrender) then FOnSurrender(Self);
    end;
  finally
    Data.Free;
  end;
end;

procedure TGameProtocolServer.SendCmd(Command: TCommand);
var
  Data: TVarBlockSerializer;
  Data2: TListByte;
begin
  Data := TVarBlockSerializer.Create;
  Data2 := TListByte.Create;
  try
    Data.WriteVarUInt(Integer(Command));
    Data.Stream.Position := 0;
    Data.ReadVarList(Data2);
    Pin.Send(Data2);
  finally
    Data2.Free;
    Data.Free;
  end;
end;

constructor TGameProtocolServer.Create;
begin
  Pin := TCommPin.Create;
  Pin.OnReceive := Receive;
end;

destructor TGameProtocolServer.Destroy;
begin
  Pin.Free;
  inherited Destroy;
end;

procedure TGameProtocolServer.GameStart;
begin
  SendCmd(cmdGameStart);
end;

procedure TGameProtocolServer.GameEnd;
begin
  SendCmd(cmdGameEnd);
end;

procedure TGameProtocolServer.TurnStart;
begin
  SendCmd(cmdTurnStart);
end;

procedure TGameProtocolServer.ParametersChanged;
begin
  SendCmd(cmdParametersChanged);
end;

procedure TGameProtocolServer.NextPlayer;
begin
  SendCmd(cmdNextPlayer);
end;

{ TGameProtocol }

procedure TGameProtocolClient.Receive(Sender: TCommPin; Stream: TListByte);
var
  Data: TVarBlockSerializer;
  Command: Integer;
begin
  Data := TVarBlockSerializer.Create;
  Data.WriteVarList(Stream);
  Data.Stream.Position := 0;
  Command := Data.ReadVarUInt;
  try
    if Command = Integer(cmdGameStart) then begin
      if Assigned(FOnGameStart) then FOnGameStart(Self);
    end else
    if Command = Integer(cmdGameEnd) then begin
      if Assigned(FOnGameEnd) then FOnGameEnd(Self);
    end else
    if Command = Integer(cmdTurnStart) then begin
      if Assigned(FOnTurnStart) then FOnTurnStart(Self);
    end else
    if Command = Integer(cmdNextPlayer) then begin
      if Assigned(FOnNextPlayer) then FOnNextPlayer(Self);
    end else
    if Command = Integer(cmdParametersChanged) then begin
      if Assigned(FOnParametersChanged) then FOnParametersChanged(Self);
    end;
  finally
    Data.Free;
  end;
end;

procedure TGameProtocolClient.SendCmd(Command: TCommand);
var
  Data: TVarBlockSerializer;
  Data2: TListByte;
begin
  Data := TVarBlockSerializer.Create;
  Data2 := TListByte.Create;
  try
    Data.WriteVarUInt(Integer(Command));
    Data.Stream.Position := 0;
    Data.ReadVarList(Data2);
    Pin.Send(Data2);
  finally
    Data2.Free;
    Data.Free;
  end;
end;

procedure TGameProtocolClient.TurnEnd;
begin
  SendCmd(cmdTurnEnd);
end;

procedure TGameProtocolClient.Surrender;
begin
  SendCmd(cmdSurrender);
end;

procedure TGameProtocolClient.SendMessage(Text: string);
var
  Data: TVarBlockSerializer;
  Data2: TListByte;
begin
  Data := TVarBlockSerializer.Create;
  Data2 := TListByte.Create;
  try
    Data.WriteVarUInt(Integer(cmdTextMessage));
    Data.WriteVarString(Text);
    Data.Stream.Position := 0;
    Data.ReadVarList(Data2);
    Pin.Send(Data2);
  finally
    Data2.Free;
    Data.Free;
  end;
end;

constructor TGameProtocolClient.Create;
begin
  Pin := TCommPin.Create;
  Pin.OnReceive := Receive;
end;

destructor TGameProtocolClient.Destroy;
begin
  Pin.Free;
  inherited Destroy;
end;

end.

