////////////////////////////////////////////////////////////////////////////////
// All code below is exclusively owned by author of Chess4Net - Pavel Perminov
// (packpaul@mail.ru, packpaul1@gmail.com).
// Any changes, modifications, borrowing and adaptation are a subject for
// explicit permition from the owner.

unit GameChessBoardUnit;

interface

uses
  ExtCtrls, TntStdCtrls, Buttons, Controls, StdCtrls, Classes, Forms, TntForms,
  Graphics, Messages,
  // Chess4net
  ChessBoardHeaderUnit, ChessBoardUnit, ChessRulesEngine,
  LocalizerUnit, PosBaseChessBoardLayerUnit;

type
  TGameChessBoardEvent =
    (cbeMoved, cbeMate, cbeStaleMate, cbeInsuffMaterial, cbeKeyPressed,
     cbeClockSwitched, cbeTimeOut, cbeExit, cbeMenu, cbeActivate, cbeFormMoving,
     cbeRefreshAll);
     // It's possible to add new events. cbeRefreshAll signals that global options had been changed

  TGameChessBoardHandler = procedure(e: TGameChessBoardEvent;
                                 d1: pointer = nil; d2: pointer = nil) of object;

{$IFDEF THREADED_CHESSCLOCK}
  TGameChessBoard = class;

  TTimeLabelThread = class(TThread)
  private
    ChessBoard: TGameChessBoard;
    player_time: array[TFigureColor] of TDateTime;
  protected
    procedure Execute; override;
  public
    WhiteTime, BlackTime: string;
    constructor Create(ChessBoard: TGameChessBoard);
  end;
{$ENDIF}

  TGameChessBoard = class(TTntForm, ILocalizable)
    TimePanel: TPanel;
    WhiteLabel: TTntLabel;
    WhiteTimeLabel: TLabel;
    BlackLabel: TTntLabel;
    BlackTimeLabel: TLabel;
    GameTimer: TTimer;
    WhiteFlagButton: TSpeedButton;
    BlackFlagButton: TSpeedButton;
    WhitePanel: TPanel;
    BlackPanel: TPanel;
    ChessBoardPanel: TPanel;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure GameTimerTimer(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure FormActivate(Sender: TObject);
    procedure FlagButtonClick(Sender: TObject);
    procedure FormCanResize(Sender: TObject; var NewWidth, NewHeight: Integer;
      var Resize: Boolean);
    procedure TimePanelResize(Sender: TObject);

  private
    m_ChessBoard: TChessBoard;
    m_PosBaseChessBoardLayer: TPosBaseChessBoardLayer;

    FHandler: TGameChessBoardHandler;

    auto_flag: boolean; // ��������� ���������
    player_time: array[TFigureColor] of TDateTime; // ����� ����� � ������
    past_time: TDateTime; // ����� ������ ����������� ����
    unlimited_var: array[TFigureColor] of boolean; // ������ ��� ���������� ��������
    clock_color: TFigureColor; // ���� ����������� ������

    shuted: boolean; // ��������� �������� �������� ����

    // Resizing
    m_ResizingType: (rtNo, rtHoriz, rtVert);
//    m_iDeltaWidthHeight: integer;

    m_iTimePanelInitialWidth: integer;
    m_iWhitePanelInitialLeft, m_iBlackPanelInitialLeft: integer;
    m_iWhitePanelInitialWidth, m_iBlackPanelInitialWidth: integer;
    m_TimeFont: TFont;

    m_bFlashOnMove: boolean; // flag for flashing window on icoming move

{$IFDEF THREADED_CHESSCLOCK}
    TimeLabelThread: TTimeLabelThread; // ���� ������������ ��� ������ � ����� � �������
{$ENDIF}

    function FGetMode: TMode;
    procedure FSetMode(const Value: TMode);
    procedure ShowTime(const c: TFigureColor);
    function FGetPlayerColor: TFigureColor;
    procedure FSetPlayerColor(const Value: TFigureColor);
    function FGetFlipped: boolean;
    procedure FSetFlipped(bValue: boolean);
    function FGetTime(color: TFigureColor): TDateTime;
    procedure FSetTime(color: TFigureColor; const tm: TDateTime);
    procedure FSetUnlimited(color: TFigureColor; const unl: boolean);
    function FGetUnlimited(color: TFigureColor): boolean;
    function FGetLastMoveHilighted: boolean;
    procedure FSetLastMoveHilighted(bValue: boolean);
    function FGetCoordinatesShown: boolean;
    procedure FSetCoordinatesShown(bValue: boolean);
    function GetStayOnTop: boolean;
    procedure FSetStayOnTop(onTop: boolean);
    procedure FSetAutoFlag(auto_flag: boolean);
    procedure FFlashWindow;
    function FGetAnimation: TAnimation;
    procedure FSetAnimation(const Value: TAnimation);
    function FGetViewGaming: boolean;
    procedure FSetViewGaming(bValue: boolean);

    // Localization
    procedure ILocalizable.Localize = FLocalize;
    procedure FLocalize;

    procedure WMMoving(var Msg: TWMMoving); message WM_MOVING;
    procedure WMSizing(var Msg: TMessage); message WM_SIZING;

    function FGetPositionColor: TFigureColor;

    function FGetTrainingMode: boolean;
    procedure FSetTrainingMode(bValue: boolean);

    function FGetUseUserBase: boolean;
    procedure FSetUseUserBase(bValue: boolean);

    procedure FChessBoardHandler(e: TChessBoardEvent; d1: pointer = nil;
      d2: pointer = nil);
    procedure FDoHandler(e: TGameChessBoardEvent; d1: pointer = nil;
      d2: pointer = nil);

  public
    constructor Create(Owner: TComponent; AHandler: TGameChessBoardHandler = nil;
      const strPosBaseName: string = ''); reintroduce;

    procedure FCreateChessBoard(const strPosBaseName: string);
    procedure FDestroyChessBoard;

    procedure TakeBack; // ������ ���� �������
    procedure SwitchClock(clock_color: TFigureColor);
    procedure InitPosition;
    procedure PPRandom;
    procedure StopClock;

    procedure ResetMoveList;
    function SetPosition(const strPosition: string): boolean;
    function GetPosition: string;
    function NMoveDone: integer; // ���������� ��������� �����
    function DoMove(const strMove: string): boolean;
    procedure Shut;

    procedure WriteGameToBase(vGameResult: TGameResult);
    procedure SetExternalBase(const strExtPosBaseName: string);
    procedure UnsetExternalBase;

    property Unlimited[color: TFigureColor]: boolean read FGetUnlimited write FSetUnlimited;
    property Time[color: TFigureColor]: TDateTime read FGetTime write FSetTime;
    property PlayerColor: TFigureColor read FGetPlayerColor write FSetPlayerColor;
    property PositionColor: TFigureColor read FGetPositionColor; // Whos move it is in the current position
    property ClockColor: TFigureColor read clock_color;
    property Mode: TMode read FGetMode write FSetMode;
    property CoordinatesShown: boolean read FGetCoordinatesShown write FSetCoordinatesShown;

    property Flipped: boolean read FGetFlipped write FSetFlipped;
    property LastMoveHilighted: boolean read FGetLastMoveHilighted write FSetLastMoveHilighted;
    property FlashOnMove: boolean read m_bFlashOnMove write m_bFlashOnMove;
    property StayOnTop: boolean read GetStayOnTop write FSetStayOnTop;
    property AutoFlag: boolean read auto_flag write FSetAutoFlag;
    property Animation: TAnimation read FGetAnimation write FSetAnimation;
    property ViewGaming: boolean read FGetViewGaming write FSetViewGaming;

    property pTrainingMode: boolean read FGetTrainingMode write FSetTrainingMode;
    property pUseUserBase: boolean read FGetUseUserBase write FSetUseUserBase;
  end;

implementation

{$J+}

{$R *.dfm}

uses
  SysUtils, Types, Windows,
  //
  ChessClockUnit;

const
  TIME_COLOR = clBlack;

  ZEITNOT_COLOR = clMaroon;
//  CHEAT_TIME_CONST = 1.5; // > 1
  WHITE_LONG_LABEL: WideString   =   'White   ';
  WHITE_MEDIUM_LABEL: WideString = 'White ';
  WHITE_SHORT_LABEL: WideString  =  'W ';
  BLACK_LONG_LABEL: WideString   =   'Black   ';
  BLACK_MEDIUM_LABEL: WideString = 'Black ';
  BLACK_SHORT_LABEL: WideString  =  'B ';

////////////////////////////////////////////////////////////////////////////////
// TTimeLabelThread

{$IFDEF THREADED_CHESSCLOCK}
procedure TTimeLabelThread.Execute;
begin
  while ChessBoard.GameTimer.Enabled do
    begin
      if self.player_time[fcWhite] <> ChessBoard.player_time[fcWhite] then
        ChessBoard.ShowTime(fcWhite);
      if self.player_time[fcBlack] <> ChessBoard.player_time[fcBlack] then
        ChessBoard.ShowTime(fcBlack);
      Sleep(ChessBoard.GameTimer.Interval div 2);
    end;
  ChessBoard.TimeLabelThread := nil;  
end;


constructor TTimeLabelThread.Create(ChessBoard: TGameChessBoard);
begin
  self.ChessBoard := ChessBoard;
  self.player_time[fcWhite] := ChessBoard.player_time[fcWhite];
  self.player_time[fcBlack] := ChessBoard.player_time[fcBlack];

  inherited Create(TRUE);
//Priority := tpNormal;
  FreeOnTerminate := TRUE;
  Resume;
end;
{$ENDIF}

////////////////////////////////////////////////////////////////////////////////
// TGameChessBoard

function TGameChessBoard.DoMove(const strMove: string): boolean;
begin
  Result := m_ChessBoard.DoMove(strMove);
  if (Result) then
  begin
    if (m_bFlashOnMove and (Mode = mGame)) then
      FFlashWindow;
  end;
end;


procedure TGameChessBoard.ShowTime(const c: TFigureColor);
var
  time_label: TLabel;
begin
  if c = fcWhite then time_label:= WhiteTimeLabel
    else time_label:= BlackTimeLabel;

  if unlimited_var[c] then
    begin
      time_label.Caption:= '';
      exit;
    end;

  if (TChessClock.IsZeitnot(player_time[c])) then
    time_label.Font.Color := ZEITNOT_COLOR
  else
    time_label.Font.Color := TIME_COLOR;

  time_label.Caption := TChessClock.ConvertToStr(player_time[c]);
end;


procedure TGameChessBoard.ResetMoveList;
begin
  m_ChessBoard.ResetMoveList;
end;


function TGameChessBoard.SetPosition(const strPosition: string): boolean;
begin
  Result := m_ChessBoard.SetPosition(strPosition);
  if (Result) then
    clock_color := PositionColor;
end;


function TGameChessBoard.GetPosition: string;
begin
  Result := m_ChessBoard.GetPosition;
end;


procedure TGameChessBoard.FormCreate(Sender: TObject);
begin
  m_iTimePanelInitialWidth := TimePanel.Width;
  m_iWhitePanelInitialLeft := WhitePanel.Left;
  m_iWhitePanelInitialWidth := WhitePanel.Width;
  m_iBlackPanelInitialLeft := BlackPanel.Left;
  m_iBlackPanelInitialWidth := BlackPanel.Width;

  m_TimeFont := TFont.Create;
  m_TimeFont.Assign(WhiteTimeLabel.Font);

  BlackFlagButton.Glyph := WhiteFlagButton.Glyph; // For size minimization

  TLocalizer.Instance.AddSubscriber(self);
  FLocalize;

  // Clock initialization
  FSetUnlimited(fcWhite, TRUE);
  FSetUnlimited(fcBlack, TRUE);
end;


constructor TGameChessBoard.Create(Owner: TComponent;
  AHandler: TGameChessBoardHandler = nil; const strPosBaseName: string = '');
begin
  FHandler := AHandler;
  inherited Create(Owner);
  FCreateChessBoard(strPosBaseName);
end;


procedure TGameChessBoard.FCreateChessBoard(const strPosBaseName: string);
begin
  m_ChessBoard := TChessBoard.Create(self, FChessBoardHandler);
  m_PosBaseChessBoardLayer := TPosBaseChessBoardLayer.Create(strPosBaseName);

  m_ChessBoard.AddLayer(m_PosBaseChessBoardLayer);

  with ChessBoardPanel do
    SetBounds(Left, Top, m_ChessBoard.ClientWidth, m_ChessBoard.ClientHeight);

  m_ChessBoard.BorderStyle := bsNone;
  m_ChessBoard.Align := alClient;
  m_ChessBoard.Parent := ChessBoardPanel;
  m_ChessBoard.Visible := TRUE;

  InitPosition;
end;


procedure TGameChessBoard.FDestroyChessBoard;
begin
  m_ChessBoard.RemoveLayer(m_PosBaseChessBoardLayer); // m_ChessBoard is destroyed by its parent
  FreeAndNil(m_PosBaseChessBoardLayer);
end;


procedure TGameChessBoard.FormDestroy(Sender: TObject);
begin
  TLocalizer.Instance.DeleteSubscriber(self);

  m_TimeFont.Free;

  FDestroyChessBoard;
end;


procedure TGameChessBoard.InitPosition;
begin
  m_ChessBoard.InitPosition;
end;


procedure TGameChessBoard.FSetMode(const Value: TMode);
begin
  m_ChessBoard.Mode := Value;
  if (Value <> mGame) then
  begin
    WhiteFlagButton.Visible := FALSE;
    BlackFlagButton.Visible := FALSE;
  end;
end;


function TGameChessBoard.FGetMode: TMode;
begin
  Result := m_ChessBoard.Mode;
end;


procedure TGameChessBoard.FSetTime(color: TFigureColor; const tm: TDateTime);
begin
  if (not Unlimited[color]) then
  begin
    if ((not auto_flag) and (not ViewGaming)) then
    begin
      case color of
        fcWhite:
          WhiteFlagButton.Visible := ((PlayerColor = fcBlack) and (tm = 0.0));
        fcBlack:
          BlackFlagButton.Visible := ((PlayerColor = fcWhite) and (tm = 0.0));
      end;
    end;
    player_time[color] := tm;
    ShowTime(color);
  end;
end;


function TGameChessBoard.FGetTime(color: TFigureColor): TDateTime;
begin
  Result:= player_time[color];
end;


procedure TGameChessBoard.GameTimerTimer(Sender: TObject);
begin
  if unlimited_var[clock_color] then
    begin
      GameTimer.Enabled := FALSE;
      exit;
    end;
  // TODO: cheating check
  player_time[clock_color] := player_time[clock_color] - (Now - past_time);
  if player_time[clock_color] <= 0.0 then
    begin
      player_time[clock_color] := 0.0;
      ShowTime(clock_color);
      if ((not auto_flag) and (PlayerColor <> clock_color) and (not ViewGaming)) then
      begin
        case clock_color of
          fcWhite:
            WhiteFlagButton.Visible := TRUE;
          fcBlack:
            BlackFlagButton.Visible := TRUE;
        end;
      end;
      if ((PlayerColor <> clock_color) and (Mode = mGame) and (auto_flag)) then
        FDoHandler(cbeTimeOut, self);
      GameTimer.Enabled := FALSE;
    end;
{$IFNDEF THREADED_CHESSCLOCK}
  ShowTime(clock_color);
{$ENDIF}

  past_time:= Now;
end;


procedure TGameChessBoard.FSetUnlimited(color: TFigureColor; const unl: boolean);
begin
  unlimited_var[color]:= unl;
  ShowTime(color);
end;


function TGameChessBoard.FGetUnlimited(color: TFigureColor): boolean;
begin
  Result := unlimited_var[color];
end;


procedure TGameChessBoard.SwitchClock(clock_color: TFigureColor);
begin
  self.clock_color := clock_color;
  if (not GameTimer.Enabled) then
  begin
    past_time := Now;
    GameTimer.Enabled := TRUE;
  end;
  if (Mode = mGame) then
    FDoHandler(cbeClockSwitched, self);
  ShowTime(clock_color);

{$IFDEF THREADED_CHESSCLOCK}
  if (not Assigned(TimeLabelThread)) then
    TimeLabelThread := TTimeLabelThread.Create(self);
{$ENDIF}
end;


procedure TGameChessBoard.FSetPlayerColor(const Value: TFigureColor);
begin
  m_ChessBoard.PlayerColor := Value;
end;


function TGameChessBoard.FGetPlayerColor: TFigureColor;
begin
  Result := m_ChessBoard.PlayerColor;
end;


procedure TGameChessBoard.StopClock;
begin
  GameTimer.Enabled := FALSE;
  WhiteFlagButton.Visible := FALSE;
  BlackFlagButton.Visible := FALSE;
end;


procedure TGameChessBoard.FormCanResize(Sender: TObject; var NewWidth,
  NewHeight: Integer; var Resize: Boolean);
var
  iNewChessBoardWidth, iNewChessBoardHeight: integer;
begin
  Resize := (m_ResizingType <> rtNo);
  if (not Resize) then
    exit;

  iNewChessBoardWidth := m_ChessBoard.Width + (NewWidth - self.Width);
  iNewChessBoardHeight := m_ChessBoard.Height + (NewHeight - self.Height);

  m_ChessBoard.FormCanResize(self, iNewChessBoardWidth, iNewChessBoardHeight, Resize);
  if (Resize) then
  begin
    NewWidth := self.Width + (iNewChessBoardWidth - m_ChessBoard.Width);
    NewHeight := self.Height + (iNewChessBoardHeight - m_ChessBoard.Height);
  end;
end;

procedure TGameChessBoard.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  if (not shuted) then
  begin
    FDoHandler(cbeExit, self);
    Action:= caNone;
  end
  else
    shuted := FALSE;
end;


procedure TGameChessBoard.Shut;
begin
  shuted:= TRUE;
  Close;
end;


procedure TGameChessBoard.PPRandom;
begin
  m_ChessBoard.PPRandom;
end;


procedure TGameChessBoard.TakeBack;
begin
  m_ChessBoard.TakeBack;
end;


function TGameChessBoard.FGetLastMoveHilighted: boolean;
begin
  Result := m_ChessBoard.LastMoveHilighted;
end;


procedure TGameChessBoard.FSetLastMoveHilighted(bValue: boolean);
begin
  m_ChessBoard.LastMoveHilighted := bValue;
end;


procedure TGameChessBoard.FSetCoordinatesShown(bValue: boolean);
begin
  m_ChessBoard.CoordinatesShown := bValue;
end;


function TGameChessBoard.FGetCoordinatesShown: boolean;
begin
  Result := m_ChessBoard.CoordinatesShown;
end;


function TGameChessBoard.NMoveDone: integer;
begin
  Result := m_ChessBoard.NMoveDone;
end;


procedure TGameChessBoard.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  FDoHandler(cbeKeyPressed, Pointer(Key), self);
end;


function TGameChessBoard.GetStayOnTop: boolean;
begin
  Result := (self.FormStyle = fsStayOnTop);
end;


procedure TGameChessBoard.FSetStayOnTop(onTop: boolean);
begin
  if (onTop) then
    self.FormStyle := fsStayOnTop
  else
    self.FormStyle := fsNormal;
end;


procedure TGameChessBoard.FormActivate(Sender: TObject);
begin
  FDoHandler(cbeActivate, self);
end;


procedure TGameChessBoard.WMMoving(var Msg: TWMMoving);
begin
  // TODO: it's possible to handle if form is outside of the screen
  FDoHandler(cbeFormMoving, Pointer(Msg.DragRect.Left - Left), Pointer(Msg.DragRect.Top - Top));
  inherited;
end;


procedure TGameChessBoard.WMSizing(var Msg: TMessage);
begin
  m_ChessBoard.Perform(Msg.Msg, Msg.WParam, Msg.LParam);

  case Msg.WParam of
    WMSZ_RIGHT, WMSZ_LEFT, WMSZ_BOTTOMRIGHT, WMSZ_TOPLEFT:
      m_ResizingType := rtHoriz;
    WMSZ_BOTTOM, WMSZ_TOP:
      m_ResizingType := rtVert;
  else
    begin
      m_ResizingType := rtNo;
      PRect(Msg.LParam).Left := Left;
      PRect(Msg.LParam).Top := Top;
    end;
  end; // case
end;


function TGameChessBoard.FGetPositionColor: TFigureColor;
begin
  Result := m_ChessBoard.PositionColor;
end;


procedure TGameChessBoard.FlagButtonClick(Sender: TObject);
begin
  if (Mode = mGame) then
    FDoHandler(cbeTimeOut, self);
end;


procedure TGameChessBoard.FSetAutoFlag(auto_flag: boolean);
begin
  self.auto_flag := auto_flag;
  if (auto_flag) then
  begin
    WhiteFlagButton.Visible := FALSE;
    BlackFlagButton.Visible := FALSE;
  end;
end;


procedure TGameChessBoard.TimePanelResize(Sender: TObject);
var
  rRatio: real;
begin
  // Adjust panels on TimePanel
  rRatio := TimePanel.Width / m_iTimePanelInitialWidth;
  WhitePanel.Left := Round(rRatio * m_iWhitePanelInitialLeft);
  WhitePanel.Width := m_iWhitePanelInitialWidth;
  BlackPanel.Left := Round(rRatio * m_iBlackPanelInitialLeft);
  BlackPanel.Width := m_iBlackPanelInitialWidth;


  WhiteTimeLabel.Font.Assign(m_TimeFont);
  BlackTimeLabel.Font.Assign(m_TimeFont);
  
  if (WhitePanel.Left + WhitePanel.Width < BlackPanel.Left) then
  begin
    WhiteLabel.Caption := WHITE_LONG_LABEL;
    BlackLabel.Caption := BLACK_LONG_LABEL;
  end
  else
  begin
    WhitePanel.Left := 4;
    WhitePanel.Width := TimePanel.Width div 2;
    BlackPanel.Left := TimePanel.Width div 2;
    BlackPanel.Width := TimePanel.Width div 2 - 4;

    WhiteLabel.Caption := WHITE_MEDIUM_LABEL;
    BlackLabel.Caption := BLACK_MEDIUM_LABEL;
  end;

  // Adjust color labels
  if ((WhiteTimeLabel.Left + WhiteTimeLabel.Width > WhitePanel.Width) or
      (BlackTimeLabel.Left + BlackTimeLabel.Width > BlackPanel.Width)) then
  begin
    WhiteLabel.Caption := WHITE_MEDIUM_LABEL;
    BlackLabel.Caption := BLACK_MEDIUM_LABEL;
    if ((WhiteTimeLabel.Left + WhiteTimeLabel.Width <= WhitePanel.Width) and
      (BlackTimeLabel.Left + BlackTimeLabel.Width <= BlackPanel.Width)) then
      exit; // TODO: a KLUDGE - make it nice!
  
    WhiteTimeLabel.Font.Size := WhiteTimeLabel.Font.Size - 4;
    BlackTimeLabel.Font.Size := BlackTimeLabel.Font.Size - 4;
    WhiteLabel.Caption := WHITE_SHORT_LABEL;
    BlackLabel.Caption := BLACK_SHORT_LABEL;
  end;
end;


procedure TGameChessBoard.FFlashWindow;
var
  flushWindowInfo: TFlashWInfo;
begin
 // Flash with taskbar
 flushWindowInfo.cbSize := SizeOf(flushWindowInfo);
 flushWindowInfo.hwnd := Application.Handle;
 flushWindowInfo.dwflags := FLASHW_TRAY; // FLASHW_ALL; //FLASHW_TRAY;
 flushWindowInfo.ucount := 3; // Flash times
 flushWindowInfo.dwtimeout := 0; // speed in msec, 0 - frequency of cursor flashing
 FlashWindowEx(flushWindowInfo);

 if (self.Focused) then
   exit;
 // Flash window
 flushWindowInfo.hwnd := self.Handle; // handle of the flashing window
 flushWindowInfo.dwflags := FLASHW_CAPTION; // FLASHW_TRAY; // FLASHW_ALL; //FLASHW_TRAY;
 FlashWindowEx(flushWindowInfo);
end;


procedure TGameChessBoard.FLocalize;
begin
  with TLocalizer.Instance do
  begin
    WHITE_LONG_LABEL := GetLabel(13);
    WHITE_MEDIUM_LABEL := GetLabel(14);
    WHITE_SHORT_LABEL := GetLabel(15);
    BLACK_LONG_LABEL := GetLabel(16);
    BLACK_MEDIUM_LABEL := GetLabel(17);
    BLACK_SHORT_LABEL := GetLabel(18);
  end;

  TimePanelResize(nil);
end;


procedure TGameChessBoard.WriteGameToBase(vGameResult: TGameResult);
begin
  m_PosBaseChessBoardLayer.WriteGameToBase(vGameResult);
end;


procedure TGameChessBoard.SetExternalBase(const strExtPosBaseName: string);
begin
  m_PosBaseChessBoardLayer.SetExternalBase(strExtPosBaseName);
end;


procedure TGameChessBoard.UnsetExternalBase;
begin
  m_PosBaseChessBoardLayer.UnsetExternalBase;
end;


function TGameChessBoard.FGetTrainingMode: boolean;
begin
  Result := m_PosBaseChessBoardLayer.TrainingMode;
end;


procedure TGameChessBoard.FSetTrainingMode(bValue: boolean);
begin
  m_PosBaseChessBoardLayer.TrainingMode := bValue;
end;


function TGameChessBoard.FGetUseUserBase: boolean;
begin
  Result := m_PosBaseChessBoardLayer.UseUserBase;
end;


procedure TGameChessBoard.FSetUseUserBase(bValue: boolean);
begin
  m_PosBaseChessBoardLayer.UseUserBase := bValue;
end;


function TGameChessBoard.FGetFlipped: boolean;
begin
  Result := m_ChessBoard.Flipped;
end;


procedure TGameChessBoard.FSetFlipped(bValue: boolean);
begin
  m_ChessBoard.Flipped := bValue;
end;


function TGameChessBoard.FGetAnimation: TAnimation;
begin
  Result := m_ChessBoard.Animation;
end;


procedure TGameChessBoard.FSetAnimation(const Value: TAnimation);
begin
  m_ChessBoard.Animation := Value;
end;


function TGameChessBoard.FGetViewGaming: boolean;
begin
  Result := m_ChessBoard.ViewGaming;
end;


procedure TGameChessBoard.FSetViewGaming(bValue: boolean);
begin
  m_ChessBoard.ViewGaming := bValue;
end;


procedure TGameChessBoard.FChessBoardHandler(e: TChessBoardEvent; d1: pointer = nil;
  d2: pointer = nil);
begin
  case e of
    ChessBoardUnit.cbeMate:
      FDoHandler(cbeMate, self);

    ChessBoardUnit.cbeStaleMate:
      FDoHandler(cbeStaleMate, self);

    ChessBoardUnit.cbeMoved:
    begin
      if ((Mode = mGame) and (PositionColor <> PlayerColor)) then
        FDoHandler(cbeMoved, d1, self);
      SwitchClock(PositionColor);      
    end;

    ChessBoardUnit.cbeMenu:
      FDoHandler(cbeMenu, self);
  end;
end;


procedure TGameChessBoard.FDoHandler(e: TGameChessBoardEvent; d1: pointer = nil;
  d2: pointer = nil);
begin
  if (Assigned(FHandler)) then
    FHandler(e, d1, d2);
end;

end.