/*************************************************************************
  Crytek Source File.
  Copyright (C), Crytek Studios, 2001-2004.
 -------------------------------------------------------------------------
  $Id$
  $DateTime$
  
 -------------------------------------------------------------------------
  History:
  - 22:11:2005: Created by Filippo De Luca
	- 31:01:2006: Modified & adopted to new HUD by Jan Müller

*************************************************************************/
#include "StdAfx.h"
#include "Game.h"
#include "Player.h"
#include "GameUtils.h"
#include <ISerialize.h>

#include <IGameTokens.h>

CNanoSuit::CNanoSuit() : m_pSprintSound(NULL), m_pStrengthSound(NULL), m_pMedicalSound(NULL)
{
	Reset(NULL);
	m_iLastSaved = 0;
	m_bCloaked = false;
}

CNanoSuit::~CNanoSuit()
{}

void CNanoSuit::Reset(CPlayer *owner)
{
	m_active = false;
	m_ownerId = owner?owner->GetEntityId():0;

	m_bStrengthUsed = false;

	m_energy = 200.0f;
	m_deltaEnergy = 0.0f;
	m_rechargeRate = 200.0f/10.0f;//about 10 sec to recharge full - set in update
	m_healthRechargeBar = 1.0f;
	m_healthMin = 100;
	m_rechargeAdjuster = 0;
	m_fLastSoundPlayedMedical = 0;

	memset(&m_slots,0,sizeof(m_slots));
	strcpy(m_slots[NANOSLOT_ARMOR].name,"armor");
	strcpy(m_slots[NANOSLOT_SPEED].name,"speed");
	strcpy(m_slots[NANOSLOT_STRENGTH].name,"strength");
	strcpy(m_slots[NANOSLOT_MEDICAL].name,"medical");
	
	SetAllSlots(50, 50, 50);

	m_healthRegenAdjuster = 0;
}

void CNanoSuit::UpdateHUD()
{
	if (!m_active)
		return;

	g_pGame->GetIGameFramework()->GetIGameTokenSystem()->SetOrCreateToken("hud.nanosuit.energy", TFlowInputData((float)m_energy, true));
	for (int i=0;i<NANOSLOT_LAST;++i)
	{
		char str[64];
		strcpy(str,"hud.nanosuit.");
		strcat(str,m_slots[i].name);

		g_pGame->GetIGameFramework()->GetIGameTokenSystem()->SetOrCreateToken(str, TFlowInputData((float)m_slots[i].realVal, true));
		strcat(str,"desired");
		g_pGame->GetIGameFramework()->GetIGameTokenSystem()->SetOrCreateToken(str, TFlowInputData((float)m_slots[i].desiredVal, true));
	}
}

void CNanoSuit::Update(CPlayer *owner,float frameTime)
{
	if (!m_active || !owner)
		return;

	//update health
	int32 currentHealth = owner->GetHealth();
	float recharge = m_rechargeRate;
	if (currentHealth < int(100) || m_bCloaked)
	{
		if(m_bCloaked)
			currentHealth = min(currentHealth, 98);

		//check for low health and play sound
		if(currentHealth < 90 && GetSlotValue(NANOSLOT_MEDICAL, true) > 50)
		{
			float now = GetISystem()->GetITimer()->GetAsyncTime().GetMilliSeconds();
			if(now - m_fLastSoundPlayedMedical > 30000.0f)
			{
				m_fLastSoundPlayedMedical = now;
				PlaySound(MEDICAL_SOUND);
			}
		}

		//now compute new regeneration
		if(currentHealth < m_healthMin)
			m_healthMin = currentHealth;
		m_healthRechargeBar = (currentHealth - m_healthMin) / (100.0f - m_healthMin);
		//heal the player according to healing energy ... (heal 1hp at least (health is an integer ..))
		//(adding/subtracting to/from normal healing rate in BasicActor.lua
		m_healthRegenAdjuster = max(m_slots[NANOSLOT_MEDICAL].realVal / 25.0f, 0.0f) - (m_bCloaked?0.5f:0.0f);
		recharge -= (m_rechargeRate * (m_slots[NANOSLOT_MEDICAL].desiredVal / 100.0f));
	}
	else
		m_healthMin = 100;

	//subtract energy from suit for active components
	if(m_bCloaked)
		recharge-= 7.30f;
	if(m_bStrengthUsed)
	{
		m_rechargeAdjuster = -100.0f;
		m_bStrengthUsed = false;
	}
	if(m_rechargeAdjuster < -2.0f)
	{
		recharge += m_rechargeAdjuster;
		m_rechargeAdjuster -= m_rechargeAdjuster*frameTime;
	}

	//update energy
	float lastDelta(m_deltaEnergy);

	if (m_deltaEnergy>0.0)
		m_deltaEnergy = max(m_deltaEnergy - 50.0f*frameTime,0.0f);
	else
		m_deltaEnergy = min(m_deltaEnergy + 50.0f*frameTime,0.0f);

	m_energy += lastDelta - m_deltaEnergy;
	m_energy = min(max(m_energy + recharge*frameTime,0.0f),200.0f);

	//in godMode nanosuit energy is always at full charge
	//SPlayerStats *plStats = (SPlayerStats *)owner->GetActorStats();
	//if (plStats && plStats->godMode)
	//	m_energy = 200.0f;

	for (int i=0;i<NANOSLOT_LAST;++i)
		m_slots[i].realVal = m_slots[i].desiredVal;

	Balance(m_energy);
}

void CNanoSuit::Balance(float energy)
{
	for(int i = 0; i < NANOSLOT_LAST; i++)
	{
		float slotPerCent = m_slots[i].desiredVal / 200; //computes percentage for 200 total ...
			m_slots[i].realVal = energy * slotPerCent;
	}
}

void CNanoSuit::SetEnergy(float value)
{
	float desiredEnergy = min(max(value,0.0f),100.0f);
	m_deltaEnergy += desiredEnergy - m_energy;
}

void CNanoSuit::SetAllSlots(float armor, float strength, float speed)
{
	float energy = armor + strength + speed;
	if(energy > 200)
		return;
	m_slots[NANOSLOT_ARMOR].desiredVal = armor;
	m_slots[NANOSLOT_STRENGTH].desiredVal = strength;
	m_slots[NANOSLOT_SPEED].desiredVal = speed;
	m_slots[NANOSLOT_MEDICAL].desiredVal = 200.0f - energy;
}

int CNanoSuit::IDByName(char *slotStr)
{
	if (!strcmp(slotStr,"speed"))
		return NANOSLOT_SPEED;
	else if (!strcmp(slotStr,"armor"))
		return NANOSLOT_ARMOR;
	else if (!strcmp(slotStr,"strength"))
		return NANOSLOT_STRENGTH;
	else if (!strcmp(slotStr,"medical"))
		return NANOSLOT_MEDICAL;
	else
		return NANOSLOT_LAST;
}

float CNanoSuit::GetUsedEnergy()
{
	if (!m_active)
		return 0.0f;

	float currentBudget(0);
	for (int i=0;i<NANOSLOT_LAST;++i)
		currentBudget += m_slots[i].desiredVal;

	return currentBudget;
}

float CNanoSuit::GetSlotValue(int slot,bool desired) const
{
	if (m_active && slot>=0 && slot<NANOSLOT_LAST)
		return (desired?m_slots[slot].desiredVal:m_slots[slot].realVal);

	return 0.0f;
}

bool CNanoSuit::GetSoundIsPlaying(ENanoSound sound) const
{
	if(!GetISystem()->GetIGame()->GetIGameFramework()->IsGameStarted())
		return false;
	switch(sound)
	{
	case SPEED_SOUND:
		if(m_pSprintSound) 
			return m_pSprintSound->IsPlaying();
		break;
	default:
		break;
	}
	return false;
}

void CNanoSuit::PlaySound(ENanoSound sound)
{
	if(!GetISystem()->GetISoundSystem())
		return;

	switch(sound)
	{
	case SPEED_SOUND:
		m_pSprintSound = GetISystem()->GetISoundSystem()->LoadSound("Sounds/interface:suit:suit_speed_use",FLAG_SOUND_2D);
		if(m_pSprintSound && !m_pSprintSound->IsPlaying())
			m_pSprintSound->Play();
		break;
	case STRENGTH_SOUND:
		if(!m_pStrengthSound)
			m_pStrengthSound = GetISystem()->GetISoundSystem()->LoadSound("Sounds/interface:suit:suit_strength_use",FLAG_SOUND_2D);
		if(m_pStrengthSound)
			m_pStrengthSound->Play();
		break;
	case MEDICAL_SOUND:
		if(!m_pMedicalSound)
			m_pMedicalSound = GetISystem()->GetISoundSystem()->LoadSound("Sounds/interface:suit:suit_medical_repair",FLAG_SOUND_2D);
		if(m_pMedicalSound)
			m_pMedicalSound->Play();
		break;
	default:
		break;
	}
}

void CNanoSuit::Serialize(TSerialize ser, unsigned aspects)
{
	FUNCTION_PROFILER(GetISystem(), PROFILE_GAME);

	if (ser.GetSerializationTarget() != eST_Network)
	{
		for(int s = 0; s < NANOSLOT_LAST; s++)		//has the name to be serialized??
		{
			ser.Value("nanoSlotDesired", m_slots[s].desiredVal);
			ser.Value("nanoSlotValue", m_slots[s].realVal);
		}
		ser.Value("nanoSuitEnergy", m_energy);
		ser.Value("nanoSuitDeltaEnergy", m_deltaEnergy);
		ser.Value("nanoSuitActive", m_active);
	}
	else 
	{

	}
}