///////////////////////////////////////////////////////////////////////
// Copyright (C) Andru 2007                                          //
// mail: dr.andru@gmail.com                                          //
// site: http://andru.2x4.ru                                         //
//                                                                   //
// OMEGA Engine is free software.                                    //
//                                                                   //
// You may redistribute it and/or modify it under the terms of the   //
// GNU General Public License, as published by the Free Software     //
// Foundation; either version 2 of the License, or (at your option)  //
// any later version.                                                //
//                                                                   //
// this module is distributed in the hope that it will be useful,    //
// but WITHOUT ANY WARRANTY; without even the implied warranty of    //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.              //
// See the GNU General Public License for more details.              //
//                                                                   //
// You should have received a copy of the GNU General Public License //
// along with this module.  If not, write to:                        //
// 	The Free Software Foundation, Inc.,                              //
// 	51 Franklin Street, Fifth Floor                                  //
// 	Boston, MA  02110-1301, USA.                                     //
///////////////////////////////////////////////////////////////////////
unit ENGINE_CONSOLE;

{$I DEFINES.pas}

interface
uses
  Windows,

  TEXTURE_MANAGER,

  ENGINE_CONST,
  ENGINE_VAR,
  ENGINE_UTILS,

  ENGINE_LOG,

  INPUT_KEYBOARD,

  G2D_CAMERA,

  G2D_TEXT,
  G2D_PRIMITIVES,
  G2D_SSPRITE,

  MATH_FAST,

  UTILS;


procedure Console_AddChar( Symbol : Char );
procedure Console_Backspace;

procedure Console_Active( Enable : Boolean ); stdcall;
procedure Console_SetOptions( Font      : PFont2D;
                              Texture   : PTexture;
                              Color     : Integer;
                              Alpha     : Byte;
                              FontColor : Integer;
                              FontAlpha : Byte ); stdcall;
procedure Console_ToLog( Connect : Boolean ); stdcall;
procedure Console_Draw; stdcall;
procedure Console_Process( wParam : DWORD ); stdcall;

procedure Console_RegCommand( Command : PChar; Execute : Pointer ); stdcall;
procedure Console_RegVariable( VarName : PChar; Variable : Pointer ); stdcall;
procedure Console_RegProcedure( ProcName : PChar; ProcPtr : Pointer ); stdcall;
procedure Console_AddString( Str : PChar ); stdcall;

const
  CONSOLE_VARTYPE_INTEGER = 0;
  CONSOLE_VARTYPE_STRING  = 1;

type
  TCommand = record
    Proc     : Procedure;
    Command  : String;
end;

type
  TVariable = record
    Name    : String;
    Ptr     : Pointer;
end;

type
  TProcedure = record
    Proc     : Procedure( Attrib : PChar );
    Name     : String;
end;

type
  TConsole = record
    Enable : Boolean;
    Active : Boolean;
    ToLog  : Boolean;

    Commands  : array of TCommand;
    CommCount : Integer;
    Variables : array of TVariable;
    VarCount  : Integer;
    Procedures: array of TProcedure;
    ProcCount : Integer;
    Messages  : array of String;
    MessCount : Integer;
    Message   : String;

    Y : Double;

    Font      : PFont2D;
    FontColor : Integer;
    FontAlpha : Byte;

    Alpha   : Byte;
    Color   : Integer;

    Texture : PTexture;
end;

var
  Console : TConsole;

//----------------------------------------------------------------------------//
                                 IMPLEMENTATION
//----------------------------------------------------------------------------//
uses
 ENGINE_SCREEN;

procedure Console_AddChar;
Begin
Console.Message := Console.Message + Symbol;
End;

procedure Console_AddString;
Begin
INC( Console.MessCount );
SetLength( Console.Messages, Console.MessCount );
Console.Messages[ Console.MessCount - 1 ] := Str;

if Console.ToLog Then
  LOG_AddMessage( LOGT_CONSOLE, PChar( '"' + Str + '"' ) );
End;

procedure Console_Backspace;
Begin
if Length( Console.Message ) > 0 Then
  Delete( Console.Message, Length( Console.Message ), 1 );
End;

procedure Console_Active;
Begin
Console.Enable := Enable;
End;

procedure Console_SetOptions;
Begin
Console.Font      := Font;
Console.Texture   := Texture;
Console.Color     := Color;
Console.Alpha     := Alpha;
Console.FontColor := FontColor;
Console.FontAlpha := FontAlpha;
End;

procedure Console_ToLog;
Begin
Console.ToLog := Connect;
End;

procedure Console_Draw;
  var
    i : Integer;
    c : Single;
    t : Char;
    W, Y : Single;
    CA : Boolean;
Begin
CA := Cam2D.Active;
Cam2D.Active := FALSE;
if Console.Font = nil Then Exit;
if not Console.Active Then
  begin
    if Console.Y > 0 Then Console.Y := Console.Y - 500 / ( OE_GetFPS + 1 )
  end else
    if OE_GetFPS > 5 Then
      if Console.Y < ogl_Height shr 1 Then Console.Y := Console.Y + 500 / ( OE_GetFPS + 1 );
Y := Console.Y / scr_ScaleY;
W := ogl_Width / scr_ScaleX;

if Console.Texture = nil Then
  Pr2D_Rect( 0, 0, W, Y, Console.Color, Console.Alpha, PR_FILL )
else
  SSprite_Draw( Console.Texture, 0, 0, ogl_Width, Y, Console.Alpha, 0, 1 );
Pr2D_Rect( 0, Y - 1, W, 1, $FFFFFF, 255, PR_FILL );

c := Console.MessCount - 1;
if c > Y / Console.Font.Height Then c := Y / Console.Font.Height;
for i := M_Round( c ) downto 0 do
  Text_Draw( Console.Font,
             10, Y - i * Console.Font.Height - Console.Font.Height * 3,
             PChar( Console.Messages[ Console.MessCount - 1 - i ] ), 1, 0,
             Console.FontAlpha, Console.FontColor );

i := random( 2 );
if i = 1 Then t := '_' else t := ' ';
Text_Draw( Console.Font,
           10, Y - Console.Font.Height * 2, PChar( '> ' + Console.Message + t ), 1, 0,
           Console.FontAlpha, Console.FontColor );

Text_Draw( Console.Font,
           W - Text_GetWidth( Console.Font, PChar( wnd_ClassName + ' ' + OE_VERSION ), 1, 0 ),
           Y - Console.Font.Height, PChar( wnd_ClassName + ' ' + OE_VERSION ), 1, 0,
           255, $FFFFFF );

Cam2D.Active := CA;
End;

procedure Console_Process;
  var
    i      : Integer;
    S1, S2 : String;

  function GetVarName : String;
    var
      i : Integer;
  Begin
    Result := '';
    if Console.Message <> '' Then
      for i := 1 to Length( Console.Message ) do
        if Console.Message[ i ] <> ' ' Then
          Result := Result + Console.Message[ i ]
        else
          exit;
  End;
  function GetVarValue : String;
    var
      i : Integer;
      s : Boolean;
  Begin
    s := FALSE;
    Result := '';
    if Console.Message <> '' Then
      for i := 1 to Length( Console.Message ) do
        begin
          if Console.Message[ i ] = ' ' Then
            if not s Then
              begin
                if i = Length( Console.Message ) Then
                  begin
                    Result := ' ';
                    exit;
                  end;
                s := TRUE;
                continue;
              end;
          if s Then
            Result := Result + Console.Message[ i ];
        end;
  End;
Begin
if ( Chr( wParam ) = '~' ) or
   ( Chr( wParam ) = '`' ) or
   ( Chr( wParam ) = '¸' ) or
   ( Chr( wParam ) = '¨' ) Then
  begin
    Console.Active := not Console.Active;
    Exit;
  end;
if Console.Active and Console.Enable Then
  begin
    if ( wParam = 13 ) and ( Console.Message <> '' ) Then
      begin
        if @app_ConsoleMessage <> nil Then
          app_ConsoleMessage( PChar( Console.Message ), Length( Console.Message ) );
        S1 := StrUp( GetVarName );
        for i := 0 to Console.VarCount - 1 do
          begin
            S2 := StrUp( Console.Variables[ i ].Name );
            if S1 = S2 Then
              begin
                S2 := GetVarValue;
                Console_AddString( PChar( Console.Message ) );
                PInteger( Console.Variables[ i ].Ptr )^ := U_StrToInt( PChar( S2 ) );
                Console.Message := '';
                exit;
              end;
          end;

        S1 := StrUp( GetVarName );
        for i := 0 to Console.ProcCount - 1 do
          begin
            S2 := StrUp( Console.Procedures[ i ].Name );
            if S1 = S2 Then
              begin
                S2 := GetVarValue;
                Console_AddString( PChar( Console.Message ) );
                Console.Procedures[ i ].Proc( PChar( S2 ) );
                Console.Message := '';
                exit;
              end;
          end;

        for i := 0 to Console.CommCount - 1 do
          begin
            S1 := StrUp( Console.Message );
            S2 := StrUp( Console.Commands[ i ].Command );
            if S1 = S2 Then
              begin
                Console_AddString( PChar( Console.Message ) );
                Console.Commands[ i ].Proc;
                Console.Message := '';                
                exit;
              end;
          end;

        Console_AddString( PChar( Console.Message + ERR_UNKNOWN_COMMAND ) );
        Console.Message := '';
      end;
    if wParam >= 32 Then
      Console_AddChar( Chr( wParam ) );
    if wParam = 8 Then
      Console_BackSpace;
  end;
End;

procedure Console_RegCommand;
Begin
INC( Console.CommCount );
SetLength( Console.Commands, Console.CommCount );
Console.Commands[ Console.CommCount - 1 ].Command := Command;
Console.Commands[ Console.CommCount - 1 ].Proc    := Execute;
End;

procedure Console_RegVariable;
Begin
INC( Console.VarCount );
SetLength( Console.Variables, Console.VarCount );
Console.Variables[ Console.VarCount - 1 ].Name    := VarName;
Console.Variables[ Console.VarCount - 1 ].Ptr     := Variable;
End;

procedure Console_RegProcedure;
Begin
INC( Console.ProcCount );
SetLength( Console.Procedures, Console.ProcCount );
Console.Procedures[ Console.ProcCount - 1 ].Name := ProcName;
Console.Procedures[ Console.ProcCount - 1 ].Proc := ProcPtr;
End;

initialization
  Console.Font      := nil;
  Console.Texture   := nil;
  Console.FontColor := $FFFFFF;
  Console.FontAlpha := 255;
  Console.Alpha     := 155;
  Console.Color     := 0;
  Console.Texture   := nil;
  Console.Active    := FALSE;
  Console.Enable    := FALSE;

end.
