unit UGameClient;

{$mode delphi}

interface

uses
  Classes, SysUtils, UGame, Forms, fgl, UGameProtocol, UGameServer, UCommThread,
  UThreading, UCommFrame, UPlayer;

type
  TClientConnectType = (ctLocal, ctNetwork);

  { TClient }

  TClient = class
  private
    FActive: Boolean;
    FForm: TForm;
    FGame: TGame;
    FControlPlayer: TPlayer;
    FOnChange: TNotifyEvent;
    FOnDestroy: TNotifyEvent;
    FOnGameEnd: TNotifyEvent;
    FOnNextPlayer: TNotifyEvent;
    FOnReceive: TCommandEvent;
    FOnMove: TMoveEvent;
    FOnTurnStart: TNotifyEvent;
    CommThread: TCommThread;
    CommFrame: TCommFrame;
    procedure SetActive(AValue: Boolean);
    procedure SetControlPlayer(AValue: TPlayer);
    procedure SetForm(AValue: TForm);
    procedure PlayerMove(CellFrom, CellTo: TPlayerCell; var CountOnce, CountRepeat: Integer;
      Update: Boolean; var Confirm: Boolean);
    procedure SetOnMove(AValue: TMoveEvent);
  protected
    procedure SetGame(AValue: TGame); virtual;
    procedure ReceiveCmd(Command: TCommand; DataOut, DataIn: TStream); virtual;
    procedure DoTurnStartHandler(Sender: TObject); virtual;
    procedure DoTurnStart; virtual;
    procedure DoGameEndHandler(Sender: TObject);
    procedure DoGameEnd;
    procedure DoNextPlayerHandler(Sender: TObject);
    procedure DoNextPlayer;
    procedure DoParametersChangedHandler(Sender: TObject);
  public
    Name: string;
    LocalServer: TServer;
    RemoteAddress: string;
    RemotePort: Word;
    ConnectType: TClientConnectType;
    Protocol: TGameProtocolClient;
    procedure DoChange;
    constructor Create; virtual;
    destructor Destroy; override;
    property ControlPlayer: TPlayer read FControlPlayer write SetControlPlayer;
    property Game: TGame read FGame write SetGame;
    property Form: TForm read FForm write SetForm;
    property Active: Boolean read FActive write SetActive;
    property OnDestroy: TNotifyEvent read FOnDestroy write FOnDestroy;
    property OnMove: TMoveEvent read FOnMove write SetOnMove;
    property OnReceive: TCommandEvent read FOnReceive write FOnReceive;
    property OnChange: TNotifyEvent read FOnChange write FOnChange;
    property OnTurnStart: TNotifyEvent read FOnTurnStart write FOnTurnStart;
    property OnGameEnd: TNotifyEvent read FOnGameEnd write FOnGameEnd;
    property OnNextPlayer: TNotifyEvent read FOnNextPlayer write FOnNextPlayer;
  end;

  { TClients }

  TClients = class(TFPGObjectList<TClient>)
    Game: TGame;
    function New(Name: string): TClient;
    function SearchPlayer(Player: TPlayer): TClient;
    constructor Create(FreeObjects: Boolean = True);
  end;


implementation

uses
  UClientGUI;

{ TClients }

function TClients.New(Name: string): TClient;
begin
  Result := TClientGUI.Create;
  Result.Game := Game;
  Result.Name := Name;
  Add(Result);
end;

function TClients.SearchPlayer(Player: TPlayer): TClient;
var
  Client: TClient;
begin
  Result := nil;
  for Client in Self do
    if Client.ControlPlayer = Player then begin
      Result := Client;
      Break;
    end;
end;

constructor TClients.Create(FreeObjects: Boolean = True);
begin
  Game := nil;
  inherited;
end;

{ TClient }

procedure TClient.SetGame(AValue: TGame);
begin
  if FGame = AValue then Exit;
  FGame := AValue;
end;

procedure TClient.DoChange;
begin
  if Assigned(FOnChange) then
    FOnChange(Self);
end;

procedure TClient.PlayerMove(CellFrom, CellTo: TPlayerCell; var CountOnce,
  CountRepeat: Integer; Update: Boolean; var Confirm: Boolean);
begin
  if Assigned(FOnMove) then
    FOnMove(CellFrom, CellTo, CountOnce, CountRepeat, Update, Confirm);
end;

procedure TClient.SetOnMove(AValue: TMoveEvent);
begin
  //if FOnMove = AValue then Exit;
  FOnMove := AValue;
end;

procedure TClient.ReceiveCmd(Command: TCommand; DataOut, DataIn: TStream);
begin

end;

procedure TClient.DoTurnStartHandler(Sender: TObject);
begin
  Synchronize(DoTurnStart);
end;

procedure TClient.DoTurnStart;
begin
  if Assigned(FOnTurnStart) then
    FOnTurnStart(Self);
end;

procedure TClient.DoGameEndHandler(Sender: TObject);
begin
  Synchronize(DoGameEnd);
end;

procedure TClient.DoGameEnd;
begin
  if Assigned(FOnGameEnd) then FOnGameEnd(Self);
end;

procedure TClient.DoNextPlayerHandler(Sender: TObject);
begin
  Synchronize(DoNextPlayer);
end;

procedure TClient.DoNextPlayer;
begin
  if Assigned(FOnNextPlayer) then FOnNextPlayer(Self);
end;

procedure TClient.DoParametersChangedHandler(Sender: TObject);
begin
  Synchronize(DoChange);
end;

procedure TClient.SetControlPlayer(AValue: TPlayer);
begin
  if FControlPlayer = AValue then Exit;
  if Assigned(FControlPlayer) then
    FControlPlayer.OnMove := nil;
  FControlPlayer := AValue;
  if Assigned(FControlPlayer) then begin
     FControlPlayer.OnMove := PlayerMove;
  end;
end;

procedure TClient.SetActive(AValue: Boolean);
var
  ServerClient: TServerClient;
begin
  if FActive = AValue then Exit;
  if FActive then begin
    case ConnectType of
      ctLocal: begin
        CommThread.Active := False;
        CommThread.Ext.Disconnect;
        CommThread.Pin.Disconnect;
      end;
    end;
  end;
  FActive := AValue;
  if FActive then begin
    case ConnectType of
      ctLocal: if LocalServer.Active then begin
        CommFrame.FrameDataPin.Connect(Protocol.Pin);
        CommFrame.RawDataPin.Connect(CommThread.Pin);
        CommThread.Active := True;
        CommFrame.Active := True;
        ServerClient := LocalServer.GetNewServerClient;
        ServerClient.Player := ControlPlayer;
        ServerClient.CommFrame.RawDataPin.Connect(CommThread.Ext);
      end else raise Exception.Create('Local server is not active');
      //ctNetwork: ;
    end;
  end else begin
    Protocol.Pin.Disconnect;
  end;
end;

procedure TClient.SetForm(AValue: TForm);
begin
  if FForm = AValue then Exit;
  FForm := AValue;
end;

constructor TClient.Create;
begin
  CommThread := TCommThread.Create(nil);
  CommFrame := TCommFrame.Create(nil);
  FControlPlayer := nil;
  Protocol := TGameProtocolClient.Create;
  Protocol.OnTurnStart := DoTurnStartHandler;
  Protocol.OnGameEnd := DoGameEndHandler;
  Protocol.OnNextPlayer := DoNextPlayerHandler;
  Protocol.OnParametersChanged := DoParametersChangedHandler;
end;

destructor TClient.Destroy;
begin
  Form := nil;
  ControlPlayer := nil;
  FreeAndNil(Protocol);
  FreeAndNil(CommThread);
  FreeAndNil(CommFrame);
  inherited Destroy;
end;


end.

