/*
 *  acm : an aerial combat simulator for X
 *  Copyright (C) 1991-1994,1997  Riley Rainey
 *
 *  This program 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; version 2 dated June, 1991.
 *
 *  This program 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 this program;  if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA.
 */

#include <math.h>
#include <stdio.h>
#include <string.h>
#include "pm.h"
#include "init.h"
#include "inventory.h"
#include "missile.h"
#include "../util/memory.h"
#include "weapon.h"
#include "sounds.h"
#include "gear.h"

#define aim9m_IMPORT
#include "aim9m.h"

static int select_aim9m(craft *);
static int display_aim9m(craft *, craftType *, viewer *, int, int);
static int update_aim9m(craft *);
static int fire_aim9m(craft *);

static weapon_Type aim9mDesc =
{
	select_aim9m,				/* select */
	update_aim9m,				/* update */
	display_aim9m,				/* display procedure */
	fire_aim9m,					/* fire */
	(int (*)(craft *)) NULL,	/* fire button release */
};

static int hasFired[manifest_MAXPLAYERS];
static int count[manifest_MAXPLAYERS];

/*
 *  AIM-9M selection function
 *
 *  A selection function normally determines whether there are any weapons
 *  of this type on-board.  If so, and the weapon system is functional
 *  (in other words, undamaged) then return 1; otherwise return 0.
 */

static int
select_aim9m(craft * c)
{
	hasFired[c->pIndex] = 0;
	count[c->pIndex] = weapon_countOrdinance(c, weapon_AIM9M);
	return 1;
}

static int
update_aim9m(craft * c)
{
	int i;

	if( ! hasFired[c->pIndex] )
		return 1;
	
	hasFired[c->pIndex] = 0;  /* reset fire request */

	/*
	 *  Missile won't fire if we have "Weight on wheels"
	 *  or if we run out of ammunition.
	 */

	if( gear_someWheelGroundContact(c)
	|| count[c->pIndex] <= 0 )
		return 1;

	/* Get station from which to launch the missile: */
	i = weapon_getReadyStation(c, weapon_AIM9M);
	if (i < 0){
		fprintf(stderr, "Oops. Can't find an AIM-9\n");
		return 1;
	}

	/*
	 *  Decrement missiles counter.
	 *  In arcade mode, we never run out of ammunition
	 */

	if (arcadeMode == 0) {
		c->station[i].id = -1;
		count[c->pIndex]--;
	}

	/* Launch missile from station i: */
	missile_fire(c, i);
	sounds_playSound(c, sounds_MissileLaunch, FALSE);

	return 1;
}

static int
fire_aim9m(craft * c)
{
	hasFired[c->pIndex] = 1;
	return 1;
}

/*
 *  AIM-9M display function
 *
 *  Update the HUD display strings associated with this weapon system.
 *  c = the aircraft.
 *  w = the missile's description record.
 *  dummy1, dummy2 = ignored, not set.
 *
 *  This code may be called by drones, so the viewer may be NULL.
 *
 *  Return a nonzero value if have a reasonable chance of scoring a kill.
 */

static int
display_aim9m(craft * c, craftType * w, viewer * unused, int dummy1, int dummy2)
{

	char      s[16];
	double    d, a1, v, r, root1, root2, n, t;
	VPoint    tmp;
	int       target;

	sprintf(s, "%d %s", count[c->pIndex], weapon_idToName(weapon_AIM9M));
	strcpy(c->leftHUD[3], s);

/*
 *  Compute time to target t. Gives < 0.0 if no target available or not
 *  reachable.
 */

	v = VMagnitude(&c->Cg);
	a1 = (w->maxThrust - 0.5 * c->air.rho * w->CDOrigin * v * v)
		/ (w->emptyWeight + w->maxFuel) * units_earth_g;

	if (c->curRadarTarget >= 0 && a1 >= 0.0) {

		d = c->targetDistance;
		r = c->targetClosure;

		n = r * r + 2.0 * a1 * d;
		if (n > 0) {
			n = sqrt(n);
			root1 = (-r + n) / a1;
			root2 = (-r - n) / a1;
			if (root1 >= 0.0)
				if (root2 >= 0.0)
					if (root1 < root2)
						t = root1;
					else
						t = root2;
				else
					t = root1;
			else if (root2 >= 0.0)
				t = root2;
			else
				t = -1.0;
		}
		else
			t = -1.0;
	}

	else
		t = -1.0;

/*
 *  See if the missiles can lock onto any target.  We'll constrain missile_getIRTarget()
 *  so that it will only select target's in a twenty degree boresight cone.
 */

	if (count[c->pIndex] > 0) {
		target = missile_getIRTarget(c, &tmp, 0.17633);
	}
	else {
		target = -1;
	}

/*
 *  Update HUD display strings.
 */

	if (t < 0.0)
		sprintf(s, "ARM      --");
	else if (target >= 0 && t >= (w->armDelay + 0.5) && t <= 15.0)
		sprintf(s, "LOCKED   %d", (int) (t + 0.5));
	else if (t <= 15.0)
		sprintf(s, "IN RANGE %d", (int) (t + 0.5));
	else
		sprintf(s, "ARM      %d", (int) (t + 0.5));
	
	strcpy(c->leftHUD[2], s);

	strcpy(c->leftHUD[4], "");

/*
 *  Return TRUE if we are recommending a missile shot.
 */

	return target >= 0 && t >= (w->armDelay + 0.5) && t <= 10.0;
}


weapon_Type *
aim9m_new(void)
{
	craftType *c;
	FILE     *f;
	dis_entity_type em1 =
	{2, 1, 225, 1, 1, 3, 0};
	dis_entity_type em2 =
	{2, 1, 222, 1, 2, 1, 0};

	c = inventory_craftTypeNew(NULL);
	c->name = memory_strdup( weapon_idToName(weapon_AIM9M) );

	c->entityType = em1;
	c->altEntityType = em2;

	aim9mDesc.w = c;

	c->CDOrigin = 0.04;			/* 5" radius of body */
	c->CDFactor = -2.56694;

	c->CDBOrigin = 0.0;
	c->CDBFactor = 0.0;

	VIdentMatrix(&(c->I));
	c->I.m[0][0] = 0.0;
	c->I.m[1][1] = 0.0;
	c->I.m[2][2] = 0.0;
	c->cmSlope = -1.88;

	c->wingS = 1.0;

/*
 *  Assume 150.0 lb of weight is fuel and that it burns for about 4 seconds.
 *  That yields a fuel burn rate of 40 lb/s.
 */

	c->emptyWeight = 90.0;
	c->maxFuel = 100.0;
	c->maxThrust = 4000.0;
	c->spFuelConsump = 40;

/*
 *  Three second arming delay
 */

	c->armDelay = 1.0;

	f = init_fopen("missiles/aim9.obv", "r");
	c->object = VReadObject(f);
	fclose(f);

	return &aim9mDesc;
}
