/*
 *  psychlops_widgets_base.cpp
 *  Psychlops Standard Library (Universal)
 *
 *  Last Modified 2011/01/19 by Kenchi HOSOKAWA
 *  (C) 2011 Kenchi HOSOKAWA, Kazushi MARUYA and Takao SATO
 */


#include <iostream>
#include "psychlops_widgets_event.h"
#include "../../../core/graphic/psychlops_g_canvas.h"


namespace Psychlops
{

namespace Events
{
	long PointerDeviceEvent::getTime() { return time; }
	Point PointerDeviceEvent::getPlace() { return place; }
	PointerDeviceEvent::PointerDeviceEvent() {}
	const char* PointerDeviceEvent::name = "PointerDeviceEvent"; const char* PointerDeviceEvent::getName() const { return name; };

	MouseLeftDown::MouseLeftDown() {}
	MouseLeftDown::MouseLeftDown(long when, Point where) { time = when; place = where; }
	const char* MouseLeftDown::name = "MouseLeftDown"; const char* MouseLeftDown::getName() const { return name; };

	MouseLeftUp::MouseLeftUp() {}
	MouseLeftUp::MouseLeftUp(long when, Point where) { time = when; place = where; }
	const char* MouseLeftUp::name = "MouseLeftUp"; const char* MouseLeftUp::getName() const { return name; };

	MouseRightDown::MouseRightDown() {}
	MouseRightDown::MouseRightDown(long when, Point where) { time = when; place = where; }
	const char* MouseRightDown::name = "MouseRightDown"; const char* MouseRightDown::getName() const { return name; };

	MouseRightUp::MouseRightUp() {}
	MouseRightUp::MouseRightUp(long when, Point where) { time = when; place = where; }
	const char* MouseRightUp::name = "MouseRightUp"; const char* MouseRightUp::getName() const { return name; };


	KeyEvent::KeyEvent() {}
	const char* KeyEvent::name = "KeyEvent"; const char* KeyEvent::getName() const { return name; };

	KeyDown::KeyDown() {}
	KeyDown::KeyDown(long when, unsigned int where) { time = when; code = where; }
	const char* KeyDown::name = "KeyDown"; const char* KeyDown::getName() const { return name; };

	KeyUp::KeyUp() {}
	KeyUp::KeyUp(long when, unsigned int where) { time = when; code = where; }
	const char* KeyUp::name = "KeyUp"; const char* KeyUp::getName() const { return name; };



	Focus::Focus() {}
	const char* Focus::name = "Focus"; const char* Focus::getName() const { return name; };

	Blur::Blur() {}
	const char* Blur::name = "Blur"; const char* Blur::getName() const { return name; };

	Evoke::Evoke() {}
	const char* Evoke::name = "Evoke"; const char* Evoke::getName() const { return name; };

	AddToTabstopList::AddToTabstopList(Emittable *e) { target = e; }
	const char* AddToTabstopList::name = "AddToTabstopList"; const char* AddToTabstopList::getName() const { return name; };





	ActionFunction__::ActionFunction__(Fn f) : fn(f) { }
	void ActionFunction__::call(Event &event) { (*fn)(); }
	Callable__* createActionFunction(void (*fn)()) { return new ActionFunction__(fn); }



	Dispatcher::~Dispatcher()
	{
		std::map<const char*, std::list<DG> >::iterator s;
		std::list<DG>::iterator c;
		if(!slot.empty())
		{
			s = slot.begin();
			while( s != slot.end() )
			{
				if(!((*s).second.empty()))
				{
					c = (*s).second.begin();
					while( c != (*s).second.end() )
					{
						delete (*c);
						c++;
					}
				}
				++s;
			}
		}
	}

	void Dispatcher::emit(Event &event)
	{
		std::list<DG>::iterator c;
		const char* info = event.getName();
		if(slot.count(info) == 1)
		{
			std::list<DG> *it = &(slot[info]);
			c = (*it).begin();
			while( c != (*it).end() )
			{
				(*c)->call(event);
				++c;
			}
			++it;
		}
	}
	void Emittable::bubble(Event &ev) { if(&(getParent()) != 0) getParent().getBubble(ev); }


	EmittableBase::EmittableBase() { parent_ = 0; }

	Point EmittableBase::getHitDatum() { const Point p(0,0,0); return p; }
	Rectangle EmittableBase::getArea() { return area_; }
	Container& EmittableBase::getParent() { return *parent_; }
	Container& EmittableBase::setParent(Container &par) { parent_ = &par; return *parent_; }
	Dispatcher& EmittableBase::getSlots() { return slots_; }

	void EmittableBase::distribute(Event &ev) { getSlots().emit(ev); }
	void EmittableBase::distribute(Events::PointerDeviceEvent &ev) { getSlots().emit(ev); }




	ContainerBase::ContainerBase() { }
	Point ContainerBase::getHitDatum() { const Point p(0,0,0); return p; }
	void ContainerBase::append(Emittable &target)
	{
		children_.push_back(&target);
		target.setParent(*this);
	}
	void ContainerBase::remove(Emittable &target)
	{
	}
	void ContainerBase::getBubble(Event &ev)
	{
		slots_.emit(ev);
		bubble(ev);
	}

	void ContainerBase::distribute(Event &ev)
	{
		std::vector<Emittable *>::iterator w = children_.begin();
		while(w != children_.end() )
		{
			(**w).distribute(ev);
			w++;
		}
	}

	void ContainerBase::distribute(Events::PointerDeviceEvent &ev)
	{
		std::vector<Emittable *>::iterator w = children_.begin();
		while(w != children_.end() )
		{
			Point p = (**w).getHitDatum();
			if((**w).getArea().include(ev.getPlace().shift(-p.x, -p.y))) (**w).distribute(ev);
			w++;
		}
	}

	Rectangle ContainerBase::getArea() { return area_; }
	Container& ContainerBase::getParent() { return *parent_; }
	Container& ContainerBase::setParent(Container &par) { parent_ = &par; return *parent_; }
	Dispatcher& ContainerBase::getSlots() { return slots_; }



	RootContainer::RootContainer() { root = 0; focused = 0; focused__ = 0; }
	void RootContainer::distributeToFocus(Event &ev)
	{
		if(focused<tabstop_list.size())
			tabstop_list[focused]->distribute(ev);
	}
	void RootContainer::getBubble(Event &ev)
	{
		if(ev.getName() == AddToTabstopList::name)
		{
			AddToTabstopList *addToTabstopList = (AddToTabstopList*)(&ev);
			tabstop_list.push_back(addToTabstopList->target);
			focused = 0;
		}
		if(root!=0)
		{
			root->getBubble(ev.getName());
		}
	}

	void RootContainer::appendTabStop__(void *target)
	{
		bool on_off = true;
		if(on_off) {
			for(std::vector<void*>::iterator i=tabstop_list__.begin(); i!=tabstop_list__.end(); i++) {
				if(*i==target) { return; }
			}
			tabstop_list__.push_back(target);
		} else {
			for(std::vector<void*>::iterator i=tabstop_list__.begin(); i!=tabstop_list__.end(); i++) {
				if(*i==target) { tabstop_list__.erase(i); return; }
			}
		}
	}
	bool RootContainer::isFocused__(void *target)
	{
		if(tabstop_list__.size()>focused__) {
			return tabstop_list__[focused__]==target ? true : false;
		} else {
			return false;
		}
	}
	void RootContainer::nextTabStop()
	{
		++focused %= tabstop_list__.size();
		++focused__ %= tabstop_list__.size();
	}
	void RootContainer::prevTabStop()
	{
		--focused %= tabstop_list__.size();
		--focused__ %= tabstop_list__.size();
	}


}
}
