#include <glibmm/thread.h>
#include <glibmm/timer.h>
#include "dispatcher.h"
#include <iostream>
#include <boost/shared_ptr.hpp>

using namespace Glib;
using boost::shared_ptr;
using namespace std;

// Class for worker thread
class Worker {
private:
	bool        kill_;
	int         msg_cnt_;
	Dispatcher& disp_;
	Thread*     thread_;
private:
	void main() {
		while(!kill_) { // No need for mutexing as this should be atomic
			g_atomic_int_inc(&msg_cnt_); // add 1 to unprocessed message count
			disp_.emit(); // Emit rapidly
			Glib::usleep(10000);
		}
	}
public:
	Worker(Dispatcher& d, int& msg_cnt)
	: kill_(false),
	  msg_cnt_(msg_cnt),
	  disp_(d),
	  thread_(Thread::create(sigc::mem_fun(*this, &Worker::main), true)) {

	}

	~Worker() {
		kill_ = true; // No need for mutexing as this should be atomic
		thread_->join();

		cout << "Worker::~Worker(): msg_cnt_: " << msg_cnt_ << endl;
		if (msg_cnt_ != 0) {
			cout << "  Warning: msg_cnt_ not zero!" << endl;
		}
	}
};

// This class owns the Worker object and its dispatcher
class WorkerOwner : public sigc::trackable {
private:
	int        msg_cnt_;
	Dispatcher dispatcher_;
	Worker     worker_;
	char x[1 << 24]; // create huge array in order to force the compiler to really
	                 // destroy this object on delete (otherwise we might not get
	                 // a real segfault)
private:
	void handler() {
		g_atomic_int_dec_and_test(&msg_cnt_); // decrement unprocessed message count
	}
public:
	WorkerOwner()
	: msg_cnt_(0),
	  worker_(dispatcher_, msg_cnt_) {
		dispatcher_.connect(sigc::mem_fun(*this, &WorkerOwner::handler));
	}
	~WorkerOwner() {

	}
};

shared_ptr<WorkerOwner> wrk[2];

// We want do destroy the owner of the Worker object at some point,
// here simulated by timeout

bool workerowner_destroyer() {
	wrk[0].reset(); // causes deletion of the WorkerOwner object
	return false;
}

// This simulates load in the main thread which causes dispatcher
// events to accumulate in the pipe (it is sufficient in the real application
// for events to accumulate for a short while and in the meanwhile destroy
// the dispatcher object)
bool timeout() {
	int i;
	for (i = 0; i < 10000000; i++); // some load
	//std::cout << std::dec << i << std::endl;
	return true;
}

int main(int argc, char* argv[]) {
	RefPtr<MainLoop> loop = MainLoop::create(false);
	thread_init();

	wrk[0].reset(new WorkerOwner());
	wrk[1].reset(new WorkerOwner());

	signal_timeout().connect(sigc::ptr_fun(&timeout), 10);
	signal_timeout().connect(sigc::ptr_fun(&workerowner_destroyer), 500);

	loop->run();

	return 0;
}
