/*
===========================================================================
Copyright (C) 2015 the OpenMoHAA team

This file is part of OpenMoHAA source code.

OpenMoHAA source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.

OpenMoHAA source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
===========================================================================
*/

// lodthing.cpp : Level of detail manager

#include "lodthing.h"
#include "player.h"
#include "scriptexception.h"

Event EV_LODTool_Spawn
(
	"lod_spawn",
	EV_CONSOLE,
	"s",
	"model",
	"Edit LOD on the specified model"
);
Event EV_LODTool_Think
(
	"lod_think",
	EV_DEFAULT,
	NULL,
	NULL,
	"Called every frame to process the view thing."
);
Event EV_LODTool_SetModel
(
	"lod_model",
	EV_DEFAULT,
	NULL,
	NULL,
	"Set the model of the current viewthing"
);
Event EV_LODTool_SetYaw
(
	"lod_yaw",
	EV_CONSOLE,
	"f",
	"yaw",
	"Set the yaw of the model"
);
Event EV_LODTool_SetRoll
(
	"lod_roll",
	EV_CONSOLE,
	"f",
	"roll",
	"Set the roll of the model"
);
Event EV_LODTool_SetAngles
(
	"lod_angles",
	EV_CONSOLE,
	"f[0,360]f[0,360]f[0,360]",
	"pitch yaw roll",
	"Set the angles of the model"
);
Event EV_LODTool_Discard
(
	"lod_discard",
	EV_CONSOLE,
	NULL,
	NULL,
	"Discard LOD changes"
);

LODMaster LODModel;

CLASS_DECLARATION( Listener, LODMaster, "lodmaster" )
{
	{ &EV_LODTool_Spawn,			&LODMaster::Spawn },
	{ &EV_LODTool_SetYaw,			&LODMaster::PassEvent },
	{ &EV_LODTool_SetRoll,			&LODMaster::PassEvent },
	{ &EV_LODTool_SetAngles,		&LODMaster::PassEvent },
	{ &EV_LODTool_Discard,			&LODMaster::PassEvent },
	{ NULL, NULL }
};

void LODMaster::Init
	(
	void
	)
{
	gi.AddCommand( "lod_spawn", NULL );
	gi.AddCommand( "lod_yaw", NULL );
	gi.AddCommand( "lod_pitch", NULL );
	gi.AddCommand( "lod_roll", NULL );
	gi.AddCommand( "lod_angles", NULL );
	gi.AddCommand( "lod_discard", NULL );
}

void LODMaster::Spawn
	(
	Event *ev
	)
{
	const char *mdl;
	Vector forward, up, delta;
	Entity *ent;
	LODSlave *m_lodmodel;

	mdl = ev->GetString( 1 );

	if( !mdl || !*mdl )
	{
		ScriptError( "Must specify a model name" );
	}

	gi.cvar_set( "lod_tikiname", mdl );
	gi.cvar_set( "lod_tool", "1" );

	ent = g_entities->entity;
    if (!ent) {
        return;
    }

	if( ent->IsSubclassOfPlayer() )
	{
		( ( Player* )ent )->SetFov( 80 );
		ent->setOriginEvent( Vector( 2000, 0, 0 ) );
	}

	if( m_current )
	{
		m_current->PostEvent( EV_Remove, 0 );
	}

	m_lodmodel = new LODSlave;
	m_current = m_lodmodel;

	ent->angles.AngleVectorsLeft( &forward, NULL, &up );

	m_lodmodel->m_baseorigin = Vector( -1600, 0, 0 );
	m_lodmodel->setOrigin( m_lodmodel->m_baseorigin );
	m_lodmodel->m_baseorigin = m_lodmodel->origin;

	delta = Vector( "1 0 0" );
	delta.toAngles();

	m_lodmodel->setAngles( delta );
	m_lodmodel->setScale( 1.0f );

	Event *event = new Event( EV_LODTool_SetModel );

	event->AddString( mdl );
	m_lodmodel->ProcessEvent( event );

	if( !m_lodmodel->edict->tiki )
	{
		m_current = NULL;

		ScriptError( "Error in model '%s', LOD model not spawned.", mdl );
	}

	for( int i = 0; i < MAX_FRAMEINFOS; i++ )
	{
		m_lodmodel->Pause( i );
	}

	gi.SendConsoleCommand( "cg_drawvidemodel 0\n" );
	gi.SendConsoleCommand( "cg_shadows 0\n" );
	gi.SendConsoleCommand( "ui_compass 0\n" );
	gi.SendConsoleCommand( "r_fastsky 1\n" );
	gi.SendConsoleCommand( "r_drawworld 0\n" );
}

void LODMaster::PassEvent
	(
	Event *ev
	)
{
	if( !m_current )
	{
		ScriptError( "No LOD Model" );
	}

	m_current->ProcessEvent(*ev);
}

CLASS_DECLARATION( Animate, LODSlave, "lodslave" )
{
	{ &EV_LODTool_Think,		&LODSlave::ThinkEvent },
	{ &EV_LODTool_SetModel,		&LODSlave::SetModelEvent },
	{ &EV_LODTool_Discard,		&LODSlave::Delete },
	{ NULL, NULL }
};

void LODSlave::UpdateCvars
	(
	qboolean quiet,
	qboolean updateFrame
	)
{

}

LODSlave::LODSlave
	(
	void
	)
{
	m_baseorigin = origin;
	LODModel.m_current = this;

	edict->s.eType = ET_MODELANIM_SKEL;
	edict->s.renderfx |= RF_SHADOW;
	edict->s.renderfx |= RF_ADDITIVE_DLIGHT;

	PostEvent( EV_LODTool_Think, level.frametime );
}

static float lod_yaw = 0.0f;

void LODSlave::ThinkEvent
	(
	Event *ev
	)
{
	cvar_t *cvar;
	Entity *ent;
	Vector position;

	PostEvent( EV_LODTool_Think, level.frametime );

	lod_yaw += 2.0f;
	if( lod_yaw > 180.0f ) {
		lod_yaw = lod_yaw - 360.0f;
	}

	cvar = gi.Cvar_Get( "lod_pitch_val", "", 0 );

	angles[ 0 ] = cvar->value;
	angles[ 1 ] = lod_yaw;

	setAngles( angles );

	ent = g_entities->entity;
	if( ent->IsSubclassOfPlayer() )
	{
		( ( Player * )ent )->SetFov( 80.0 );
		ent->setOrigin( Vector( -4000, 0, 0 ) );
	}

	cvar = gi.Cvar_Get( "lod_position", "", 0 );
	sscanf( cvar->string, "%f %f %f", &position[ 0 ], &position[ 1 ], &position[ 2 ] );

	cvar = gi.Cvar_Get( "lod_zee_val", "", 0 );
	position[ 2 ] -= cvar->value;

	setOrigin( position );
}

void LODSlave::SetModelEvent
	(
	Event *ev
	)
{
	str modelname = ev->GetString( 1 );

	setModel( modelname );

	if( edict->tiki )
	{
		NewAnim( "idle" );
		SetFrame();
	}
}

void LODSlave::Delete
	(
	Event *ev
	)
{
	ScriptError( "DELETE" );
}
