#include "MW4Headers.hpp"

#include "AI_HitTesting.hpp"
#include <Adept\Map.hpp>
#include <Adept\CollisionGrid.hpp>
#include "MWMover.hpp"
#include "aiutils.hpp"
#include "Weapon.hpp"
#include "ProjectileWeapon.hpp"
#include "Vehicle.hpp"
#include "MWDamageObject.hpp"
#include "AI_FireData.hpp"
#include "SubsystemClassData.hpp"


using namespace Stuff;
using namespace MW4AI;
using namespace MechWarrior4;

const Stuff::Scalar line_exaggeration = 20.0f;



std::pair<MW4AI::FireData,Stuff::Time> MW4AI::CalculateFireData(const FireParamPackage& fire_params,
																MechWarrior4::Weapon& weapon)
{
	Verify(&fire_params != 0);
	Check_Object(&weapon);

	Stuff::Time missile_lock_time(0);
	Stuff::Vector3D velocity(0,0,0);

	if (weapon.IsDerivedFrom(ProjectileWeapon::DefaultData) == true)
	{
		ProjectileWeapon* projectile_weapon = Cast_Object(ProjectileWeapon*,&weapon);
		Check_Object(projectile_weapon);
		const ProjectileWeapon__GameModel* game_model = projectile_weapon->GetGameModel();

		if (game_model != 0)
		{
			if (fire_params.who_to_hit != 0)
			{
				missile_lock_time = game_model->targetLockTime * 2;
			}

			velocity = game_model->initialLinearVelocity;
		}
	}

	if (fire_params.vehicle_shooting_at == 0)
	{
		FireData new_fire_data(fire_params.fire_data);
		std::pair<FireData,Stuff::Time> rv(new_fire_data,missile_lock_time);
		rv.first.GetQuery().m_raySource = const_cast<Adept::Entity*>(fire_params.who_to_hit);

		return (rv);
	}

	Check_Object(fire_params.vehicle_shooting_at);

	Vehicle* v = (Vehicle*)fire_params.vehicle_shooting_at;	// must cast away constness since GetLocalToWorld() is not const
	Stuff::Point3D current_position(v->GetLocalToWorld());

	Stuff::Point3D new_position;
	Stuff::Time time;

	if (Small_Enough(velocity))
	{
		time = fire_params.frame_delay;
	}
	else
	{
		v->EstimateFuturePosition(&new_position,(Scalar)fire_params.frame_delay,false);

		time = fire_params.frame_delay +
			   (GetApproximateLength(new_position,current_position) / velocity.GetApproximateLength());
	}

	v->EstimateFuturePosition(&new_position,(Scalar)time);


	Stuff::Point3D delta;
	delta.Subtract(new_position,current_position);

	Stuff::Point3D target_point(fire_params.fire_data.GetDest());
	target_point += delta;

	FireData new_fire_data(fire_params.fire_data.GetSource(),
						   fire_params.fire_data.GetOrigin(),
						   target_point);

	new_fire_data.SetLineLength(new_fire_data.GetLine().m_length + line_exaggeration);

	std::pair<FireData,Stuff::Time> rv(new_fire_data,missile_lock_time);
	rv.first.GetQuery().m_raySource = const_cast<Adept::Entity*>(fire_params.who_to_hit);
	return (rv);
}
