/*****************************************************************************
 *
 *  Copyright (C) 2003 Cédric Brégardis <cedric.bregardis@free.fr>
 *
 *  This file is part of BRIQUOLO
 *
 *  BRIQUOLO is free software; you can 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.
 *
 *  BRIQUOLO 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 BRIQUOLO; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *****************************************************************************/
#ifndef MOGL_FENETRE
#define MOGL_FENETRE


#ifdef _WIN32
#include <windows.h>
#include <windowsx.h>
#endif

#include <GL/gl.h>
#include <GL/glu.h>
#include <SDL/SDL.h>
#include <iostream>
#include <string>
#include <map>
#include <set>
#include "MOGL_Interface.h"
#include "MOGL_Signal.h"

using namespace std;

/**
   Permet de gérer une fenêtre destinée à recevoir l'affichage.
   La résolution par défaut est 640x480 avec des couleurs codées sur 16 bits, en mode fenêtré.
*/
class MOGL_Fenetre
{
    // **** Types locaux à la classe ****
  public:
    struct MOGL_Resolution;
  private:
    struct CompareResolution
    {
        bool operator() (const MOGL_Resolution & x, const MOGL_Resolution & y)
        {
          return x.w < y.w;
        }
    };

    typedef set<MOGL_Interface *> MOGL_Set_Interface;
    typedef MOGL_Set_Interface::iterator MOGL_ItSet_Interface;

    typedef map<unsigned int, MOGL_Set_Interface> MOGL_Map_Interface;
    typedef MOGL_Map_Interface::iterator MOGL_ItMap_Interface;
  public:
    struct MOGL_Resolution
    {
        MOGL_Resolution(unsigned int pW, unsigned int pH): w(pW), h(pH)
        {
        }
        unsigned int w, h;
    };
    typedef set<MOGL_Resolution, CompareResolution> MOGL_Set_Resolution;
    typedef MOGL_Set_Resolution::iterator MOGL_ItSet_Resolution;


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

  protected :
    char * _Titre;
    int _ResolutionX, _ResolutionY;
    int _MemResolutionX, _MemResolutionY;
    unsigned int _NbBitParPixel;
    bool _FinBoucle;
    SDL_Surface * _SurfaceSDL;
    bool _Fullscreen;
    bool _GrabCurseur;
    int _RepetitionDelai;
    int _RepetitionIntervalle;

    MOGL_Map_Interface _EnsembleInterface;

    unsigned int _NumeroImage;
    bool _ExisteFenetre;
    bool _CacheSouris;

    MOGL_Set_Resolution _SetResolution;

    // Données pour les joysticks
    unsigned int _NombreJoysticks;
    SDL_Joystick ** _Joysticks;
    bool _bManualResize;

    // Les Signaux
  public:
    MOGL_Signal0 Idle;
    MOGL_Signal1<SDL_keysym *> KeyDown;
    MOGL_Signal1<SDL_keysym *> KeyUp;
    MOGL_Signal1<SDL_MouseMotionEvent *> MouseMove;
    MOGL_Signal1<SDL_MouseButtonEvent *> MouseButtonDown;
    MOGL_Signal1<SDL_MouseButtonEvent *> MouseButtonUp;
    MOGL_Signal3<int,int,int> ChangementMode;
    MOGL_Signal0 Destruction;
    MOGL_Signal3<unsigned int, unsigned int, float> MouvementAxeJoystick; // Joystick index, Axe index, valeur
    MOGL_Signal2<unsigned int, unsigned int> BoutonJoystickDown;          // Joystick index, Bouton index
    MOGL_Signal2<unsigned int, unsigned int> BoutonJoystickUp;            // Joystick index, Bouton index

  protected:
    void _MouvementAxeJoystick(SDL_JoyAxisEvent * p_JoyAxisEvent);
    void _BoutonJoystickDown(SDL_JoyButtonEvent * p_JoyButtonEvent);
    void _BoutonJoystickUp(SDL_JoyButtonEvent * p_JoyButtonEvent);
    bool _InitGL();
    void _GestionEvenement();
    void _Reshape (int w,int h);
    void _ManualResize(int p_ResolutionX, int p_ResolutionY);

    SDL_Surface * _CreerFenetre(unsigned int & p_Bpp, unsigned int p_Flags);

  public :
    MOGL_Fenetre(const char * p_Titre=NULL);
    ~MOGL_Fenetre();

    /**
       Permet de définir la résolution de la fenêtre
       @param p_ResolutionX : résolution en X de la fenêtre
       @param p_ResolutionY : résolution en Y de la fenêtre
       @param p_Fullscreen : indique si la fenêtre doit être plein écran ou non.
       @return <i>true</i> si il n'y a pas eu de problème, <i>false</i> sinon. Un problème peut intervenir seuleument s'il
               s'agit d'un changement de mode alors que la fen^tre existe
    */
    bool SetMode(int p_ResolutionX, int p_ResolutionY, bool p_Fullscreen);

    MOGL_Set_Resolution GetAvailableResolution() const;

    /**
       Permet de définir la résolution de la fenêtre. Le nombre de bit par pixel reste inchangé.
       @param p_ResolutionX : résolution en X de la fenêtre
       @param p_ResolutionY : résolution en Y de la fenêtre
    */
    bool SetMode(int p_ResolutionX, int p_ResolutionY);

    /**
       Permet de récupérer la résolution X de la fenêtre.
       @return La résolution X.
     */
    int GetResolutionX() const;

    /**
       Permet de récupérer la résolution Y de la fenêtre.
       @return La résolution Y.
     */
    int GetResolutionY() const;

    /**
       Permet de récupérer le nombre de bits par pixel de la fenêtre.
       @return Le nombre de bits par pixels.
     */
    int GetBPP() const;

    /**
       Permet de définir le titre de la fenêtre. Le titre n'est affiché que lorsque la fenetre n'est pas en plein écran
       (@sa SetFullscreen()].
       @param p_Titre : titre de la fenêtre
    */
    void SetTitre(char * p_Titre);

    /**
       Permet de mettre la fenêtre en plein écran.
       p_Fullscreen : true si plein écran, false sinon.
    */
    void SetFullscreen(bool p_Fullscreen);

    /**
       Indique si la fenêtre est en plein écran.
       @return <i>true</i> si a fenêtre est en plein écran, <i>false</i> sinon.
     */
    bool GetFullscreen() const;

    /**
       Permet d'initialiser la fenêtre d'affichage ainsi que tout l'environnement MOGL.
       Cette initialisation doit être effectuée avant la plupart des opérations pouvant être effectuées par MOGL
       (chargement de texture...)
       @return <i>true</i> s'il n'y a pas eu de problème, et <i>false</i> sinon.
    */
    bool Initialiser();

    /**
       Permet de Lancer la boucle d'évènement de MOGL. La méthode ne redonne la main que lorsque la boucle d'évènement est terminée,
       ce qui signifie que l'exécution de MOGL est achevée.
       @return <i>true</i> s'il n'y a pas eu de problème, <i>false</i> sinon.
    */
    bool LancerBoucle();

    /**
       Permet d'arreter la boucle inité par LancerBoucle()
     */
    void Arreter();

    /**
       Permet d'ajouter une interface à la fenêtre. Les interface représente des <i>contenus</i> liés à la fenêtre
       comme par exemple MOGL_Univers qui représente un univers 3D ou encore MOGL_Facade qui représente un affichage 2D.
    */
    void AjouterInterface(MOGL_Interface * p_Interface);

    /**
       Permet de retirer une interface.
       @sa AjouterInterface().
    */
    bool RetirerInterface(MOGL_Interface * p_Interface);


    /**
       Permet d'infiquer à la fenêtre si elle peut garder le curseur.
       @param p_Val : <i>true</i> pour l'attraper, <i>false</i> sinon.
    */
    void SetGrabCurseur(bool p_Val);

    /**
       Permet de cacher le pointeur de souris. Par défaut, le pointeur est caché.
       param p_Val : <i>true</i> pour le cacher, <i>false</i> sinon.
     */
    void SetCacherCurseur(bool p_Val);

    /**
       Permet de définir la répétition des touches.
       @todo à amméliorer.
    */
    void DefinirRepetitionTouche(int p_Delai, int p_Intervalle);

    /**
     * Permet de prendre un screenshot au format BMP.
     *
     * @param p_NomFichier : nom du fichier de sauvegarde.
     *
     * @return <i>true</i> s'il n'y a pas eu d'erreur, <i>false</i> sinon.
     */
    bool ScreenshotBMP(char * p_NomFichier);

    /**
     * Permet de prendre un screenshot au format BMP.
     * Le nom du fichier est ici déterminé de manière automatique, à partir du prefix fourni.
     * Le nom correspond au préfix indiqué qui est suivi d'un numéro (le premier disponible,
     * de manière à ce que le fichier n'existe pas sur le disque), et de l'extension <i>.bmp</i>
     *
     * @param p_Prefix : préfix du nom du fichier
     *
     * @return <i>true</i> s'il n'y a pas eu d'erreur, <i>false</i> sinon.
     */
    bool ScreenshotPrefixBMP(char * p_Prefix);

    unsigned int GetNombreJoystick() const;
    bool OuvrirJoystick(unsigned int p_IndiceJoystick);
    bool FermerJoystick(unsigned int p_IndiceJoystick);
};

#endif

/** @mainpage Moteur Open GL - MOGL
        @section intro Introduction
         @subsection quoi Qu'est-ce que c'est ?
         MOGL est un <i>moteur 3D temps réel</i>.
         Cela signifie qu'il permet de gérer l'affichage d'un univers en trois dimension de manière suffisamment rapide pour
         être interactif.
         Ainsi MOGL propose un ensemble de classes C++ disponibles sous la forme d'une bibliothèque permettant la réalisation aisée
         d'une application, en proposant tous les services liées à la mise en place d'un univers 3D : Création d'une fenêtre d'affichage,
         affichage d'objets, animations, interraction...

         @subsection specif Spécificités de MOGL
         Ce genre d'outil existe sous de très nombreuses formes. Par exemple <i>3D Master Suite</i> développé à l'origine par SGI est une
         bibliotèque reposant sur OpenGL, qui est utilisé dans le monde professionel qui propose la réalisation d'un affichage 3D
         (pour la réalisation de logiciel de CAO par exemple). De même, Id Software s'est démarqué par la création de moteurs 3D
         utilisés dans le jeux video (<i>Quake 3</i> par exemple).
         L'initiative de base est semblable, cependant le but étant différents ces deux outils n'ont pas les même contraintes,
         et ne sont pas interchangables.
         @par
         De la même manière MOGL a été conçu dans un but précis : c'est un moteur 3D de type jeux video (ainsi il n'est peut pas conçu
         pour s'intégrer dans une IHM complexe), simple d'utilisation et multiplateforme.

         @subsection fonctionnalites Fonctionnalités
          @li Affichage de triangles et de strips
          @li Gestion des éléments de l'affichage par l'intermédiaire d'un arbre, de manipulation aisée
          @li Moteur de particules permettant la création de nouvelles particules facilement
          @li Affichage de Lens Flare
          @li Animation aisée des objets présents dans l'arbre par l'intermédiare de classes spécialisés
          @li Elements 2D placé au dessus de l'affichage 3D pour la réalisation aisée d'IHM.

        @section install Installation
*/
