// ObjectRev.cpp: implementation of the CObjectRev class.
//
//////////////////////////////////////////////////////////////////////

#include "ObjectRev.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

LINK_ENTITY_TO_CLASS ( object_rev, CObjectRev);

CObjectRev::CObjectRev()
{

}

void CObjectRev::Spawn()
{
	Precache( );
	char* thismodel;
	switch (type)
	{
	default:
	case TYPE_EDIT: thismodel = "models/rev/w_edit.mdl"; break;
	case TYPE_ADD: thismodel = "models/rev/w_add.mdl"; break;
	case TYPE_DEL: thismodel = "models/rev/w_delete.mdl"; break;
	case TYPE_INTEG: thismodel = "models/rev/w_integ.mdl"; break;
	case TYPE_BRANCH: thismodel = "models/rev/w_add.mdl"; break;
	}

	from = NULL;

	SET_MODEL( ENT(pev), thismodel);
	
	UTIL_SetOrigin( pev, pev->origin );
	target = (Vector)pev->origin;  //by default, we're already where we want to be.

	UTIL_SetSize( pev, Vector(-2.5, -2.5, -2.5), Vector( 2.5, 2.5, 2.5) );  //collision box!

	pev->movetype = MOVETYPE_FLY;
	pev->solid = SOLID_BBOX; 

	SetThink( Think );
	SetTouch( Touch );

	pev->nextthink = gpGlobals->time + 0.5;
}

void CObjectRev::Precache()
{
	PRECACHE_MODEL( "models/rev/w_edit.mdl" );
	PRECACHE_MODEL( "models/rev/w_add.mdl" );
	PRECACHE_MODEL( "models/rev/w_delete.mdl" );
	PRECACHE_MODEL( "models/rev/w_integ.mdl" );
	BeamSprite = PRECACHE_MODEL( "sprites/smoke.spr" ); 
}

void CObjectRev :: Think( void )
{
/*
	if (!IsInWorld())
	{
		parent->disown( this );
		UTIL_Remove( this );
		return;
	}
	Commenting this out because there might be "from" records pointing to this.  Screw it.  Generating
	"object fell out of level" errors is better than segfaulting.  If it ever needs to be fixed, then it can
	be done by making the "from" relationship doubly-linked, but I don't have the energy right now.
*/  
	if (UTIL_VecUpdate( &(pev->origin), target )) {
		pev->nextthink = gpGlobals->time + 0.05;
		UTIL_SetSize( pev, Vector(-2.5, -2.5, -2.5), Vector( 2.5, 2.5, 2.5) );  //collision box!
	}
	else 
	{
		pev->nextthink = gpGlobals->time + 0.5;
		if (from != NULL)
		{
			MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, from->pev->origin);

			WRITE_BYTE( TE_BEAMENTPOINT ); 
			WRITE_SHORT( entindex() ); 
			WRITE_COORD( from->pev->origin.x ); 
			WRITE_COORD( from->pev->origin.y ); 
			WRITE_COORD( from->pev->origin.z ); 
			WRITE_SHORT( BeamSprite ); // Beam sprite index. 
			WRITE_BYTE( 0 ); // Starting frame 
			WRITE_BYTE( 0 ); // Framerate 
			WRITE_BYTE( 10 ); // How long the beam stays on. 
			WRITE_BYTE( 4 ); //width
			WRITE_BYTE( 0 ); // Noise 
			WRITE_BYTE( red ); //red
			WRITE_BYTE( green ); 
			WRITE_BYTE( blue ); 
			WRITE_BYTE( bright ); 
			WRITE_BYTE( 0 ); // Speed, sort of.

			MESSAGE_END( );

		}
		if (next != NULL)
		{
			MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, next->pev->origin);

			WRITE_BYTE( TE_BEAMENTPOINT ); 
			WRITE_SHORT( entindex() ); 
			WRITE_COORD( next->pev->origin.x ); 
			WRITE_COORD( next->pev->origin.y ); 
			WRITE_COORD( next->pev->origin.z ); 
			WRITE_SHORT( BeamSprite ); // Beam sprite index. 
			WRITE_BYTE( 0 ); // Starting frame 
			WRITE_BYTE( 0 ); // Framerate 
			WRITE_BYTE( 5 ); // How long the beam stays on. 
			WRITE_BYTE( 4 ); //width
			WRITE_BYTE( 0 ); // Noise 
			WRITE_BYTE( 128 ); //red
			WRITE_BYTE( 128 ); 
			WRITE_BYTE( 128 ); 
			WRITE_BYTE( 128 ); 
			WRITE_BYTE( 0 ); // Speed, sort of.

			MESSAGE_END( );
		}
	}
}

void CObjectRev :: Touch( CBaseEntity* Thing )
{ 
	CBasePlayer *pl;
	CBaseEntity *be = CBaseEntity::Instance(Thing->pev->owner);

	if (Thing->IsPlayer()) pl = (CBasePlayer*) Thing;
	else if (be->IsPlayer()) pl = (CBasePlayer*) be;
	else return;

	if (Thing->IsLong()) {
		Long( pl );
		pl->m_flNextP4Time = gpGlobals->time + 0.5;
		return;
	}

	if (Thing->IsExpand()) {
		Expand( pl );
		pl->m_flNextP4Time = gpGlobals->time + 0.5;
		return;
	}

	if (pl->m_flNextP4Time > gpGlobals->time) return;
	pl->m_flNextP4Time = gpGlobals->time + 0.2;
	UTIL_PrintHud(pl, filerev.Text());
}

void CObjectRev::Long( CBasePlayer* pl )
{
	ClientLuser ui;
	ClientApi client;
	Error e;
	StrBuf msg = StrBuf();

	client.Init( &e );
	if (e.GetSeverity()) {
		e.Fmt(&msg);
		UTIL_FatalHud(pl, msg.Text());
		pl->m_flNextP4Time = gpGlobals->time + 20.0; //20 second delay on connect error
		return;
	}
	
	char* args[1];
	args[0] = filerev.Text();

	client.SetArgv(1, args);
	client.Run( "filelog", &ui );

	client.Final( &e );
	if (e.GetSeverity()) {
		e.Fmt(&msg);
		UTIL_WarningHud(pl, msg.Text());
	}

	UTIL_PrintHud( pl, ui.message.Text());
}

void CObjectRev::Expand( CBasePlayer* pl )
{
	ClientLuser ui;
	ClientApi client;
	Error e;
	StrBuf msg = StrBuf();

	client.Init( &e );
	if (e.GetSeverity()) {
		e.Fmt(&msg);
		UTIL_FatalHud(pl, msg.Text());
		pl->m_flNextP4Time = gpGlobals->time + 20.0; //20 second delay on connect error
		return;
	}
	
	char* args[2];
	args[0] = "-q";
	args[1] = filerev.Text();

	client.SetArgv(2, args);
	client.Run( "print", &ui );

	client.Final( &e );
	if (e.GetSeverity()) {
		e.Fmt(&msg);
		UTIL_WarningHud(pl, msg.Text());
	}

	UTIL_PrintHud( pl, ui.message.Text());
}