/*
 *  acm : an aerial combat simulator for X
 *  Copyright (C) 1991-1998  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 <string.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include "box.h"
#include "damage.h"
#include "dis_if.h"
#include "drone.h"
#include "inventory.h"
#include "joystick.h"
#include "pm.h"
#include "render.h"

#define browse_IMPORT
#include "browse.h"

#define MAX_MAPPED_STRING_LEN	20
#define MAX_POPUP_STRING_LEN	40

#define REF_X		-1.3
#define REF_Y		-1.1


/*  There's a bug lurking here, but for now ... */

#ifdef WINNT
#define SCALE_1		5.0
#else
#define SCALE_1		7.0
#endif

struct _dis_browse {
	char  info[32];
	dis_if_Entity  *p;
	craftType *cinfo;   /* craftType iff this an aircraft we can grab */
};

#define BROWSE_MAX 256
#define ITEM_LIMIT 5
#define LINE_SPACING 0.2

static struct _dis_browse browse_info[BROWSE_MAX];
static int bcount;

/*
 *  Generate the stealth browsing table from the current DIS
 *  entity database
 */

static void
buildBrowseInfoTable ()
{
	abort();
#ifdef xxxxxxxxxxxxxxxxxxxxxxxx
	dis_if_Entity * e = dis_if_getEntityTable(), *ep;
	long etop = dis_if_getEntityTop();
	int i=0;
	craftType * cinfo;
	char *marker;

	ep = e;
	bcount = 0;

	/*
	 *  Update the list of entities we might be interested in following
	 */

	for (i = 0; i <= etop && bcount < BROWSE_MAX; ++i, ++ep) {
		if (ep->entityType.kind == DISKindPlatform &&
			ep->entityType.domain == DISDomainAir) {
			browse_info[bcount].p = ep;

			/*
			 *  Was this an aircraft type defined in the inventory file?
			 *  If so, mark it as "flyable".
			 */

			cinfo = inventory_craftTypeSearchByEntityType( &ep->entityType );
			if (cinfo && cinfo->CLift) {
				browse_info[bcount].cinfo = cinfo;
				marker = "* ";
			}
			else {
				browse_info[bcount].cinfo = NULL;
				marker = "  ";
			}

			sprintf (browse_info[bcount].info, "%s%d,%d,%d",
					 marker,
					 ep->entityId.sim_id.site_id, 
					 ep->entityId.sim_id.application_id,
					 ep->entityId.entity_id
					 );
			++ bcount;
		}
	}
#endif
}

#ifdef XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
/*
 *  Display the stealth browser page in the MFD
 */

void
browse_page(craft * c, viewer * u)
{
	XSegment  seg[2048], m_seg[256];
	char      buf[256];
	int       slot_size, m_i = 0, i = 0, xc, yc, h, x, y;
	int       item_count;
	static    Alib_ZInfo z, zm;
	double    yy;


	if (c->radarMode != RM_DIS_BROWSE)
		return;

	z.depth = --u->v->w->depth;
	z.color = (Alib_Pixel) (u->v->w->pixel[panelBackgroundColor]);
	zm.depth = z.depth;
	zm.color = (Alib_Pixel) (u->v->w->pixel[magentaColor]);
	Alib_fillRectangle(u->v->w, &u->indicator, &z);

	slot_size = RectWidth(u->indicator);
	xc = u->indicator.a.x + (slot_size + 1) / 2;
	yc = u->indicator.a.y + (slot_size + 1) / 2;

	yy = 0.0;

	h = (int) (11.0 * u->xscaleFactor + 0.5);
	y = (int) ((REF_Y + yy) * u->v->Scale.y / (SCALE_1 * 4));

	/*
	 *  Update the list of entities we might be interested in following
	 */

	buildBrowseInfoTable ();

	/*
	 *  display current DIS entity browsing page
	 */

	item_count = 0;
	for (i=u->browseBase; 
		 i<bcount && item_count<ITEM_LIMIT; 
		 ++i, ++item_count) {
		memory_strcpy(buf, sizeof(buf), browse_info[i].info);
		x = (int) (REF_X * u->v->Scale.x / (SCALE_1 * 4));
		y = (int) ((REF_Y + yy) * u->v->Scale.y / (SCALE_1 * 4));
		if (u->browseSelectedItem == i) {
			VDrawStrokeString(u->v, x + xc, y + yc,
							  buf,
							  strlen(buf), h, zm.color);
		}
		else {
			VDrawStrokeString(u->v, x + xc, y + yc,
							  buf,
							  strlen(buf), h, z.color);
		}
		yy += LINE_SPACING;
	}

	VSetClipRect(u->v, &u->indicator);

	VDrawSegments(u->v, m_seg, m_i, 
				  (Alib_Pixel) (u->v->w->pixel[magentaColor]));

	VDrawSegments(u->v, seg, i, 
				  (Alib_Pixel) (u->v->w->pixel[HUDPixel]));

	return;
}
#endif /* XXXXXXXXXXXXXXXXXX */

int
browse_controlRequestCallback( dis_pdu *pdu, void *pu )
{
	abort();
#ifdef xxxxxxxxxxxxxxxxxxxxxxxxxxxx
	viewer *u = (viewer *) pu;
	dis_if_Entity *e, *ep;
	dis_simulation_addr my_addr;
	dis_entity_id new_entity_id;
	disx_ApplicationInfo *app;
	craft *c;

	if ( pdu->hdr.pdu_type == PDUTypeAcknowledge &&
		 pdu->acknowledge.resp_flag == 1) {

	/*
	 * "take over the craft"
	 *
	 * alter the viewer entry to reflect that we've hijacked an aircraft
	 *
	 * alter the ptbl (craft) entry to reflect that this is now an aircraft
	 * that we are responsible for modeling
	 */

		u->viewer_state = ViewerStateNormal;
		c = u->watchedCraft;
		u->watchedCraft = u->c;
		u->c = c;

		c->type = CT_PLANE;
		c->vl = u;

		c->radarMode = RM_STANDBY;

		/*
		 *  Until we can think of a better way to set fuel state,
		 *  damage bits, etc. this will have to suffice.
		 */

		(*c->cinfo->resupply) (c);

		/* FIXME: array 'entities' does not exist anymore */
		ep = &entities[c->disId];

		ep->entryType = dis_if_LOCAL;

		app = dis_if_getApplicationInfo();
		disx_getSimulationAddress ( app, &my_addr );

		/* SITE ID */

		if ((transferEntityIdBits & 0x4)) {
			new_entity_id.sim_id.site_id = my_addr.site_id;
		}
		else {
			new_entity_id.sim_id.site_id = 
				ep->entityId.sim_id.site_id;
		}

		/* APPLICATION ID */

		if ((transferEntityIdBits & 0x2)) {
			new_entity_id.sim_id.application_id = my_addr.application_id;
		}
		else {
			new_entity_id.sim_id.application_id = 
				ep->entityId.sim_id.application_id;
		}

		/* ENTITY ID */

		if ((transferEntityIdBits & 0x1)) {

			/*  Issue a new entity id (good within this application) */

			dis_entity_id temp_id;

			disx_issueEntityID( app, &temp_id );
			new_entity_id.entity_id = temp_id.entity_id;
		}
		else {

			/* use existing entity ID */
			new_entity_id.entity_id = ep->entityId.entity_id;
		}

		/* TODO: check for collisions in entity table if mode wasn't 0, or 7 */
		ep->entityId = new_entity_id;

	}

	/*
     *  Transfer Control Request was rejected.  Return to stealth state.
     */

	else {
		u->viewer_state = ViewerStatePiggyback;
		XBell( u->dpy, 50 );
	}

	return 0;
#endif
}


int
browse_stealthCraft( craft *c, viewer *u, int item, int take_control)
{
	int i;

	/*
	 *  Locate the browse info entry that corresponds to the
	 *  designated craft.
	 */

	if ( item == -1 ) {

		buildBrowseInfoTable ();

		for(i=0; i<bcount; ++i) {
			if (browse_info[i].p->c == c) {
				item = i;
				break;
			}
		}
	}

	/* follow that aircraft */
	if ( item != -1 ) {
		u->browseSelectedItem = item;
	}
	else {
		u->browseSelectedItem = -1;
	}

	if ( end_game_mode && take_control && item != -1 ) {
		browse_info[item].p->c->flags |= FL_END_GAME_DRONE;
		u->viewer_state = ViewerStateControlPending;
		drone_endGameDistanceCheck(browse_info[item].p->c, u);
	}
	else {
		u->viewer_state = ViewerStatePiggyback;
	}
	u->watchedCraft = c;

	return 0;
}

#ifdef XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
int
browse_keyEvent(craft * c, viewer * u, XEvent * ev, int player)
{

	KeySym    keysym;
	XComposeStatus compose;
	char      buffer[MAX_MAPPED_STRING_LEN];
	int       buflen = MAX_MAPPED_STRING_LEN;

	(void) XLookupString((XKeyEvent *) ev, buffer, buflen,
						 &keysym, &compose);

	if (player) {

		switch (keysym) {

#ifdef sun
		case XK_R7:
#else
		case XK_Home:
#endif

			break;

		case XK_Prior:
			u->browseBase -= ITEM_LIMIT;
			if (u->browseBase < 0) {
				u->browseBase = 0;
				XBell ( u->dpy, 50 );
			}
			break;

		case XK_Next:
			u->browseBase += ITEM_LIMIT;
			if (u->browseBase >= bcount) {
				u->browseBase = bcount - ITEM_LIMIT + 1;
			}
			if (u->browseBase < 0) {
				u->browseBase = 0;
				XBell ( u->dpy, 50 );
			}
			break;

#ifdef sun
		case XK_Up:
#else
		case XK_KP_8:
#endif
			render_setOutsideView(c, u, render_VIEW_FORWARD);
			break;

/* look right */

#ifdef sun
		case XK_Right:
#else
		case XK_KP_6:
#endif
			render_setOutsideView(c, u, render_VIEW_RIGHT);
			break;

/* look left */

#ifdef sun
		case XK_Left:
#else
		case XK_KP_4:
#endif
			render_setOutsideView(c, u, render_VIEW_LEFT);
			break;

/* look back */

#ifdef sun
		case XK_Down:
#else
		case XK_KP_2:
#endif
			render_setOutsideView(c, u, render_VIEW_AFT);
			break;

/* look up */

#ifdef sun
		case XK_R11:
#else
		case XK_KP_5:
#endif
			render_setOutsideView(c, u, render_VIEW_UP);
			break;

		case XK_N:
		case XK_n:
			c->flags ^= FL_CHASE_VIEW;
			break;

#ifdef SPECIAL_KEYS

		case XK_o:
			if (! damage_absorbDamage(c, 3) == 0) {
				c->kill(c, "You asked to absorb some damage. The aircraft was destroyed. No further details are available.");
				return -1;
			}
			break;


		case XK_semicolon:
			debug ^= 1;
			break;

#endif

		case XK_P:
		case XK_p:
			c->kill(c, "(FIXME)");
			return -1;
/*NOTREACHED */ break;

		case XK_braceleft:
			box_startRecording();
			break;

		case XK_braceright:
			box_endRecording();
			break;

		case XK_bracketleft:
			box_startPlayback();
			break;

		case XK_k:
		case XK_K:
			joystick_calibrate();
			break;

		}

	}
	return 0;
}
#endif /* XXXXXXXXXXXX */


void
browse_selectCockpitItem( craft *c, 
				   viewer *u, 
				   int x, 
				   int y, 
				   unsigned long time
				   )
{
	double dy, yscale;
	int slot_size, item;
	int yc;

	slot_size = RectWidth(u->indicator);
	yc = u->indicator.a.y + (slot_size + 1) / 2;

	yscale = (int) (u->v->Scale.y / (SCALE_1 * 4));

	if (c->radarMode != RM_DIS_BROWSE) {
		return;
	}

	/*
	 * Click on radar set?
	 */

	if (x > u->indicator.a.x && x < u->indicator.a.x + slot_size &&
		y > u->indicator.a.y && y < u->indicator.a.y + slot_size) {

		/* get index of selected item */

		dy = (y - yc) / yscale;
		dy -= REF_Y;
		item = (int) ( dy / LINE_SPACING ) + u->browseBase;

		if (item < bcount && item >= 0) {

			/*
			 *  Double-Click?  Activate control request
			 */

			if (u->browseSelectedItem == item &&
				time - u->browseClickTime < 500) {

				/*
				 * We can only take control of aircraft that we have a
				 * definition for.  When that's the case for a given
				 * entity, cinfo will be non-NULL.
				 */

				if (browse_info[item].cinfo) {

					/*
					 * If we're in end-game mode, check for hostile
					 * aircraft in our proximity.  Calling 
					 * drone_endGameDistanceCheck once will cause it to be called
					 * once per second.
					 */

					u->viewer_state = ViewerStateControlPending;

					if ( end_game_mode ) {
						 browse_info[item].p->c->flags |= FL_END_GAME_DRONE;
						 drone_endGameDistanceCheck(browse_info[item].p->c, u);
					}
					else {
						dis_if_requestControl ( browse_info[item].p,
								browse_controlRequestCallback, u );
					}
				}
				else {
					//XBell( u->dpy, 50 );
				}

			}
			else {

				browse_stealthCraft ( browse_info[item].p->c, u, item, 0 );

			}
		}

	}

	u->browseClickTime = time;
}