#include "stdafx.h"
#include "CellWarsMTManager.h"

#include "Touchable.h"
#include "MultiSelectionCircle.h"
#include "Infrastructure\Camera.h"
#include "CellWarsGameManager.h"
#include "Bacterium.h"

#include <algorithm>
#include <iostream>

//#define DEBUG_OUTPUT

const float CellWarsMTManager::MAX_DIST_SELECTION_CIRCLE_START_TO_END = 5.0f;
const int CellWarsMTManager::MOUSE_CURSOR_ID = -1;
const float CellWarsMTManager::TIME_UNTIL_MOUSE_FADE = 30.0f;

CellWarsMTManager::CellWarsMTManager() : MultiTouchManager(), mMousePath(NULL), mousePosBorderOffset(0, 0),
	timeSinceLastMouseEvent(TIME_UNTIL_MOUSE_FADE), mouseCursor(new Actor())
{
	selectionCircleList = new std::list<MultiSelectionCircle*>();

	if (verbose)
		std::cout << "cell wars multitouch constructor" << std::endl;

	mouseCursor->SetSprite("Resources/Images/cursor.png");
	mouseCursor->SetSize(2);
	theWorld.Add(mouseCursor, LayerEnum::Cursor);
}

CellWarsMTManager::~CellWarsMTManager()
{
	std::list<MultiSelectionCircle*>::iterator it(selectionCircleList->begin());

	while (it != selectionCircleList->end())
	{
		(*it)->Destroy();
		++it;
	}

	delete selectionCircleList;
}

void CellWarsMTManager::removeTuioCursorWithoutTouchable(std::list<Vector2> *path)
{
	// only if distance from start to end not to big
	std::list<Vector2>::iterator lastPoint = path->end();
	--lastPoint;
	float dist = ((*path->begin()) - (*lastPoint)).Length();
	if (dist < MAX_DIST_SELECTION_CIRCLE_START_TO_END)
	{
		// close polygon
		path->push_back(*path->begin());
		std::list<Bacterium*>* bacteriaList = theCellWarsGame.getBacteriaList();
	
		bool madeNewSelection = false;
		MultiSelectionCircle* newSelectionCircle = NULL;
		std::list<Bacterium*>::iterator it = bacteriaList->begin();
		while(it != bacteriaList->end())
		{
			if (!(*it)->isCurrentlySelected())
			{
				bool pointInPolygon = MathUtil::PointIsInsidePolygon((*it)->GetPosition(), path);
				if (pointInPolygon)
				{
					if (!madeNewSelection)
					{
						newSelectionCircle = new MultiSelectionCircle(this);
						selectionCircleList->push_back(newSelectionCircle);
						madeNewSelection = true;
					}
					newSelectionCircle->addBacteriumToSelectionList(*it);
				}
			}

			++it;
		}
	}
}

void CellWarsMTManager::removeTouchableFromCursorMap(Touchable* remThis)
{
	std::map<int, Touchable*>::iterator it(cursorIDToTouchableMapping->begin());

	while (it != cursorIDToTouchableMapping->end())
	{
		if ((*it).second == remThis)
		{
			cursorIDToTouchableMapping->erase(it++);
		}
		else
			++it;
	}
}

void CellWarsMTManager::removeSelectedBacteriumFromSelectionCircles(Bacterium* remBact)
{
	std::list<MultiSelectionCircle*>::iterator it(selectionCircleList->begin());

	while (it != selectionCircleList->end())
	{
		// if remBact is the last selected bacterium of this
		// MultiSelectionCircle, it will destroy itself,
		// which will invalidate the iterator
		MultiSelectionCircle* itTempRef = (*it);
		++it;
		itTempRef->removeBacteriumFromSelectionList(remBact);
	}
}

void CellWarsMTManager::removeMultiSelectionCircle(MultiSelectionCircle* remMTCircle)
{
	std::list<MultiSelectionCircle*>::iterator it;
	it = std::find(selectionCircleList->begin(), selectionCircleList->end(), remMTCircle);
	if (it != selectionCircleList->end())
	{
		(*it)->Destroy();
		selectionCircleList->erase(it);
	}
}

void CellWarsMTManager::update(float dt)
{
	timeSinceLastMouseEvent += dt;

	mouseCursor->SetPosition(mCursorPos);
	if (timeSinceLastMouseEvent <= TIME_UNTIL_MOUSE_FADE)
	{
		mouseCursor->SetAlpha(1);
	}
	else
	{
		mouseCursor->SetAlpha(0);
	}

	if (cursorEventBuffer.size() > 0)
		theCellWarsGame.gotInput();

	MultiTouchManager::update();
}

Vec2i CellWarsMTManager::limitMousePosToScreen(Vec2i screenCoordinates)
{
	Vec2i limitedCoords(screenCoordinates);
	limitedCoords.X += mousePosBorderOffset.X;
	limitedCoords.Y += mousePosBorderOffset.Y;

	int resX = theCamera.GetWindowWidth();
	int resY = theCamera.GetWindowHeight();
	if (limitedCoords.X < 0)
	{
		mousePosBorderOffset.X -= limitedCoords.X;
		limitedCoords.X = 0;
	}
	if (limitedCoords.X >= resX)
	{
		mousePosBorderOffset.X -= limitedCoords.X - resX;
		limitedCoords.X = resX;
	}
	if (limitedCoords.Y < 0)
	{
		mousePosBorderOffset.Y -= limitedCoords.Y;
		limitedCoords.Y = 0;
	}
	if (limitedCoords.Y >= resY)
	{
		mousePosBorderOffset.Y -= limitedCoords.Y - resY;
		limitedCoords.Y = resY;
	}
	
#ifdef DEBUG_OUTPUT
	std::cout << "limitMousePosToScreen " << " at " << screenCoordinates.X << "|" << screenCoordinates.Y << 
		" offset: " << mousePosBorderOffset.X << "|" << mousePosBorderOffset.Y << 
		" limited: " << limitedCoords.X << "|" << limitedCoords.Y << std::endl;
#endif
	
	return limitedCoords;
}

void CellWarsMTManager::MouseDownEvent(Vec2i screenCoordinates, MouseButtonInput button)
{
	timeSinceLastMouseEvent = 0;
	if (button == MOUSE_LEFT)
	{
		mMousePath = new std::list<Vector2>();
		Vector2 mousePos(MathUtil::ScreenToWorld(limitMousePosToScreen(screenCoordinates)));
		mMousePath->push_back(Vector2(mousePos));

		lockCursorEventBuffer();
		cursorEventBuffer.push_back(TouchEvent(MOUSE_CURSOR_ID, TouchEventTypes::FingerDown, mousePos, mMousePath));
		
#ifdef DEBUG_OUTPUT
		std::cout << "MouseDownEvent " << MOUSE_CURSOR_ID << ", at " << mousePos.X << "|" << mousePos.Y << std::endl;
#endif

		unlockCursorEventBuffer();
	}
}

void CellWarsMTManager::MouseMotionEvent(Vec2i screenCoordinates)
{
	timeSinceLastMouseEvent = 0;
	Vector2 mousePos(MathUtil::ScreenToWorld(limitMousePosToScreen(screenCoordinates)));
	if (mMousePath)
	{
		mMousePath->push_back(Vector2(mousePos));

		lockCursorEventBuffer();
		cursorEventBuffer.push_back(TouchEvent(MOUSE_CURSOR_ID, TouchEventTypes::FingerMove, mousePos, mMousePath));
		
#ifdef DEBUG_OUTPUT
		std::cout << "MouseMotionEvent " << MOUSE_CURSOR_ID << ", at " << mousePos.X << "|" << mousePos.Y << std::endl;
#endif

		unlockCursorEventBuffer();
	}
	mCursorPos = mousePos;
}

void CellWarsMTManager::MouseUpEvent(Vec2i screenCoordinates, MouseButtonInput button)
{
	timeSinceLastMouseEvent = 0;
	if (button == MOUSE_LEFT)
	{
		Vector2 mousePos(MathUtil::ScreenToWorld(limitMousePosToScreen(screenCoordinates)));
		mMousePath->push_back(Vector2(mousePos));

		lockCursorEventBuffer();
		cursorEventBuffer.push_back(TouchEvent(MOUSE_CURSOR_ID, TouchEventTypes::FingerUp, mousePos, mMousePath));
		
#ifdef DEBUG_OUTPUT
		std::cout << "MouseUpEvent " << MOUSE_CURSOR_ID << ", at " << mousePos.X << "|" << mousePos.Y << std::endl;
#endif

		unlockCursorEventBuffer();

		mMousePath = NULL;
	}
}

void CellWarsMTManager::MouseWheelEvent(int position)
{
	timeSinceLastMouseEvent = 0;
}

void CellWarsMTManager::render()
{
	if (timeSinceLastMouseEvent <= TIME_UNTIL_MOUSE_FADE)
	{
		// cursor
		glColor4f(0.05f, 0.3f, 0.2f, 1.0f);

		if (mMousePath && mMousePath->size() > 0)
		{
			// path
			Vector2 lastPoint = mMousePath->front();
			for (std::list<Vector2>::iterator point(mMousePath->begin()); point != mMousePath->end(); ++point) 
			{
				DrawLine(lastPoint, *point);
				lastPoint = *point;
			}
		}
	}
}