#include "PlatformPrecomp.h"
#include "DragControlComponent.h"
#include "util/GLESUtils.h"
#include "Entity/EntityUtils.h"
#include "BaseApp.h"
#include "Entity/ArcadeInputComponent.h"
#include "GUI/GameMenu.h"


DragControlComponent::DragControlComponent()
{
	SetName("DragControl");


SAMPLE_COUNT = 8; //unused

LENGTH_REQUIRED_FOR_MOVE = 16;

if (IsIphoneSize || IsIphone4Size) LENGTH_REQUIRED_FOR_MOVE = 32; //the screen is tiny, need a few more pixels

	if (IsIphone4Size)
	{
		LENGTH_REQUIRED_FOR_MOVE *= 2;
	}


}

DragControlComponent::~DragControlComponent()
{
}

void DragControlComponent::OnAdd(Entity *pEnt)
{
	EntityComponent::OnAdd(pEnt);
	m_pPos2d = &GetParent()->GetVar("pos2d")->GetVector2();
	m_pSize2d = &GetParent()->GetVar("size2d")->GetVector2();
	if (IsIPAD())
	{
		*m_pPos2d =(CL_Vec2f(0,29));
	} else
	{
		*m_pPos2d = (iPhoneMap(0,29));
	}
	
	
	
	//fit the active area to match the active dink screen layout
	if (g_dglo.GetActiveView() != DinkGlobals::VIEW_ZOOMED && IsDrawingDinkStatusBar())
	{
		if (IsIPAD())
		{
			*m_pSize2d = CL_Vec2f(865, 584);
		} else
		{
			*m_pSize2d = iPhoneMap(380, 237);
		}

	} else
	{
		if (IsIPAD())
		{
			*m_pSize2d = CL_Vec2f(866, 715);

		} else
		{
			*m_pSize2d = iPhoneMap(380, 286);
		}
	}
	
	if (GetApp()->GetIconsOnLeft())
	{
		m_pPos2d->x += GetScreenSizeXf()-m_pSize2d->x;
	}
	
	m_lastTouch = CL_Vec2f(0,0);
	
	/*
	m_pScale = &GetParent()->GetShared()->GetVarWithDefault("scale", Variant(1.0f))->GetFloat();
	m_pRotation = &GetParent()->GetVar("rotation")->GetFloat();  //in degrees

	m_pColor = &GetParent()->GetShared()->GetVarWithDefault("color", Variant(MAKE_RGBA(255,255,255,255)))->GetUINT32();
	m_pColorMod = &GetParent()->GetShared()->GetVarWithDefault("colorMod", Variant(MAKE_RGBA(255,255,255,255)))->GetUINT32();
	m_pAlpha = &GetParent()->GetShared()->GetVarWithDefault("alpha", Variant(1.0f))->GetFloat();
	m_pAlignment = &GetParent()->GetVar("alignment")->GetUINT32();
	*/

	//register ourselves to render if the parent does
	//GetParent()->GetFunction("OnRender")->sig_function.connect(1, boost::bind(&DragControlComponent::OnRender, this, _1));
	GetParent()->GetFunction("OnUpdate")->sig_function.connect(1, boost::bind(&DragControlComponent::OnUpdate, this, _1));
	GetBaseApp()->m_sig_arcade_input.connect(1, boost::bind(&DragControlComponent::OnArcadeInput, this, _1));	

	GetParent()->GetVar("ignoreTouchesOutsideRect")->Set(uint32(1));
	EntityComponent *pTouch = GetParent()->AddComponent(new TouchHandlerComponent);
	
	//movement arrows

	//for speed, we've disabled movement message handling in App.cpp, but we actually want them just here, so we'll hardwire it
	AddInputMovementFocusIfNeeded(GetParent());

	GetParent()->GetFunction("OnOverStart")->sig_function.connect(1, boost::bind(&DragControlComponent::OnOverStart, this, _1));	
	GetParent()->GetFunction("OnOverEnd")->sig_function.connect(1, boost::bind(&DragControlComponent::OnOverEnd, this, _1));	
	GetParent()->GetFunction("OnOverMove")->sig_function.connect(1, boost::bind(&DragControlComponent::OnOverMove, this, _1));

	GetParent()->GetParent()->GetFunction("OnKillingControls")->sig_function.connect(1, boost::bind(&DragControlComponent::OnKillingControls, this, _1));	

	/*

	EntityComponent *pFilter = m_pArrowEnt->AddComponent(new FilterInputComponent);
	pFilter->GetVar("mode")->Set(uint32(FilterInputComponent::MODE_CLIP_INPUT_TO_ABSOLUTE_CLIP_RECT_AND_DISABLE_INPUT_CHILDREN));
	pFilter->GetVar("clipRect")->Set(CL_Rectf(0,43,397, GetScreenSizeY()));

	m_timeOfLastTouch = GetTick(TIMER_SYSTEM);
	SetAlignmentEntity(m_pArrowEnt, ALIGNMENT_CENTER);
	m_pArrowEnt->GetVar("pos2d")->Set(CL_Vec2f(80, 240));

	m_vArrowImageSizeOver2 = m_pArrowEnt->GetVar("size2d")->GetVector2()/2;
	*/
	VariantList vTemp;
	OnOverEnd(&vTemp);
}

void DragControlComponent::OnRemove()
{
	EntityComponent::OnRemove();
}

void DragControlComponent::SendKey(eDinkInput key, bool bIsDown)
{
	if (bIsDown)
	{
		g_dglo.m_dirInput[key] = true;
		g_dglo.m_dirInputFinished[key] = false; //make sure it wasn't scheduled to stop pressing
	} else
	{
		g_dglo.m_dirInputFinished[key] = true;
	}
}

void DragControlComponent::OnKillingControls(VariantList *pVList)
{
	RemoveFocusIfNeeded(GetParent());
}

void DragControlComponent::AddSample(DragUnit v)
{
	if (DinkIsDoingScreenTransition()) return;
	m_samples.push_back(v);
	
	/*
	if (m_samples.size() > SAMPLE_COUNT)
	{
	  m_samples.pop_front();
	}
	*/
	
}

void DragControlComponent::OnOverStart(VariantList *pVList)
{
	m_samples.clear();
	m_lastTouch = pVList->Get(0).GetVector2();
}

void DragControlComponent::OnOverEnd(VariantList *pVList)
{
//	CL_Vec2f vPos = pVList->Get(0).GetVector2();
//	LogMsg("Got over end: %s", PrintVector2(vPos).c_str());
	m_samples.clear();
	m_lastTouch = CL_Vec2f(0,0);
	ClearKeyInput();
}

void DragControlComponent::OnOverMove(VariantList *pVList)
{
	AddSample( DragUnit(pVList->Get(0).GetVector2() - m_lastTouch, GetTick(TIMER_GAME)));
	//SetPosition(pVList->Get(0).GetVector2());
	m_lastTouch = pVList->Get(0).GetVector2();
}

void DragControlComponent::ClearKeyInput()
{
	SendKey(DINK_INPUT_UP, false);
	SendKey(DINK_INPUT_DOWN, false);
	SendKey(DINK_INPUT_LEFT, false);
	SendKey(DINK_INPUT_RIGHT, false);
}

void DragControlComponent::OnRender(VariantList *pVList)
{
	CL_Vec2f vFinalPos = pVList->m_variant[0].GetVector2()+*m_pPos2d;
}

void DragControlComponent::ProcessLastJoystickReading()
{

	if (m_samples.size() == 0) return;
	//first, lets figure out what direction we want
	CL_Vec2f vDir = CL_Vec2f(0,0);
	
	std::deque< DragUnit> sampleTemp;

	for (int i=m_samples.size()-1; i >= 0;)
	{
		//if (m_samples.size() < SAMPLE_COUNT) break;

		/*
		if (1)
		//if (m_samples.at(i).m_timeMade+100 < GetTick(TIMER_GAME))
			{
			vDir = CL_Vec2f(0,0);
	//would removing this stop us from moving?
			for (int h=1; h < m_samples.size();h++)
			{
				vDir += m_samples[h].m_vPos;
			}
			
			if (vDir.length() < LENGTH_REQUIRED_FOR_MOVE)
			{
				//yes it would.  Just let it be, for now.
				//break;
			} else
			{
				//it's not needed
			}

			m_samples.erase(m_samples.begin()+i);
			continue;
		} else
		{
			break;
		}

		*/
		vDir += m_samples[i].m_vPos;
		sampleTemp.push_front( m_samples[i]);
		
		if (vDir.length() >=  LENGTH_REQUIRED_FOR_MOVE)
		{
			//all done
			break;
		}
		
		i--;
	}
	
	m_samples = sampleTemp;

	//vDir = CL_Vec2f(0,0);

	/*
	for (unsigned int i=0; i < m_samples.size();i++)
	{
		vDir += m_samples[i].m_vPos;
	}
	*/
	ClearKeyInput();

	//LogMsg("vDir length is %.2f", vDir.length());
	if (vDir.length() < LENGTH_REQUIRED_FOR_MOVE) return;

	vDir.normalize();

	//recalculate the points
	sampleTemp.clear();

	//sampleTemp.push_front(m_samples[m_samples.size()-1]);

	sampleTemp.push_front(DragUnit( (vDir*LENGTH_REQUIRED_FOR_MOVE)*1.1, 0));
	m_samples = sampleTemp;

#ifdef _DEBUG
	//LogMsg("Dir is %s (%d samples)", PrintVector2(vDir).c_str(), m_samples.size());
#endif
	//convert to 360 degrees
	int dir = (int(RAD2DEG(atan2(vDir.y, vDir.x))+(90)));

	const int maxDirections = 8;
	int finaldir = mod(dir+ (360/ (maxDirections*2)), 360)/ (360/maxDirections);

	//nah, let's do 8 actually

	//LogMsg("Pressing %s, which is dir %d (final: %d)", PrintVector2(m_lastTouchDir).c_str(), dir, finaldir);

	switch (finaldir)
	{
	case 0:  SendKey(DINK_INPUT_UP, true); break;
	case 1:  SendKey(DINK_INPUT_RIGHT, true); SendKey(DINK_INPUT_UP, true); break;

	case 2:  SendKey(DINK_INPUT_RIGHT, true); break;
	case 3:  SendKey(DINK_INPUT_RIGHT, true); SendKey(DINK_INPUT_DOWN, true);  break;
	case 4:  SendKey(DINK_INPUT_DOWN, true);  break;

	case 5:  SendKey(DINK_INPUT_DOWN, true);  SendKey(DINK_INPUT_LEFT, true);  break;
	case 6:  SendKey(DINK_INPUT_LEFT, true);  break;
	case 7:  SendKey(DINK_INPUT_LEFT, true);  SendKey(DINK_INPUT_UP, true);  break;
	}
}



void DragControlComponent::OnArcadeInput(VariantList *pVList)
{
	int vKey = pVList->Get(0).GetUINT32();
	bool bIsDown = pVList->Get(1).GetUINT32() != 0;

	//LogMsg("Key %d, down is %d", vKey, int(bIsDown));
	switch (vKey)
	{
	case VIRTUAL_KEY_DIR_LEFT:
		SendKey(DINK_INPUT_LEFT, bIsDown);
		break;

	case VIRTUAL_KEY_DIR_RIGHT:
		SendKey(DINK_INPUT_RIGHT, bIsDown);
		break;

	case VIRTUAL_KEY_DIR_UP:
		SendKey(DINK_INPUT_UP, bIsDown);
		break;

	case VIRTUAL_KEY_DIR_DOWN:
		SendKey(DINK_INPUT_DOWN, bIsDown);
		break;
	}
}


void DragControlComponent::OnUpdate(VariantList *pVList)
{
	ProcessLastJoystickReading();
}