unit UStatistics;
{ ********************************************************************************* }
{ (c) GNU                                                                           }
{ author: Heiko Tietze                                                              }
{ version: 1.0                                                                      }
{ date: 11.12.2004                                                                  }
{ description: form for visualization of statistics - placed words, computation     }
{              speed and highscores                                                 }
{ ********************************************************************************* }

{$I Def.inc}

interface

uses SysUtils, Variants, Classes, Messages, Math, Types, IniFiles,
     {$IFDEF VCL}
     Windows, Graphics, Controls, Forms, Dialogs, ComCtrls, StdCtrls, ExtCtrls, ImgList, Grids, Menus,
     {$ELSE}
     QGraphics, QControls, QForms, QDialogs, QComCtrls, QExtCtrls, QStdCtrls, QImgList, QGrids, QMenus,
     {$ENDIF}
     UTools, UGameOptions,ULanguage;

type TStatistics = class(TForm)
        PageControl   : TPageControl;
        tsMoves       : TTabSheet;
        sgMoves       : TStringGrid;
        PopupMenu     : TPopupMenu;
        ColorDialog   : TColorDialog;
        pmBkColor     : TMenuItem;
        pmN1          : TMenuItem;
        pmVertLine    : TMenuItem;
        pmHorzLine    : TMenuItem;
        tsHighScore   : TTabSheet;
        sgHighScore   : TStringGrid;
        procedure sgDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);
        procedure FormCreate(Sender: TObject);
        procedure sgMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
        procedure sgMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
        procedure FormShow(Sender: TObject);
        procedure FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
        procedure pmBkColorClick(Sender: TObject);
        procedure FormDestroy(Sender: TObject);
        procedure pmVertLineClick(Sender: TObject);
        procedure pmHorzLineClick(Sender: TObject);
        procedure FormActivate(Sender: TObject);
      private
        FSortOrder : (soUp=-1,soDown=+1);
        FColDown : Byte;
        FColor   : TColor;
        procedure Sort(Sender:TStringGrid; Value:integer);
      public
        function AddToHighScore(PlayerName:string;Value,PlayerCount:Word):boolean; //returns true in case of a new highscore
     end;

var Statistics: TStatistics;

implementation

{$IFDEF VCL}
  {$R *.dfm}
{$ELSE}
  {$R *.xfm}
{$ENDIF}

procedure TStatistics.FormCreate(Sender: TObject);
begin
  with TIniFile.Create(ChangeFileExt(Application.ExeName,'.ini')) do
  try
    FColor:=ReadInteger('Statistics','BkColor',clWhite);
    if ReadBool('Statistics','HorzLine',false) then sgMoves.Options:=sgMoves.Options+[goHorzLine]
                                               else sgMoves.Options:=sgMoves.Options-[goHorzLine];
    if ReadBool('Statistics','VertLine',false) then sgMoves.Options:=sgMoves.Options+[goVertLine]
                                               else sgMoves.Options:=sgMoves.Options-[goVertLine];
  finally
    Free;
  end;
end;

procedure TStatistics.FormActivate(Sender: TObject);
begin
  if Language<>nil then
  begin
    sgMoves.Cells[0,0]:=Language.Translate['Move'];   sgMoves.ColWidths[0]:=50;
    sgMoves.Cells[1,0]:=Language.Translate['Word'];   sgMoves.ColWidths[1]:=150;
    sgMoves.Cells[2,0]:=Language.Translate['Player']; sgMoves.ColWidths[2]:=150;
    sgMoves.Cells[3,0]:=Language.Translate['Score'];  sgMoves.ColWidths[3]:=50;
    sgHighScore.Cells[0,0]:=Language.Translate['Position'];  sgHighScore.ColWidths[0]:=45;
    sgHighScore.Cells[1,0]:=Language.Translate['Score'];     sgHighScore.ColWidths[1]:=45;
    sgHighScore.Cells[2,0]:=Language.Translate['Count'];     sgHighScore.ColWidths[2]:=45;
    sgHighScore.Cells[3,0]:=Language.Translate['Player'];    sgHighScore.ColWidths[3]:=150;
    sgHighScore.Cells[4,0]:=Language.Translate['Date'];      sgHighScore.ColWidths[4]:=150;
    pmBkColor.Caption:=Language.Translate['background color'];
    pmVertLine.Caption:=Language.Translate['vertical lines'];
    pmHorzLine.Caption:=Language.Translate['horizontal lines'];
  end;
end;

procedure TStatistics.FormDestroy(Sender: TObject);
begin
  with TIniFile.Create(ChangeFileExt(Application.ExeName,'.ini')) do
  try
    WriteInteger('Statistics','BkColor',FColor);
    WriteBool('Statistics','HorzLine',goHorzLine in sgMoves.Options);
    WriteBool('Statistics','VertLine',goVertLine in sgMoves.Options);
  finally
    Free;
  end;
  inherited;
end;

procedure TStatistics.FormShow(Sender: TObject);
var sl : TStringList;
    i  : integer;
    s  : string;
begin
  if sgMoves.RowCount>1 then sgMoves.FixedRows:=1;
  FSortOrder:=soUp;
  FColDown:=0;
  sl:=TStringList.Create;
  sl.Sorted:=true;
  try
    with TIniFile.Create(ChangeFileExt(Application.ExeName,'.ini')) do
    try
      ReadSectionValues('HighScores',sl);
      for i:=sl.Count-1 downto 0 do
      begin
        sgHighScore.Cells[0,sl.Count-i]:=inttostr(sl.Count-i);
        sgHighScore.Cells[1,sl.Count-i]:=IntToStr(StrToInt(sl.Names[i]));
        s:=sl.ValueFromIndex[i];
        sgHighScore.Cells[2,sl.Count-i]:=s[1];
        sgHighScore.Cells[3,sl.Count-i]:=copy(s,2,pos('@',s)-2);
        sgHighScore.Cells[4,sl.Count-i]:=copy(s,pos('@',s)+1,length(s)-pos('@',s));
      end;
    finally
      Free; //inifile
    end;
  finally
    sl.Free;
  end;
end;

procedure TStatistics.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
   if Key=ke_Escape then Close;
end;

procedure TStatistics.sgMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var aCol,aRow : integer;
begin
  (Sender as TStringGrid).MouseToCell(x,y,aCol,aRow);
  if aRow=0 then Sort(Sender as TStringGrid, aCol);
  (Sender as TStringGrid).Repaint;
end;

procedure TStatistics.sgMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var aCol,aRow : integer;
begin
  (Sender as TStringGrid).MouseToCell(x,y,aCol,aRow);
  FColDown:=aCol;
end;

procedure TStatistics.Sort(Sender:TStringGrid; Value: integer);
 function Swap(Col:integer):boolean;
 var i   : integer;
     tmp : string;
 begin
    for i:=0 to Sender.RowCount-1 do
    begin
      tmp:=Sender.Cells[i,Col];
      Sender.Cells[i,Col]:=Sender.Cells[i,Col+1];
      Sender.Cells[i,Col+1]:=tmp;
    end;
    Result:=true;
 end;
var i,j    : integer;
    swaped : boolean;
begin
   for i:=1 to Sender.RowCount-1 do
    begin
      swaped:=false;
      for j:=1 to Sender.RowCount-2 do
      begin
        if ((Sender=sgMoves) and (Value in [0,3])) or ((Sender=sgHighScore) and (Value in [0,1,2])) then
        begin
           if CompareValue(StrToInt(Sender.Cells[Value,j]),StrToInt(Sender.Cells[Value,j+1]))=integer(FSortOrder)
              then swaped:=Swap(j)
        end else
        if ((Sender=sgMoves) and (Value in [1,2])) or ((Sender=sgHighScore) and (Value=3)) then
        begin
           if AnsiCompareText(Sender.Cells[Value,j],Sender.Cells[Value,j+1])=integer(FSortOrder)
              then swaped:=Swap(j);
        end else
        if (Sender=sgHighScore) and (Value=4) then
        begin
           if CompareValue(StrToDateTime(Sender.Cells[Value,j]),StrToDateTime(Sender.Cells[Value,j+1]))=integer(FSortOrder)
              then swaped:=Swap(j)
        end;
      end;
      if not swaped then break;
    end;
    if FSortOrder=soUp then FSortOrder:=soDown else FSortOrder:=soUp;
end;

procedure TStatistics.sgDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);
var s:string;
begin
  with Sender as TStringGrid do
  begin
    if (aRow=0) then
    begin
      if FColDown=aCol then Frame3D(Canvas,Rect,clBtnShadow, clWhite, 1)
                       else Frame3D(Canvas,Rect,clWhite, clBtnShadow, 1);
      Canvas.Font.Color:=clBlack;
      Canvas.Brush.Color:=clBtnFace;
      Canvas.Brush.Style:=bsSolid;
    end else
    begin
      Canvas.Brush.Color:=FColor;
      if (Sender=sgMoves) then Canvas.Font.Color:=GameOptions.PlayerColor[StrToIntDef(Cells[1,aRow][1],-1)]
                          else Canvas.Font.Color:=clBlack;
    end;
    if (Sender=sgMoves) and (aRow>0) and (aCol=1)
       then s:=copy(Cells[aCol,aRow],2,length(Cells[aCol,aRow])-1)
       else s:=Cells[aCol,aRow];
    Canvas.FillRect(Rect);
    Canvas.TextRect(Rect, Rect.Left+3, Rect.Top+1,s);
  end;
end;

procedure TStatistics.pmBkColorClick(Sender: TObject);
begin
   ColorDialog.Color:=FColor;
   if ColorDialog.Execute then FColor:=ColorDialog.Color;
   sgMoves.Repaint;
   sgHighScore.Repaint;
end;

procedure TStatistics.pmVertLineClick(Sender: TObject);
begin
   pmVertLine.Checked:=not pmVertLine.Checked;
   with sgMoves do
     if pmVertLine.Checked then Options:=Options+[goVertLine]
                           else Options:=Options-[goVertLine];
   with sgHighScore do
     if pmVertLine.Checked then Options:=Options+[goVertLine]
                           else Options:=Options-[goVertLine];
end;

procedure TStatistics.pmHorzLineClick(Sender: TObject);
begin
   pmHorzLine.Checked:=not pmHorzLine.Checked;
   with sgMoves do
     if pmHorzLine.Checked then Options:=Options+[goHorzLine]
                           else Options:=Options-[goHorzLine];
   with sgHighScore do
     if pmHorzLine.Checked then Options:=Options+[goHorzLine]
                           else Options:=Options-[goHorzLine];
end;

function TStatistics.AddToHighScore(PlayerName: string; Value,PlayerCount: Word):boolean;
const NumberOfHighScores=20;
var sl:TStringList;
    i:integer;
    s:string;
begin
  sl:=TStringList.Create;
  sl.Sorted:=true;
  try
    with TIniFile.Create(ChangeFileExt(Application.ExeName,'.ini')) do
    try
      ReadSectionValues('HighScores',sl);
      EraseSection('HighScores');
      Value:=Value*PlayerCount;
      s:=inttostr(Value); while length(s)<5 do s:='0'+s;
      if sl.Count<NumberOfHighScores then Result:=true
                                     else Result:=s>sl.Names[0];
      sl.Add(s+sl.NameValueSeparator+inttostr(PlayerCount)+PlayerName+'@'+DateTimeToStr(Now));
      while sl.Count>NumberOfHighScores do sl.Delete(0);
      for i:=0 to sl.Count-1 do WriteString('HighScores',sl.Names[i],sl.ValueFromIndex[i]);
    finally
      Free;
    end;
  finally
    sl.Free;
  end;
end;

end.
