/*
Using parts of the TUIO C++ Demo TuioDemo.h

TUIO C++ Demo - part of the reacTIVision project
http://reactivision.sourceforge.net/

Copyright (c) 2005-2009 Martin Kaltenbrunner <mkalten@iua.upf.edu>
*/

// Do not use TUIO Objects yet. They are not thread safe.

#pragma once

#include "Infrastructure\Vector2.h"

#include <vector>
#include <list>
#include <map>

#include <TuioClient.h>
#include <TuioObject.h>
#include <TuioCursor.h>
		
#ifndef WIN32
#include <pthread.h>
#include <sys/time.h>
#else
#include <windows.h>
#endif

class Touchable;
class SelectionCircle;


namespace TouchEventTypes
{
	enum Enum
	{
		FingerDown,
		FingerMove,
		FingerUp
	};
}

class MultiTouchManager : public TUIO::TuioListener
{
public:
	// TUIO: x and y from 0 to 1
	static Vector2 TUIOToScreenCoordinates(Vector2 tuioCoords);
	static Vector2 TUIOToAngelCoordinates(Vector2 tuioCoords);
	static void TUIOPointsToAngelPoints(std::list<TUIO::TuioPoint> *tuioPoints, std::list<Vector2> *angelPointsOut);

	MultiTouchManager();
	virtual ~MultiTouchManager();
	
	void addTuioObject(TUIO::TuioObject *tobj);
	void updateTuioObject(TUIO::TuioObject *tobj);
	void removeTuioObject(TUIO::TuioObject *tobj);
	
	void addTuioCursor(TUIO::TuioCursor *tcur);
	void updateTuioCursor(TUIO::TuioCursor *tcur);
	void removeTuioCursor(TUIO::TuioCursor *tcur);

	virtual void update();

	// use this for multiselection etc.
	virtual void removeTuioCursorWithoutTouchable(std::list<Vector2> *path) = 0;

	virtual void refresh(TUIO::TuioTime ftime);

	TUIO::TuioClient* getTUIOClient(){return tuioClient;}
	
	virtual void addTouchableToCallbackList(Touchable *rhs);
	virtual void removeTouchableFromCallbackList(Touchable *rhs);
	
protected:
	static const int PORT_NUMBER;
	
	typedef struct TUIOTouchEventData
	{
		int cursorID;
		TouchEventTypes::Enum eventType;
		Vector2 pos;
		std::list<Vector2>* path;

		TUIOTouchEventData(int TUIOcursorID, TouchEventTypes::Enum TUIOEventType, Vector2 newPos, std::list<Vector2>* pathList) :
		cursorID(TUIOcursorID), eventType(TUIOEventType), pos(newPos), path(pathList){}
	} TouchEvent;

	void Initialize();

	virtual Touchable* getTouchableAtPosition(Vector2 fingerPos);

	virtual void forwardCursorEventsToTouchables();

	bool verbose;
	TUIO::TuioClient *tuioClient;
	std::vector<Touchable*> *callbackList;
	std::map<int, Touchable*> *cursorIDToTouchableMapping;			// cursorID and Touchable
	
	std::list<TouchEvent> cursorEventBuffer;
	
#ifndef WIN32
	pthread_t thread;
	pthread_mutex_t cursorMutex;
#else
	HANDLE cursorEventBufferMutex;
#endif	
	
	void lockCursorEventBuffer();
	void unlockCursorEventBuffer();
	
	void removeTouchableFromCursorMap(Touchable* remThis);
	void removeCursorFromEventBuffers(int removeThisID);
};						 