/* ============================================================================================= *
 * file:    console.h
 * created: 2002-03-18
 * coder:   [kon]
 * update:  2002-03-27
 * version: 0.9
 *
 * desc:        Implementierung einer Konsole für User.
 *              Supported Features: (Reihenfolge ihrer Programmierung)
 *               base class: Öffnen/Schließen eines Fensters
 *               Einfache Textur als Background
 *               Font
 *               einfache Eingabe in einen String, Input reading: A-Z und  0-9
 *               char Array für Command-Input-Recording
 *               Command Array mit VK_UP und VK_DOWN durchforstbar
 *               char Array für History-Recording
 *               History Array mit VK_LEFT und VK_RIGHT durchforstbar
 *               processing der Commands durch externe Funktion (kein Zugriff)
 *               zConsoleCommand Class fertig
 *               Dynamische Commands adden
 *               Vervollständigung von Inputs des Users, möglich durch VK_TAB
 *               Record der Inputs und History in Datei
 *
 * to do:       base version 0.9 finished, for 1.0: debugging, optimization
 *              Lesen von Zeichen: =?;/*+'<>,.:-()[]\
 *              2 scrollbare Texturen als Hintergrund (Q3), verzerrte Font bei (De)Aktivierung
 *              char Array durch String Arrays ersetzen (dynamische Arrays)
 *              variable Anzahl von History-Einträgen (dynamisch?)
 *              Verarbeitung einer Datei mit Commands
 *
 * problems:    Bei Command Searching durch VK_UP und VK_DOWN muss man bei Änderung der Such
 *               Richtung zweimal bestätigen. Vorher: VK_UP und dann 2x DOWN um Änderung zu
 *               erwirken. 
 *              Bei Darstellung von genau 100 Zeichen wird der letzte groß dargestellt
 *              History-Srolling mit VK_LEFT und VK_RIGHT. Besser wäre VK_PAGE_UP und DOWN
 * ============================================================================================= */

#ifndef ZED_CONSOLE_HEADER
#define ZED_CONSOLE_HEADER


/*************************************************************************************************/
/*************************************************************************************************/
// ***** Defs


// Vis-Options für Klasse
enum zconState {
   CON_ACTIVE,       // Con ganz geöffnet
   CON_INACTIVE,     // Con geschlossen
   CON_ACTIVATING,   // Con wird geöffnet
   CON_DEACTIVATING  // Con wird geschlossen
};


// Consolen Vertex
struct zconVertex {
   float x,y,z;
   float rhw;
   DWORD diffuse;
   float tu,tv;
};
#define D3DFVF_CONSOLE (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)


// Standard Var-Initialisierung
const DWORD VERTEX_DIFFUSE = 0xffffffff;       // Beginn: Vertex weiß
const zconState CON_STATE = CON_INACTIVE;      // Beginn: Console inaktiv
//const bool BACKGROUND_IMAGE = true;          // Beginn: Hintergrundbild anzeigen
#define FONT_NAME   "Courier"                  // Beginn: Courier als Font
const unsigned int FONT_HEIGHT = 11;           // Beginn: 11 als Höhe der Font (in Pixel?)
const unsigned int MAX_STR_LEN = 100;          // max. Länge eines Eingabe Strings
const unsigned int MAX_HISTORY_STR_LEN = 100;  // max. Länge eines History Strings
const DWORD FONT_LINE_COLOR = 0xffffffff;      // Beginn: Farbe des Input Strings
const DWORD FONT_HISTORY_COLOR = 0xffcacaca;   // Beginn: Farbe der Font der History
const unsigned int MAX_HISTORY_STRINGS = 128;  // Beginn: max. Anzahl von History Strings
const unsigned int MAX_COMMAND_STRINGS = 32;   // Beginn: max. Anzahl von Command Inputs


// in-class Defs
#define vlo 0
#define vro 1
#define vlu 2
#define vru 3


// Console Command
enum EConMsgParamID {
   CON_PARAM_UNKNOWN,   // darf eigentlich nie sein
   CON_PARAM_FLOAT,     // 'F'
   CON_PARAM_INT,       // 'I'
   CON_PARAM_STRING,    // 'S'
   CON_PARAM_BOOL       // 'B'
};


//-----------------------------------------
// paramCode "FFBIS" bedeutet:
// Param   Type
// 0   CON_PARAM_FLOAT
// 1   CON_PARAM_FLOAT
// 2   CON_PARAM_BOOL
// 3   CON_PARAM_INT
// 4   CON_PARAM_STRING
//-----------------------------------------
// the console vars
struct zConVars
{
   float f;
   bool  b;
   int   i;
   char *s;

   zConVars() { f=0.0f; b=true; i=0; s=NULL; }
};


/*************************************************************************************************/
/*************************************************************************************************/
// ***** Class Decl

class zConsoleCommand
{
friend class zConsole;

private:
   zConVars      *mVars;               // Werte für die Parameter
   unsigned int   miNumVars;           // Anzahl Werte
   zString        mszCommandString;    // zb. "fogcolor"
   zString          mszParamString;    // zb. "III" für 3 ints (R,G,B)
   zString          mszHelpString;     // zb. "<r> <g> <b>" wird zu "Usage: fogcolor <r> <g> <b>"
   void           (*mpFunc)(zConsoleCommand &command);  // Funktion die das Commando ausführt

public:
   // constructor und destructor
   zConsoleCommand();
   ~zConsoleCommand();
   zConsoleCommand(zString command, zString paramCodes, zString help);

   // get
   zString GetCommandString() const      { return mszCommandString;          }
   zString GetParamString() const        { return mszParamString;            }
   zString GetHelpString() const         { return mszHelpString;             }
   int GetNumParams() const              { return strlen(mszParamString);    }
   EConMsgParamID GetParamType(int i) const;
   zConVars* GetVars()                   { return mVars;                     }
   zConVars& GetVar(int i)               { return mVars[i];                  }

   // set
   void SetCommandString(zString str)    { mszCommandString=str; }
   void SetParamString(zString str)      { mszParamString=str; }
   void SetHelpString(zString str)       { mszHelpString=str; }
   void SetFunc(void (*func)(zConsoleCommand&))  { mpFunc = func;            }

   // misc
   bool HasValidParams();
   void CreateVarsFromStrings(zArray<zString>* params);

};

/*************************************************************************************************/

class zConsole
{
friend void Console_ShowAllCommands(zConsoleCommand &command);
private:

   const zString  mVersion;
   zString        mLogfile;
   bool           mbLogging;

   zconState      mState;              // Vis Eigenschaft der Console
   DWORD          mdwDiffuse;          // Vertexfarbe
   float          mfWidth, mfHeight;   // Breite, Höhe des Console Fensters (geöffnet)
   zString        mszTexfile;          // Dateistring auf Textur
   IDirect3DTexture8* mpTexture;       // Texturspeicher
   bool           mbIsValidTexture;    // Existiert Datei und ist Textur valid

   /* Hilfe-Blocks um RenderState zu setzen und dann wieder richtig zurückzusetzen. Mit StateBlock
    * setzen wir die gewünschten Änderungen und mit SavedBlock können wir die vorher gesetzten
    * States wieder setzen. Was aber nicht verändert wird ist SetTexture()
    */
   DWORD          mdwStateBlock, mdwSavedBlock;

   zconVertex     verts[4];            // Background für die Console

   zD3DFont       mFont;               // Font zum rendern der Schriftart
   zString        mszUsedFont;         // Verwendete Schriftart
   UINT           miFontHeight;        // Schriftgröße
   DWORD          mdwFontLineColor;    // Schriftfarbe für Inputstring
   DWORD          mdwFontHistoryColor; // Schriftfarbe der History

   char           mInput[MAX_STR_LEN]; // Eingabestring
   int            miInputPos;          // Position im Eingabestring

   char           maCommand[MAX_COMMAND_STRINGS][MAX_STR_LEN];      // Array der Command-Eingaben
   int            miNumCommands;       // Anzahl von gespeicherten Input-Commands
   int            miIndCommands;       // Index in Command-Array (zum überschreiben)
   int            miShowCommand;       // Command anzuzeigen bei Pfeil rauf/runter

   char           maHistory[MAX_HISTORY_STRINGS][MAX_HISTORY_STR_LEN];  // Array der History
   int            miNumHistoryEntries; // Anzahl History Einträge
   int            miIndHistory;        // Index für ersten Eintrag
   int            miHistoryOffset;     // Offset zum anzeigen

   void           (*mpFunc)(zString);    // Zeiger auf Funktion, die Commando bearbeitet.

   /* Legt Standard Vars für Console fest (Konstanten)
    */
   void PreInit();
   /* Erzeugt die nötigen StateBlocks um D3D Zustände zu erstellen
    */
   bool CreateStateBlocks();
   /* Speichert mInput in maCommand für später ab
    */
   void AddLineToCommandHistory();
   /* Speichert line in die History ein *reim*
    */
   void AddLineToHistory(zString& line);
   /* Vervollständigt mInput
    */
   void TryCommandComplete();

   /* Console Command Private*/
   zArray<zConsoleCommand>   mpCommands;

   /* Default Commands adden
    */
   void InitCommands();

   /* Verarbeitet ein korrektes Command
    */
   void ProcessCommand(zConsoleCommand &command);

   /* Verarbeitet eine Message, wo syntax/parameter/count falsch sein könnte
    */
   void ProcessMessage(zString message);

   /* Neues Command registrieren
    */
   void RegisterCommand(zConsoleCommand command);

   /* Gibt die Anzahl der Params in message zurück
    * zb. "100 20 240" würde 3 zurückgeben
    */
   int GetNumParamsInString(zString message);

   /* Erstellt Array von abgeschlossenen Strings
    * zb. "100 200 300", würde ein Array mit 3 Strings erstellen: ("100" "200" "300")
    * MUSS Anzahl von Strings zurückgeben??????
    */
   zArray<zString>* ConstructParams(zString paramstr);

public:
   zConsole()        : mVersion("0.9") { PreInit();  };
   ~zConsole()                         { Shutdown(); };

   /* Initialisierung der Console, Check Rückgabe!
    * width - Breite des Console Fensters
    * height - Höhe des Console Fensters
    * font - Schriftart
    * fontheight - Schriftgröße
    * texfile - optional: Dateistring mit Textur (am besten *.dds)
    * colorkey - Möglichkeit eine Farbe der Textur mit transparente Schwarz zu füllen
    * verdif - Diffuse Komponente der Vertices
    */
   bool Init(int width, int height, zString texfile=NULL, zString font=FONT_NAME,
             UINT fontheight=FONT_HEIGHT, DWORD colorkey=0, DWORD verdif=VERTEX_DIFFUSE);

   /* Unnötig da alles D3DPOOL_MANAGED ist; Besser jedoch Aufruf von Shutdown und Init()
    * void Restore();
    * bool Invalidate();
    */

   /* Shutdown der Console
    */
   void Shutdown();

   /* Rendern der Console
    */
   bool Render();

   /* Tastatureingaben der Console übergeben, kann Input von A-Z und 0-9 schreiben.
    * Enter: Process
    * Back: Löschen letzte Eingabe
    * Space: Fügt Leerzeichen ein
    */
   void Input(WPARAM input);

   /* Möglichkeit History-Strings zu adden durch externe Funktionen.
    * str - der History-Strings, maximal MAX_HISTORY_STR_LEN Größe
    */
   void SendMessage(zString str)         { AddLineToHistory(str);           }

   /* Eigenschaft-Änderungen der Console
    */
   bool IsActive() const               { return (mState==CON_ACTIVE);       }
   bool IsInActive() const             { return (mState==CON_INACTIVE);     }
   bool IsActivating() const           { return (mState==CON_ACTIVATING);   }
   bool IsDeActivating() const         { return (mState==CON_DEACTIVATING); }
   void Activate()                     { mState = CON_ACTIVATING;           }
   void DeActivate()                   { mState = CON_DEACTIVATING;         }
   zconState GetState() const          { return mState;                     }
   void ChangeState();
   DWORD GetDiffuse() const            { return mdwDiffuse;                 }
   void SetDiffuse(DWORD dif)          { mdwDiffuse = dif & 0x00ffffff;     }
   UINT GetWidth() const               { return (UINT)mfWidth;              }
   void SetWidth(UINT width)           { mfWidth = width;                   }
   UINT GetHeight() const              { return (UINT)mfHeight;             }
   void SetHeight(UINT height)         { mfHeight = height;                 }
   bool SetTexture(zString texfile, DWORD colorkey=0);
   DWORD GetFontLineColor() const      { return mdwFontLineColor;           }
   void SetFontLineColor(DWORD col)    { mdwFontLineColor = col;            }
   DWORD GetFontHistoryColor() const   { return mdwFontHistoryColor;        }
   void SetFontHistoryColor(DWORD col) { mdwFontHistoryColor = col;         }
   void SetProcessingFunc(void (*func)(zString))  { mpFunc = func;          }
   zString GetVersionString()          { return mVersion;                   }
   void SetLogfile(zString& str)       { mLogfile = str;                    }
   void LogInFile(bool log=true)       { mbLogging = true;                  }
   bool IsLogging()                    { return mbLogging;                  }

   /* Console Command Funcs*/

   /* Anzahl registrierter Commands
    */
   int GetNumCommands() const          { return mpCommands.GetNum();        }

   /* Registriert neues Command
    */
   // zb. RegisterCommand("/fogcolor", "III", "<r> <g> <b>");
   void RegisterCommand(zString commandstr, zString paramcode, zString helpstr="", void (*func)(zConsoleCommand&)=NULL);
   // zb. "/fogcolor, III, <r> <g> <b>"  oder  "/fogcolor, III"  oder  "/clear"]
   void RegisterCommand(zString totalstr, void (*func)(zConsoleCommand&)=NULL);
   // zb. "/fogcolor": Löscht dieses Command
   bool UnRegisterCommand(zString commandstr);
}; // class zConsole


#endif