/*****************************************************************************
 *
 *  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_SIGNAL
#define MOGL_SIGNAL

#include "MOGL_Action.h"
#include "MOGL_SignalBase.h"
#include <list>

using namespace std;

// ###################### MOGLSignal0 #########################################################

/**
   Représente un signal. Un MOGL_Signal peut être connecté à des méthodes de MOGL_Action
   par la méthode Connecter(). Ainsi lorsque la méthode Emettre() est appelée toutes
   les méthodes de MOGL_Action connectées sont appelées. Les paramètres des méthodes
   correspondent aux types spécifiés dans le template.
   A chaque nombre de paramètres correspond une classe MOGL_Signal correspondante.
   Ainsi pour un paramètre il y a MOGL_Signal1, pour deux paramètres, il y a
   MOGL_Signal2, etc.
*/
class MOGL_Signal0: public MOGL_SignalBase
{
  protected:
        // **** Types locaux à la classe ****
        class MOGL_ConnexionBase: public MOGL_ConnexionBaseBase
        {
          public:
                /**
                   Permet d'émettre le signal vers le MOGL_Action associé.
                 */
                virtual void Emettre()=0;
        };
                
        template<class TypeClasse>
        class MOGL_Connexion : public MOGL_ConnexionBase
        {
                // **** Types locaux à la classe ****
          protected:
                /**
                   Type de la méthode associée à la connexion.
                 */
                typedef void(TypeClasse::* TypeMethode)();
                // **********************************

          protected:
                /**
                   Méthode associée à la connexion.
                 */
                TypeMethode _Methode;
                
          public:
                /**
                   Constructeur par copie.
                 */
                MOGL_Connexion(TypeClasse * p_Objet, TypeMethode p_Methode)
                {
                  _Objet=p_Objet;
                  _Methode=p_Methode;
                }
                
                void Emettre()
                {
                  (static_cast<TypeClasse*>(_Objet)->*_Methode)();
                }

                MOGL_ConnexionBaseBase *  Dupliquer(MOGL_Action * p_NouvelObjet)
                {
                  MOGL_ConnexionBaseBase * connexion=new MOGL_Connexion(static_cast<TypeClasse *>(p_NouvelObjet), _Methode);
                  return connexion;
                }
        };
        // **********************************

  public:
        /**
           Permet d'émettre le signal.
        */
        void Emettre()
        {
          for(MOGL_List_Connexion::iterator it=_ListConnexion.begin(); it!=_ListConnexion.end(); it++)
          {
                static_cast<MOGL_ConnexionBase*>(*it)->Emettre();
          }
        }

        /**
           Permet de connecter une méthode d'un MOGL_Action.
           @param p_Action : pointeur vers une instance d'une classe spécialisant MOGL_Action.
           @param p_MethodeSlot : pointeur vers une méthode de l'objet <i>p_Action</i> qui n'a pas de paramètres
         */
        template<class DestType>
        void Connecter(DestType * p_Action, void (DestType::* p_MethodeSlot)() )
        {
          p_Action->AjouterSignal(this);
          
          MOGL_Connexion<DestType> * connexion=new MOGL_Connexion<DestType>(p_Action, p_MethodeSlot);
          _ListConnexion.push_back(connexion);
        }
};

// ############################################################################################

// ###################### MOGLSignal1 #########################################################

/**
   Représente un signal. Un MOGL_Signal peut être connecté à des méthodes de MOGL_Action
   par la méthode Connecter(). Ainsi lorsque la méthode Emettre() est appelée toutes
   les méthodes de MOGL_Action connectées sont appelées. Les paramètres des méthodes
   correspondent aux types spécifiés dans le template.
   A chaque nombre de paramètres correspond une classe MOGL_Signal correspondante.
   Ainsi pour un paramètre il y a MOGL_Signal1, pour deux paramètres, il y a
   MOGL_Signal2, etc.
*/
template<class TypeParam1>
class MOGL_Signal1: public MOGL_SignalBase
{
  protected:
        // **** Types locaux à la classe ****
        class MOGL_ConnexionBase: public MOGL_ConnexionBaseBase
        {
          public:
                /**
                   Permet d'émettre le signal vers le MOGL_Action associé.
                 */
                virtual void Emettre(TypeParam1 p_Param1)=0;
        };
                
        template<class TypeClasse>
        class MOGL_Connexion : public MOGL_ConnexionBase
        {
                // **** Types locaux à la classe ****
          protected:
                /**
                   Type de la méthode associée à la connexion.
                 */
                typedef void(TypeClasse::* TypeMethode)(TypeParam1);
                // **********************************

          protected:
                /**
                   Méthode associée à la connexion.
                 */
                TypeMethode _Methode;
                
          public:
                /**
                   Constructeur par copie.
                 */
                MOGL_Connexion(TypeClasse * p_Objet, TypeMethode p_Methode)
                {
                  this->_Objet=p_Objet;
                  _Methode=p_Methode;
                }
                
                void Emettre(TypeParam1 p_Param1)
                {
                  (static_cast<TypeClasse*>(this->_Objet)->*_Methode)(p_Param1);
                }

                MOGL_ConnexionBaseBase *  Dupliquer(MOGL_Action * p_NouvelObjet)
                {
                  MOGL_ConnexionBaseBase * connexion=new MOGL_Connexion(static_cast<TypeClasse *>(p_NouvelObjet), _Methode);
                  return connexion;
                }
        };
        // **********************************

  public:
        /**
           Permet d'émettre le signal.
        */
        void Emettre(TypeParam1 p_Param1)
        {
          for(MOGL_List_Connexion::iterator it=_ListConnexion.begin(); it!=_ListConnexion.end(); it++)
          {
                static_cast<MOGL_ConnexionBase*>(*it)->Emettre(p_Param1);
          }
        }

        /**
           Permet de connecter une méthode d'un MOGL_Action.
           @param p_Action : pointeur vers une instance d'une classe spécialisant MOGL_Action.
           @param p_MethodeSlot : pointeur vers une méthode de l'objet <i>p_Action</i> dont les paramètres
           correspondent à TypeParam1
         */
        template<class DestType>
        void Connecter(DestType * p_Action, void (DestType::* p_MethodeSlot)(TypeParam1) )
        {
          p_Action->AjouterSignal(this);
          
          MOGL_Connexion<DestType> * connexion=new MOGL_Connexion<DestType>(p_Action, p_MethodeSlot);
          _ListConnexion.push_back(connexion);
        }
};

// ############################################################################################

// ###################### MOGLSignal2 #########################################################

/**
   Représente un signal. Un MOGL_Signal peut être connecté à des méthodes de MOGL_Action
   par la méthode Connecter(). Ainsi lorsque la méthode Emettre() est appelée toutes
   les méthodes de MOGL_Action connectées sont appelées. Les paramètres des méthodes
   correspondent aux types spécifiés dans le template.
   A chaque nombre de paramètres correspond une classe MOGL_Signal correspondante.
   Ainsi pour un paramètre il y a MOGL_Signal1, pour deux paramètres, il y a
   MOGL_Signal2, etc.
*/
template<class TypeParam1, class TypeParam2>
class MOGL_Signal2: public MOGL_SignalBase
{
  protected:
        // **** Types locaux à la classe ****
        class MOGL_ConnexionBase: public MOGL_ConnexionBaseBase
        {
          public:
                /**
                   Permet d'émettre le signal vers le MOGL_Action associé.
                 */
                virtual void Emettre(TypeParam1 p_Param1, TypeParam2 p_Param2)=0;
        };
                
        template<class TypeClasse>
        class MOGL_Connexion : public MOGL_ConnexionBase
        {
                // **** Types locaux à la classe ****
          protected:
                /**
                   Type de la méthode associée à la connexion.
                 */
                typedef void(TypeClasse::* TypeMethode)(TypeParam1, TypeParam2);
                // **********************************

          protected:
                /**
                   Méthode associée à la connexion.
                 */
                TypeMethode _Methode;
                
          public:
                /**
                   Constructeur par copie.
                 */
                MOGL_Connexion(TypeClasse * p_Objet, TypeMethode p_Methode)
                {
                  this->_Objet=p_Objet;
                  _Methode=p_Methode;
                }
                
                void Emettre(TypeParam1 p_Param1, TypeParam2 p_Param2)
                {
                  (static_cast<TypeClasse*>(this->_Objet)->*_Methode)(p_Param1, p_Param2);
                }

                MOGL_ConnexionBaseBase *  Dupliquer(MOGL_Action * p_NouvelObjet)
                {
                  MOGL_ConnexionBaseBase * connexion=new MOGL_Connexion(static_cast<TypeClasse *>(p_NouvelObjet), _Methode);
                  return connexion;
                }
        };
        // **********************************

  public:
        /**
           Permet d'émettre le signal.
        */
        void Emettre(TypeParam1 p_Param1, TypeParam2 p_Param2)
        {
          for(MOGL_List_Connexion::iterator it=_ListConnexion.begin(); it!=_ListConnexion.end(); it++)
          {
                static_cast<MOGL_ConnexionBase*>(*it)->Emettre(p_Param1, p_Param2);
          }
        }

        /**
           Permet de connecter une méthode d'un MOGL_Action.
           @param p_Action : pointeur vers une instance d'une classe spécialisant MOGL_Action.
           @param p_MethodeSlot : pointeur vers une méthode de l'objet <i>p_Action</i> dont les paramètres
           correspondent à (TypeParam1, TypeParam2)
         */
        template<class DestType>
        void Connecter(DestType * p_Action, void (DestType::* p_MethodeSlot)(TypeParam1, TypeParam2) )
        {
          p_Action->AjouterSignal(this);
          
          MOGL_Connexion<DestType> * connexion=new MOGL_Connexion<DestType>(p_Action, p_MethodeSlot);
          _ListConnexion.push_back(connexion);
        }
};

// ############################################################################################

// ###################### MOGLSignal3 #########################################################

/**
   Représente un signal. Un MOGL_Signal peut être connecté à des méthodes de MOGL_Action
   par la méthode Connecter(). Ainsi lorsque la méthode Emettre() est appelée toutes
   les méthodes de MOGL_Action connectées sont appelées. Les paramètres des méthodes
   correspondent aux types spécifiés dans le template.
   A chaque nombre de paramètres correspond une classe MOGL_Signal correspondante.
   Ainsi pour un paramètre il y a MOGL_Signal1, pour deux paramètres, il y a
   MOGL_Signal2, etc.
*/
template<class TypeParam1, class TypeParam2, class TypeParam3>
class MOGL_Signal3: public MOGL_SignalBase
{
  protected:
        // **** Types locaux à la classe ****
        class MOGL_ConnexionBase: public MOGL_ConnexionBaseBase
        {
          public:
                /**
                   Permet d'émettre le signal vers le MOGL_Action associé.
                 */
                virtual void Emettre(TypeParam1 p_Param1, TypeParam2 p_Param2, TypeParam3 p_Param3)=0;
        };
                
        template<class TypeClasse>
        class MOGL_Connexion : public MOGL_ConnexionBase
        {
                // **** Types locaux à la classe ****
          protected:
                /**
                   Type de la méthode associée à la connexion.
                 */
                typedef void(TypeClasse::* TypeMethode)(TypeParam1, TypeParam2, TypeParam3);
                // **********************************

          protected:
                /**
                   Méthode associée à la connexion.
                 */
                TypeMethode _Methode;
                
          public:
                /**
                   Constructeur par copie.
                 */
                MOGL_Connexion(TypeClasse * p_Objet, TypeMethode p_Methode)
                {
                  this->_Objet=p_Objet;
                  _Methode=p_Methode;
                }
                
                void Emettre(TypeParam1 p_Param1, TypeParam2 p_Param2, TypeParam3 p_Param3)
                {
                  (static_cast<TypeClasse*>(this->_Objet)->*_Methode)(p_Param1, p_Param2, p_Param3);
                }

                MOGL_ConnexionBaseBase *  Dupliquer(MOGL_Action * p_NouvelObjet)
                {
                  MOGL_ConnexionBaseBase * connexion=new MOGL_Connexion(static_cast<TypeClasse *>(p_NouvelObjet), _Methode);
                  return connexion;
                }
        };
        // **********************************

  public:
        /**
           Permet d'émettre le signal.
        */
        void Emettre(TypeParam1 p_Param1, TypeParam2 p_Param2, TypeParam3 p_Param3)
        {
          for(MOGL_List_Connexion::iterator it=_ListConnexion.begin(); it!=_ListConnexion.end(); it++)
          {
                static_cast<MOGL_ConnexionBase*>(*it)->Emettre(p_Param1, p_Param2, p_Param3);
          }
        }

        /**
           Permet de connecter une méthode d'un MOGL_Action.
           @param p_Action : pointeur vers une instance d'une classe spécialisant MOGL_Action.
           @param p_MethodeSlot : pointeur vers une méthode de l'objet <i>p_Action</i> dont les paramètres
           correspondent à (TypeParam1, TypeParam2, TypeParam3)
         */
        template<class DestType>
        void Connecter(DestType * p_Action, void (DestType::* p_MethodeSlot)(TypeParam1, TypeParam2, TypeParam3) )
        {
          p_Action->AjouterSignal(this);
          
          MOGL_Connexion<DestType> * connexion=new MOGL_Connexion<DestType>(p_Action, p_MethodeSlot);
          _ListConnexion.push_back(connexion);
        }
};

// ############################################################################################

// ###################### MOGLSignal4 #########################################################

/**
   Représente un signal. Un MOGL_Signal peut être connecté à des méthodes de MOGL_Action
   par la méthode Connecter(). Ainsi lorsque la méthode Emettre() est appelée toutes
   les méthodes de MOGL_Action connectées sont appelées. Les paramètres des méthodes
   correspondent aux types spécifiés dans le template.
   A chaque nombre de paramètres correspond une classe MOGL_Signal correspondante.
   Ainsi pour un paramètre il y a MOGL_Signal1, pour deux paramètres, il y a
   MOGL_Signal2, etc.
*/
template<class TypeParam1, class TypeParam2, class TypeParam3, class TypeParam4>
class MOGL_Signal4: public MOGL_SignalBase
{
  protected:
        // **** Types locaux à la classe ****
        class MOGL_ConnexionBase: public MOGL_ConnexionBaseBase
        {
          public:
                /**
                   Permet d'émettre le signal vers le MOGL_Action associé.
                 */
                virtual void Emettre(TypeParam1 p_Param1, TypeParam2 p_Param2, TypeParam3 p_Param3, TypeParam4 p_Param4)=0;
        };
                
        template<class TypeClasse>
        class MOGL_Connexion : public MOGL_ConnexionBase
        {
                // **** Types locaux à la classe ****
          protected:
                /**
                   Type de la méthode associée à la connexion.
                 */
                typedef void(TypeClasse::* TypeMethode)(TypeParam1, TypeParam2, TypeParam3, TypeParam4);
                // **********************************

          protected:
                /**
                   Méthode associée à la connexion.
                 */
                TypeMethode _Methode;
                
          public:
                /**
                   Constructeur par copie.
                 */
                MOGL_Connexion(TypeClasse * p_Objet, TypeMethode p_Methode)
                {
                  this->_Objet=p_Objet;
                  _Methode=p_Methode;
                }
                
                void Emettre(TypeParam1 p_Param1, TypeParam2 p_Param2, TypeParam3 p_Param3, TypeParam4 p_Param4)
                {
                  (static_cast<TypeClasse*>(this->_Objet)->*_Methode)(p_Param1, p_Param2, p_Param3, p_Param4);
                }

                MOGL_ConnexionBaseBase *  Dupliquer(MOGL_Action * p_NouvelObjet)
                {
                  MOGL_ConnexionBaseBase * connexion=new MOGL_Connexion(static_cast<TypeClasse *>(p_NouvelObjet), _Methode);
                  return connexion;
                }
        };
        // **********************************

  public:
        /**
           Permet d'émettre le signal.
        */
        void Emettre(TypeParam1 p_Param1, TypeParam2 p_Param2, TypeParam3 p_Param3, TypeParam4 p_Param4)
        {
          for(MOGL_List_Connexion::iterator it=_ListConnexion.begin(); it!=_ListConnexion.end(); it++)
          {
                static_cast<MOGL_ConnexionBase*>(*it)->Emettre(p_Param1, p_Param2, p_Param3, p_Param4);
          }
        }

        /**
           Permet de connecter une méthode d'un MOGL_Action.
           @param p_Action : pointeur vers une instance d'une classe spécialisant MOGL_Action.
           @param p_MethodeSlot : pointeur vers une méthode de l'objet <i>p_Action</i> dont les paramètres
           correspondent à (TypeParam1, TypeParam2, TypeParam3, TypeParam4)
         */
        template<class DestType>
        void Connecter(DestType * p_Action, void (DestType::* p_MethodeSlot)(TypeParam1, TypeParam2, TypeParam3, TypeParam4) )
        {
          p_Action->AjouterSignal(this);
          
          MOGL_Connexion<DestType> * connexion=new MOGL_Connexion<DestType>(p_Action, p_MethodeSlot);
          _ListConnexion.push_back(connexion);
        }
};

// ############################################################################################

// ###################### MOGLSignal5 #########################################################

/**
   Représente un signal. Un MOGL_Signal peut être connecté à des méthodes de MOGL_Action
   par la méthode Connecter(). Ainsi lorsque la méthode Emettre() est appelée toutes
   les méthodes de MOGL_Action connectées sont appelées. Les paramètres des méthodes
   correspondent aux types spécifiés dans le template.
   A chaque nombre de paramètres correspond une classe MOGL_Signal correspondante.
   Ainsi pour un paramètre il y a MOGL_Signal1, pour deux paramètres, il y a
   MOGL_Signal2, etc.
*/
template<class TypeParam1, class TypeParam2, class TypeParam3, class TypeParam4, class TypeParam5>
class MOGL_Signal5: public MOGL_SignalBase
{
  protected:
        // **** Types locaux à la classe ****
        class MOGL_ConnexionBase: public MOGL_ConnexionBaseBase
        {
          public:
                /**
                   Permet d'émettre le signal vers le MOGL_Action associé.
                 */
                virtual void Emettre(TypeParam1 p_Param1, TypeParam2 p_Param2, TypeParam3 p_Param3, TypeParam4 p_Param4, TypeParam5 p_Param5)=0;
        };
                
        template<class TypeClasse>
        class MOGL_Connexion : public MOGL_ConnexionBase
        {
                // **** Types locaux à la classe ****
          protected:
                /**
                   Type de la méthode associée à la connexion.
                 */
                typedef void(TypeClasse::* TypeMethode)(TypeParam1, TypeParam2, TypeParam3, TypeParam4, TypeParam5);
                // **********************************

          protected:
                /**
                   Méthode associée à la connexion.
                 */
                TypeMethode _Methode;
                
          public:
                /**
                   Constructeur par copie.
                 */
                MOGL_Connexion(TypeClasse * p_Objet, TypeMethode p_Methode)
                {
                  this->_Objet=p_Objet;
                  _Methode=p_Methode;
                }
                
                void Emettre(TypeParam1 p_Param1, TypeParam2 p_Param2, TypeParam3 p_Param3, TypeParam4 p_Param4, TypeParam5 p_Param5)
                {
                  (static_cast<TypeClasse*>(this->_Objet)->*_Methode)(p_Param1, p_Param2, p_Param3, p_Param4, p_Param5);
                }

                MOGL_ConnexionBaseBase *  Dupliquer(MOGL_Action * p_NouvelObjet)
                {
                  MOGL_ConnexionBaseBase * connexion=new MOGL_Connexion(static_cast<TypeClasse *>(p_NouvelObjet), _Methode);
                  return connexion;
                }
        };
        // **********************************

  public:
        /**
           Permet d'émettre le signal.
        */
        void Emettre(TypeParam1 p_Param1, TypeParam2 p_Param2, TypeParam3 p_Param3, TypeParam4 p_Param4, TypeParam5 p_Param5)
        {
          for(MOGL_List_Connexion::iterator it=_ListConnexion.begin(); it!=_ListConnexion.end(); it++)
          {
                static_cast<MOGL_ConnexionBase*>(*it)->Emettre(p_Param1, p_Param2, p_Param3, p_Param4, p_Param5);
          }
        }

        /**
           Permet de connecter une méthode d'un MOGL_Action.
           @param p_Action : pointeur vers une instance d'une classe spécialisant MOGL_Action.
           @param p_MethodeSlot : pointeur vers une méthode de l'objet <i>p_Action</i> dont les paramètres
           correspondent à (TypeParam1, TypeParam2, TypeParam3, TypeParam4, TypeParam5)
         */
        template<class DestType>
        void Connecter(DestType * p_Action, void (DestType::* p_MethodeSlot)(TypeParam1, TypeParam2, TypeParam3, TypeParam4, TypeParam5) )
        {
          p_Action->AjouterSignal(this);
          
          MOGL_Connexion<DestType> * connexion=new MOGL_Connexion<DestType>(p_Action, p_MethodeSlot);
          _ListConnexion.push_back(connexion);
        }
};

// ############################################################################################

#endif

