#include "Test.h"

#include "Event.h"
#include <iostream>

namespace MM
{

class Event_test : public Test
{
public:
    Event_test (const Text & suite_name) : Test (suite_name) { }

    void run ()
    {
        count_foo0_ = 0;
        count_foo1_ = 0;
        count_foo2_ = 0;
        count_foo3_ = 0;
        mouse_click ().clear();

        test_1();                       count_tests();
        test_2();                       count_tests();
        test_pointers();                count_tests();
        test_references();              count_tests();
    }

    struct A
    {
        A () : count_f_(0), last_f1_(0), last_f2_(0), last_f3_(0), 
               last_f2ptr_(0), last_f2ref_(0) {}

        int count_f_;
        int last_f1_, last_f2_, last_f3_, last_f2ptr_, last_f2ref_;

        void f ()                       {++count_f_;}
        void f1(int a)                  {last_f1_ = a;}
        void f2(int a, int b)           {last_f2_ = a + b;}
        void f3(int a, int b, int c)    {last_f3_ = a + b + c;}
        
        void f2ptr (int* a, const int* b)   {last_f2ptr_ = *a + *b;}
        void f2ref (int& a, const int& b)   {last_f2ref_ =  a +  b;}
    };

    Event_2 <int, int> &       mouse_click ()
        {static  Event_2 <int, int > singleton;    return  singleton;}

    int count_foo0_, count_foo1_, count_foo2_, count_foo3_;

    void foo0 ()                    {++count_foo0_;}
    void foo1 (int )               {++count_foo1_;}
    void foo2 (int , int )         {++count_foo2_;}
    void foo3 (int , int , int )   {++count_foo3_;}

    void test_1 ()
    {
        Event_test::A a;

        Event event0;
        event0.subscribe (*this, &Event_test::foo0);
        event0.subscribe (a, &Event_test::A::f);
        event0.subscribe (create_command(*this, &Event_test::foo0));
        event0.publish   ();
        TEST ("", a.count_f_ == 1);
        TEST ("", count_foo0_ == 2);

        Event_1 <int> event1;
        event1.subscribe (*this, &Event_test::foo1);
        event1.subscribe (a, &Event_test::A::f1);
        event1.subscribe (create_command_1 (*this, &Event_test::foo1));
        event1.publish   (12);
        TEST ("", a.last_f1_ == 12);
        TEST ("", count_foo1_ == 2);

        Event_2 <int, int> event2;
        event2.subscribe (*this, &Event_test::foo2);
        event2.subscribe (a, &Event_test::A::f2);
        event2.subscribe (create_command_2 (*this, &Event_test::foo2));
        event2.publish   (12, 34);
        TEST ("", a.last_f2_ == 12+34);
        TEST ("", count_foo2_ == 2);

        Event_3 <int, int, int> event3;
        event3.subscribe (*this, &Event_test::foo3);
        event3.subscribe (a, &Event_test::A::f3);
        event3.subscribe (create_command_3 (*this, &Event_test::foo3));
        event3.publish   (12, 34, 56);//*/
        TEST ("", a.last_f3_ == 12+34+56);
        TEST ("", count_foo3_ == 2);
    }

    void test_2 ()
    {
        mouse_click().subscribe (*this, &Event_test::foo2);
        mouse_click().publish   (123, 45);
        TEST ("", count_foo2_ == 3);
    }


    void test_pointers()
    {
        Event_test::A a;
        int value_1 = 1, value_2 = 2;
        Event_2 <int*, const int*> event;
        event.subscribe (a, &Event_test::A::f2ptr);
        event.publish   (&value_1, &value_2);
        TEST ("", a.last_f2ptr_ == 1+2);
    }

    void test_references()
    {
        Event_test::A a;
        int value_1 = 3, value_2 = 7;
        Event_2 <int&, const int&> event;
        event.subscribe (a, &Event_test::A::f2ref);
        event.publish   (value_1, value_2);
        TEST ("", a.last_f2ref_ == 3+7);
        event.publish   (value_1, 2);
        TEST ("", a.last_f2ref_ == 3+2);
    }
};

//Event_test event_test ("demo");
Event_test test_event ("correctness");

}//MM

