#include "piobject.h"

#include "gtest/gtest.h"


class Object: public PIObject {
	PIOBJECT(Object)

public:
	Object() {
		x = 0;
		//		CONNECTL(this, deleted, [](PIObject * o){
		//			piCout << "deteted" << o;
		//		});
	}
	void test() { event_test(); }
	void test_val() { event_val(x); }
	int getX() const { return x; }

	EVENT(event_test)
	EVENT1(event_val, int, arg)

	EVENT_HANDLER(void, handler_test) { x++; }
	EVENT_HANDLER1(void, handler_val, int, arg) { x = arg; }

private:
	int x;
};


TEST(PiobjectConnections, CONNECT0) {
	Object a;
	Object b;
	EXPECT_EQ(a.getX(), 0);
	EXPECT_EQ(b.getX(), 0);
	a.test();
	EXPECT_EQ(a.getX(), 0);
	EXPECT_EQ(b.getX(), 0);
	b.test();
	EXPECT_EQ(a.getX(), 0);
	EXPECT_EQ(b.getX(), 0);
	CONNECT0(void, &a, event_test, &b, handler_test);
	EXPECT_EQ(a.getX(), 0);
	EXPECT_EQ(b.getX(), 0);
	a.test();
	EXPECT_EQ(a.getX(), 0);
	EXPECT_EQ(b.getX(), 1);
	b.test();
	EXPECT_EQ(a.getX(), 0);
	EXPECT_EQ(b.getX(), 1);
	//	piCout << "================";
}


TEST(PiobjectConnections, CONNECT0_DISCONNECT) {
	Object a;
	Object b;
	a.setName("A");
	b.setName("B");
	EXPECT_EQ(a.getX(), 0);
	EXPECT_EQ(b.getX(), 0);
	a.test();
	EXPECT_EQ(a.getX(), 0);
	EXPECT_EQ(b.getX(), 0);
	b.test();
	EXPECT_EQ(a.getX(), 0);
	EXPECT_EQ(b.getX(), 0);
	CONNECT0(void, &a, event_test, &b, handler_test);
	EXPECT_EQ(a.getX(), 0);
	EXPECT_EQ(b.getX(), 0);
	a.test();
	EXPECT_EQ(a.getX(), 0);
	EXPECT_EQ(b.getX(), 1);
	b.test();
	EXPECT_EQ(a.getX(), 0);
	EXPECT_EQ(b.getX(), 1);
	PIObject::piDisconnect(&a, "event_test");
	EXPECT_EQ(a.getX(), 0);
	EXPECT_EQ(b.getX(), 1);
	a.test();
	EXPECT_EQ(a.getX(), 0);
	EXPECT_EQ(b.getX(), 1);
	b.test();
	EXPECT_EQ(a.getX(), 0);
	EXPECT_EQ(b.getX(), 1);
	//	piCout << "================";
}

TEST(PiobjectConnections, CONNECTU) {
	Object a;
	Object b;
	EXPECT_EQ(a.getX(), 0);
	EXPECT_EQ(b.getX(), 0);
	a.test();
	EXPECT_EQ(a.getX(), 0);
	EXPECT_EQ(b.getX(), 0);
	b.test();
	EXPECT_EQ(a.getX(), 0);
	EXPECT_EQ(b.getX(), 0);
	CONNECTU(&a, event_test, &b, handler_test);
	EXPECT_EQ(a.getX(), 0);
	EXPECT_EQ(b.getX(), 0);
	a.test();
	EXPECT_EQ(a.getX(), 0);
	EXPECT_EQ(b.getX(), 1);
	b.test();
	EXPECT_EQ(a.getX(), 0);
	EXPECT_EQ(b.getX(), 1);
	//	piCout << "================";
}

TEST(PiobjectConnections, CONNECTU_DISCONNECT) {
	Object a;
	Object b;
	EXPECT_EQ(a.getX(), 0);
	EXPECT_EQ(b.getX(), 0);
	a.test();
	EXPECT_EQ(a.getX(), 0);
	EXPECT_EQ(b.getX(), 0);
	b.test();
	EXPECT_EQ(a.getX(), 0);
	EXPECT_EQ(b.getX(), 0);
	CONNECTU(&a, event_test, &b, handler_test);
	EXPECT_EQ(a.getX(), 0);
	EXPECT_EQ(b.getX(), 0);
	a.test();
	EXPECT_EQ(a.getX(), 0);
	EXPECT_EQ(b.getX(), 1);
	b.test();
	EXPECT_EQ(a.getX(), 0);
	EXPECT_EQ(b.getX(), 1);
	PIObject::piDisconnect(&a, "event_test");
	EXPECT_EQ(a.getX(), 0);
	EXPECT_EQ(b.getX(), 1);
	a.test();
	EXPECT_EQ(a.getX(), 0);
	EXPECT_EQ(b.getX(), 1);
	b.test();
	EXPECT_EQ(a.getX(), 0);
	EXPECT_EQ(b.getX(), 1);
	a.handler_val(99);
	EXPECT_EQ(a.getX(), 99);
	EXPECT_EQ(b.getX(), 1);
	CONNECTU(&a, event_val, &b, handler_val);
	EXPECT_EQ(a.getX(), 99);
	EXPECT_EQ(b.getX(), 1);
	a.test_val();
	EXPECT_EQ(a.getX(), 99);
	EXPECT_EQ(b.getX(), 99);
	a.handler_val(-1);
	EXPECT_EQ(a.getX(), -1);
	EXPECT_EQ(b.getX(), 99);
	PIObject::piDisconnect(&a, "event_val", &b);
	EXPECT_EQ(a.getX(), -1);
	EXPECT_EQ(b.getX(), 99);
	a.test_val();
	EXPECT_EQ(a.getX(), -1);
	EXPECT_EQ(b.getX(), 99);
	//	piCout << "================";
}


TEST(PiobjectConnections, CONNECTL) {
	Object a;
	Object b;
	ASSERT_EQ(a.getX(), 0);
	ASSERT_EQ(b.getX(), 0);
	a.test();
	ASSERT_EQ(a.getX(), 0);
	ASSERT_EQ(b.getX(), 0);
	b.test();
	ASSERT_EQ(a.getX(), 0);
	ASSERT_EQ(b.getX(), 0);
	CONNECTL(&a, event_test, [&b]() { b.handler_val(7); });
	ASSERT_EQ(a.getX(), 0);
	ASSERT_EQ(b.getX(), 0);
	a.test();
	ASSERT_EQ(a.getX(), 0);
	ASSERT_EQ(b.getX(), 7);
	b.test();
	ASSERT_EQ(a.getX(), 0);
	ASSERT_EQ(b.getX(), 7);
	//	piCout << "================";
}

TEST(PiobjectConnections, CONNECTL_DISCONNECT) {
	Object a;
	Object b;
	ASSERT_EQ(a.getX(), 0);
	ASSERT_EQ(b.getX(), 0);
	a.test();
	ASSERT_EQ(a.getX(), 0);
	ASSERT_EQ(b.getX(), 0);
	b.test();
	ASSERT_EQ(a.getX(), 0);
	ASSERT_EQ(b.getX(), 0);
	CONNECTL(&a, event_test, [&b]() { b.handler_test(); });
	ASSERT_EQ(a.getX(), 0);
	ASSERT_EQ(b.getX(), 0);
	a.test();
	ASSERT_EQ(a.getX(), 0);
	ASSERT_EQ(b.getX(), 1);
	b.test();
	ASSERT_EQ(a.getX(), 0);
	ASSERT_EQ(b.getX(), 1);
	b.handler_test();
	ASSERT_EQ(a.getX(), 0);
	ASSERT_EQ(b.getX(), 2);
	PIObject::piDisconnect(&a, "event_test");
	ASSERT_EQ(a.getX(), 0);
	ASSERT_EQ(b.getX(), 2);
	a.test();
	ASSERT_EQ(a.getX(), 0);
	ASSERT_EQ(b.getX(), 2);
	//	piCout << "================";
}

TEST(PiobjectConnections, CONNECTL_twice) {
	Object a;
	Object b;
	CONNECTL(&a, event_test, [&b]() { b.handler_test(); });
	a.test();
	ASSERT_EQ(a.getX(), 0);
	ASSERT_EQ(b.getX(), 1);
	CONNECTL(&a, event_test, [&b]() { b.handler_test(); });
	a.test();
	ASSERT_EQ(a.getX(), 0);
	ASSERT_EQ(b.getX(), 3);
	b.handler_val(0);
	ASSERT_EQ(a.getX(), 0);
	ASSERT_EQ(b.getX(), 0);
	PIObject::piDisconnect(&a, "event_test");
	a.test();
	ASSERT_EQ(a.getX(), 0);
	ASSERT_EQ(b.getX(), 0);
	CONNECTL(&a, event_test, [&b]() { b.handler_test(); });
	a.test();
	ASSERT_EQ(a.getX(), 0);
	ASSERT_EQ(b.getX(), 1);
	//	piCout << "================";
}

TEST(PiobjectConnections, CONNECT_AFTER_DISCONNECT) {
	Object a;
	Object b;
	CONNECTL(&a, event_test, [&b]() { b.handler_test(); });
	a.test();
	ASSERT_EQ(b.getX(), 1);
	PIObject::piDisconnect(&a, "event_test");
	a.test();
	ASSERT_EQ(b.getX(), 1);
	DISCONNECT1(void, int, &a, event_val, &b, handler_val);
	CONNECT1(void, int, &a, event_val, &b, handler_val);
	a.handler_val(8);
	a.test_val();
	ASSERT_EQ(a.getX(), 8);
	ASSERT_EQ(b.getX(), 8);
	//	piCout << "================";
}

TEST(PiobjectConnections, CONNECTL_WRONG_DISCONNECT) {
	Object a;
	Object b;
	CONNECTL(&a, event_test, [&b]() { b.handler_test(); });
	a.test();
	ASSERT_EQ(b.getX(), 1);
	PIObject::piDisconnect(&b, "event_test");
	a.test();
	ASSERT_EQ(b.getX(), 2);
	PIObject::piDisconnect(&a, "event_test");
	a.test();
	ASSERT_EQ(b.getX(), 2);
	//	piCout << "================";
}

TEST(PiobjectConnections, CONNECT_WRONG_DISCONNECT) {
	Object a;
	Object b;

	CONNECT0(void, &a, event_test, &b, handler_test);
	a.test();
	ASSERT_EQ(b.getX(), 1);
	PIObject::piDisconnect(&b, "event_test");
	a.test();
	ASSERT_EQ(b.getX(), 2);
	PIObject::piDisconnect(&a, "event_test");
	a.test();
	ASSERT_EQ(b.getX(), 2);
	//	piCout << "================";
}

TEST(PiobjectConnections, CONNECTU_WRONG_DISCONNECT) {
	Object a;
	Object b;
	CONNECTU(&a, event_test, &b, handler_test);
	a.test();
	ASSERT_EQ(b.getX(), 1);
	PIObject::piDisconnect(&b, "event_test");
	a.test();
	ASSERT_EQ(b.getX(), 2);
	PIObject::piDisconnect(&a, "event_test");
	a.test();
	ASSERT_EQ(b.getX(), 2);
	//	piCout << "================";
}
