#include "dlls/extdll.h"
#include "dlls/util.h"
#include "dlls/cbase.h"
#include "dlls/saverestore.h"
#include "dlls/func_break.h"
#include "dlls/decals.h"
#include "dlls/explode.h"
#include "mod/AvHSpecials.h"
#include "mod/AvHPushableBuildable.h"
#include "mod/AvHSharedUtil.h"

char *AvHPushableBuildable :: m_soundNames[3] = { "debris/pushbox1.wav", "debris/pushbox2.wav", "debris/pushbox3.wav" };

AvHPushableBuildable::AvHPushableBuildable(AvHTechID inTechID, AvHMessageID inMessageID, char* inClassName, int inUser3) : AvHBaseBuildable(inTechID, inMessageID, inClassName, inUser3)
{
	this->m_lastSound = 0;
	this->m_maxSpeed = 0;
	this->m_soundTime = 0;
}

void AvHPushableBuildable::SetConstructionComplete()
{
	AvHBaseBuildable::SetConstructionComplete();

//	if ( pev->spawnflags & SF_PUSH_BREAKABLE )
//		AvHBaseBuildable::Spawn();
//	else
//		Precache( );

	//pev->movetype	= MOVETYPE_PUSHSTEP;
	this->pev->movetype = MOVETYPE_TOSS;
	pev->solid		= SOLID_BBOX;
	//SET_MODEL( ENT(pev), STRING(pev->model) );
	SET_MODEL( ENT(pev), this->GetModelName());

	Vector theMinSize, theMaxSize;
	AvHSHUGetSizeForTech(this->GetMessageID(), theMinSize, theMaxSize);
	UTIL_SetSize(this->pev, theMinSize, theMaxSize); 

	if ( pev->friction > 399 )
		pev->friction = 399;

	m_maxSpeed = 100;//400 - pev->friction;
	SetBits( pev->flags, FL_FLOAT );
	pev->friction = 0;
	
	pev->origin.z += 1;	// Pick up off of the floor
	UTIL_SetOrigin( pev, pev->origin );

	// Multiply by area of the box's cross-section (assume 1000 units^3 standard volume)
	pev->skin = ( pev->skin * (pev->maxs.x - pev->mins.x) * (pev->maxs.y - pev->mins.y) ) * 0.0005;
	m_soundTime = 0;
}

float AvHPushableBuildable::GetMaxSpeed(void)
{ 
	return m_maxSpeed; 
}

void AvHPushableBuildable :: Precache( void )
{
	AvHBaseBuildable::Precache();

	for ( int i = 0; i < 3; i++ )
	{
		PRECACHE_UNMODIFIED_SOUND( m_soundNames[i] );
	}

	//if ( pev->spawnflags & SF_PUSH_BREAKABLE )
	//	AvHBaseBuildable::Precache( );
}


void AvHPushableBuildable :: KeyValue( KeyValueData *pkvd )
{
	if ( FStrEq(pkvd->szKeyName, "size") )
	{
		int bbox = atoi(pkvd->szValue);
		pkvd->fHandled = TRUE;

		switch( bbox )
		{
		case 0:	// Point
			UTIL_SetSize(pev, Vector(-8, -8, -8), Vector(8, 8, 8));
			break;

		case 2: // Big Hull!?!?	!!!BUGBUG Figure out what this hull really is
			UTIL_SetSize(pev, VEC_DUCK_HULL_MIN*2, VEC_DUCK_HULL_MAX*2);
			break;

		case 3: // Player duck
			UTIL_SetSize(pev, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX);
			break;

		default:
		case 1: // Player
			UTIL_SetSize(pev, VEC_HULL_MIN, VEC_HULL_MAX);
			break;
		}

	}
	else if ( FStrEq(pkvd->szKeyName, "buoyancy") )
	{
		pev->skin = atof(pkvd->szValue);
		pkvd->fHandled = TRUE;
	}
	else
	{
		AvHBaseBuildable::KeyValue( pkvd );
	}
}


// Pull the func_pushable
void AvHPushableBuildable :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
	if(!this->GetIsBuilt())
	{
		AvHBaseBuildable::Use(pActivator, pCaller, useType, value);
	}
	else
	{
		if ( !pActivator || !pActivator->IsPlayer() )
		{
			if ( pev->spawnflags & SF_PUSH_BREAKABLE )
				this->AvHBaseBuildable::Use( pActivator, pCaller, useType, value );
			return;
		}
		
		if ( pActivator->pev->velocity != g_vecZero )
			Move( pActivator, 0 );
	}
}


void AvHPushableBuildable :: Touch( CBaseEntity *pOther )
{
	if ( FClassnameIs( pOther->pev, "worldspawn" ) )
		return;

	Move( pOther, 1 );
}


void AvHPushableBuildable :: Move( CBaseEntity *pOther, int push )
{
	entvars_t*	pevToucher = pOther->pev;
	int playerTouch = 0;

	// Is entity standing on this pushable ?
	if ( FBitSet(pevToucher->flags,FL_ONGROUND) && pevToucher->groundentity && VARS(pevToucher->groundentity) == pev )
	{
		// Only push if floating
		if ( pev->waterlevel > 0 )
			pev->velocity.z += pevToucher->velocity.z * 0.1;

		return;
	}


	if ( pOther->IsPlayer() )
	{
		if ( push && !(pevToucher->button & (IN_FORWARD|IN_USE)) )	// Don't push unless the player is pushing forward and NOT use (pull)
			return;
		playerTouch = 1;
	}

	float factor;

	if ( playerTouch )
	{
		if ( !(pevToucher->flags & FL_ONGROUND) )	// Don't push away from jumping/falling players unless in water
		{
			if ( pev->waterlevel < 1 )
				return;
			else 
				factor = 0.1;
		}
		else
			factor = 1;
	}
	else 
		factor = 0.25;

	// temporarily increase height to allow it over bumps, but only if it's not on the ground already
	if(FBitSet(this->pev->flags, FL_ONGROUND))
	{
		this->pev->origin.z += 10;
	}
	else
	{
		int a = 0;
	}

	pev->velocity.x += pevToucher->velocity.x * factor;
	pev->velocity.y += pevToucher->velocity.y * factor;

	float length = sqrt( pev->velocity.x * pev->velocity.x + pev->velocity.y * pev->velocity.y );
	if ( push && (length > GetMaxSpeed()) )
	{
		pev->velocity.x = (pev->velocity.x * GetMaxSpeed() / length );
		pev->velocity.y = (pev->velocity.y * GetMaxSpeed() / length );
	}
	if ( playerTouch )
	{
		pevToucher->velocity.x = pev->velocity.x;
		pevToucher->velocity.y = pev->velocity.y;
		if ( (gpGlobals->time - m_soundTime) > 0.7 )
		{
			m_soundTime = gpGlobals->time;
			if ( length > 0 && FBitSet(pev->flags,FL_ONGROUND) )
			{
				m_lastSound = RANDOM_LONG(0,2);
				EMIT_SOUND(ENT(pev), CHAN_WEAPON, m_soundNames[m_lastSound], 0.5, ATTN_NORM);
	//			SetThink( StopSound );
	//			pev->nextthink = pev->ltime + 0.1;
			}
			else
				STOP_SOUND( ENT(pev), CHAN_WEAPON, m_soundNames[m_lastSound] );
		}
	}
}

#if 0
void AvHPushableBuildable::StopSound( void )
{
	Vector dist = pev->oldorigin - pev->origin;
	if ( dist.Length() <= 0 )
		STOP_SOUND( ENT(pev), CHAN_WEAPON, m_soundNames[m_lastSound] );
}
#endif