#include "common.h"

#include "Timer.h"
#include "ModelIndices.h"
#include "Streaming.h"
#include "CopPed.h"
#include "Population.h"
#include "RenderBuffer.h"
#include "Camera.h"
#include "Ropes.h"

CRope CRopes::aRopes[8];

RwImVertexIndex RopeIndices[64] = {
	0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7,
	7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15,
	15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23,
	23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 30, 31,
	31, 32	// unused
};

void
CRope::Update(void)
{
	int i;
	float step = Pow(0.85f, CTimer::GetTimeStep());
	if(!m_bWasRegistered && CTimer::GetTimeInMilliseconds() > m_updateTimer){
		m_speed[0].z -= 0.0015f*CTimer::GetTimeStep();
		m_pos[0] += m_speed[0]*CTimer::GetTimeStep();
	}
	for(i = 1; i < ARRAY_SIZE(m_pos); i++){
		CVector prevPos = m_pos[i];
		m_pos[i] += m_speed[i]*step*CTimer::GetTimeStep();
		m_pos[i].z -= 0.05f*CTimer::GetTimeStep();
		CVector dist = m_pos[i] - m_pos[i-1];
		m_pos[i] = m_pos[i-1] + (0.625f/dist.Magnitude())*dist;
		m_speed[i] = (m_pos[i] - prevPos)/CTimer::GetTimeStep();
	}
	if(!m_bWasRegistered && m_pos[0].z < 0.0f)
		m_bActive = false;
	m_bWasRegistered = false;
}

void
CRope::Render(void)
{
	int i;
	int numVerts = 0;
	if(!TheCamera.IsSphereVisible(m_pos[16], 20.0f))
		return;

	for(i = 0; i < ARRAY_SIZE(m_pos); i++){
		RwIm3DVertexSetRGBA(&TempBufferRenderVertices[i], 128, 128, 128, 100);
		RwIm3DVertexSetPos(&TempBufferRenderVertices[i], m_pos[i].x, m_pos[i].y, m_pos[i].z);
	}

	RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
	RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
	RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
	RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);

	if(RwIm3DTransform(TempBufferRenderVertices, ARRAY_SIZE(m_pos), nil, rwIM3D_VERTEXXYZ|rwIM3D_VERTEXRGBA)){
#ifdef FIX_BUGS
		RwIm3DRenderIndexedPrimitive(rwPRIMTYPELINELIST, RopeIndices, 2*(ARRAY_SIZE(m_pos)-1));
#else
		RwIm3DRenderIndexedPrimitive(rwPRIMTYPEPOLYLINE, RopeIndices, 2*(ARRAY_SIZE(m_pos)-1));
#endif
		RwIm3DEnd();
	}
}


void
CRopes::Init(void)
{
	int i;
	for(i = 0; i < ARRAY_SIZE(aRopes); i++)
		aRopes[i].m_bActive = false;
}

void
CRopes::Update(void)
{
	int i;
	for(i = 0; i < ARRAY_SIZE(aRopes); i++)
		if(aRopes[i].m_bActive)
			aRopes[i].Update();
}

void
CRopes::Render(void)
{
	int i;
	for(i = 0; i < ARRAY_SIZE(aRopes); i++)
		if(aRopes[i].m_bActive)
			aRopes[i].Render();
}

bool
CRopes::RegisterRope(uintptr id, CVector pos, bool setUpdateTimer)
{
	int i, j;
	for(i = 0; i < ARRAY_SIZE(aRopes); i++){
		if(aRopes[i].m_bActive && aRopes[i].m_id == id){
			aRopes[i].m_pos[0] = pos;
			aRopes[i].m_speed[0] = CVector(0.0f, 0.0f, 0.0f);
			aRopes[i].m_bWasRegistered = true;
			return true;
		}
	}
	for(i = 0; i < ARRAY_SIZE(aRopes); i++)
		if(!aRopes[i].m_bActive){
			aRopes[i].m_id = id;
			aRopes[i].m_pos[0] = pos;
			aRopes[i].m_speed[0] = CVector(0.0f, 0.0f, 0.0f);
			aRopes[i].m_unk = false;
			aRopes[i].m_bWasRegistered = true;
			aRopes[i].m_updateTimer = setUpdateTimer ? CTimer::GetTimeInMilliseconds() + 20000 : 0;
			for(j = 1; j < ARRAY_SIZE(aRopes[0].m_pos); j++){
				if(j & 1)
					aRopes[i].m_pos[j] = aRopes[i].m_pos[j-1] + CVector(0.0f, 0.0f, 0.625f);
				else
					aRopes[i].m_pos[j] = aRopes[i].m_pos[j-1] - CVector(0.0f, 0.0f, 0.625f);
				aRopes[i].m_speed[j] = CVector(0.0f, 0.0f, 0.0f);
			}
			aRopes[i].m_bActive = true;
			return true;
		}
	return false;
}

void
CRopes::SetSpeedOfTopNode(uintptr id, CVector speed)
{
	int i;
	for(i = 0; i < ARRAY_SIZE(aRopes); i++)
		if(aRopes[i].m_bActive && aRopes[i].m_id == id){
			aRopes[i].m_speed[0] = speed;
			return;
		}
}

bool
CRopes::FindCoorsAlongRope(uintptr id, float t, CVector *coors)
{
	int i, j;
	float f;
	for(i = 0; i < ARRAY_SIZE(aRopes); i++)
		if(aRopes[i].m_bActive && aRopes[i].m_id == id){
			t = (ARRAY_SIZE(aRopes[0].m_pos)-1)*clamp(t, 0.0f, 0.999f);
			j = t;
			f = t - j; 
			*coors = (1.0f-f)*aRopes[i].m_pos[j] + f*aRopes[i].m_pos[j+1];
			return true;
		}
	return false;
}

bool
CRopes::CreateRopeWithSwatComingDown(CVector pos)
{
	static uint32 ropeId = 0;

	if(!CStreaming::HasModelLoaded(MI_SWAT) || !RegisterRope(ropeId+100, pos, true))
		return false;
	CCopPed *swat = (CCopPed*)CPopulation::AddPed(PEDTYPE_COP, COP_HELI_SWAT, pos);
	swat->bUsesCollision = false;
	swat->m_pRopeEntity = (CEntity*)1;
	swat->m_nRopeID = 100 + ropeId;
	CAnimManager::BlendAnimation(swat->GetClump(), ASSOCGRP_STD, ANIM_ABSEIL, 4.0f);
	ropeId++;
	return true;
}
