#ifndef EVENT_H
#define EVENT_H

#ifndef ARRAY_OF_OWN_H
#include "Array_of_own.h"
#endif

#ifndef COMMAND_TEMPLATE_H
#include "Command_template.h"
#endif

namespace MM
{

class Event
{
    Array_of_own <Command>      command_;

public:
    void subscribe (Command * adoptee, bool on = true)  
    {
        if (on)
            command_.push_back (adoptee);
        else
            command_.remove    (*adoptee);
    }

    template <typename Receiver>
    void subscribe (Receiver & obj, void (Receiver::*action)())
        {command_.push_back (new Command_template<Receiver>(obj, action));}

    void publish () 
        {for (int i=0; i<command_.size(); ++i) 
            command_[i].execute();}

    void clear() {command_.clear();}
};

template <typename Arg1>
class Event_1
{
    Array_of_own <Command_1 <Arg1> >     command_;

public:
    void subscribe (Command_1<Arg1> * adoptee, bool on = true)  
    {
        if (on)
            command_.push_back (adoptee);
        else
            command_.remove    (*adoptee);
    }

    template <typename Receiver>
    void subscribe (Receiver & obj, void (Receiver::*action)(Arg1 arg1))
        {command_.push_back (new Command_template_1<Receiver, Arg1>(obj, action));}

    void publish (Arg1 arg1) 
        {for (int i=0; i<command_.size(); ++i) 
            command_[i].execute (arg1);}

    void clear() {command_.clear();}
};

template <typename Arg1, typename Arg2>
class Event_2
{
    Array_of_own <Command_2 <Arg1, Arg2> >     command_;

public:
    void subscribe (Command_2<Arg1, Arg2> * adoptee, bool on = true)  
    {
        if (on)
            command_.push_back (adoptee);
        else
            command_.remove    (*adoptee);
    }

    template <typename Receiver>
    void subscribe (Receiver & obj, void (Receiver::*action)(Arg1 arg1, Arg2 arg2))
        {command_.push_back (new Command_template_2<Receiver, Arg1, Arg2>(obj, action));}

    void publish (Arg1 arg1, Arg2 arg2) 
        {for (int i=0; i<command_.size(); ++i) 
            command_[i].execute (arg1, arg2);}

    void clear() {command_.clear();}
};

template <typename Arg1, typename Arg2, typename Arg3>
class Event_3
{
    Array_of_own <Command_3 <Arg1, Arg2, Arg3> >    command_;

public:
    void subscribe (Command_3<Arg1, Arg2, Arg3> * adoptee, bool on = true)  
    {
        if (on)
            command_.push_back (adoptee);
        else
            command_.remove    (*adoptee);
    }

    template <typename Receiver>
    void subscribe (Receiver & obj, void (Receiver::*action)(Arg1 arg1, Arg2 arg2, Arg3 arg3))
        {command_.push_back (new Command_template_3<Receiver, Arg1, Arg2, Arg3>(obj, action));}

    void publish (Arg1 arg1, Arg2 arg2, Arg3 arg3) 
        {for (int i=0; i<command_.size(); ++i) 
            command_[i].execute (arg1, arg2, arg3);}

    void clear() {command_.clear();}
};

/*template <typename TUPLE>
class Event_type
{
    void        subscribe( Agent )=0;           // Any
    void        publish( TUPLE event_data )=0;  // Any
};//*/

}//MM

#endif //EVENT_H

