#include "objects.h"
#include <string.h>

/*
   this file contains all the routines that build the object database,
   i.e. the functions that are called by the parser when new objets
   or qualities have been found in the input file.
*/


#define MAXOBJECTS 2000
#define MAXPOINTS   500    /* max. no. of points for one object */

static LOCATION *templist;    /* collect points before object is created */
static int nextpoint = 0;     /* counter for above list */
static char order[5000];      /* used to sort objects */

OBJECT **objectlist;   /* array of pointers to OBJECTs */
int objectno;          /* no. of objects that was created last (-1 if none created yet) */

LOCATION curr_location;          /* current (when reading the world file) location */
double curr_elev = UNKNOWN;      /* current elevation */


typedef struct {     /* used to build alphabetical object index */
  int index;
  char *name;
} TABLEENTRY;

TABLEENTRY *nametable;
int tableentries;
char **namearray;


int db_objects;    /* exported database information */
int db_visible;

/* initialise list of MAXOBJECTS objects, return 0 if successful, else 1 */


void initmapobjects();

int objects_init()
{
  int i;

  initmapobjects();

  templist = (LOCATION *) malloc (MAXPOINTS * sizeof (LOCATION));
  if (!templist)
    return 1;

  db_objects = db_visible = 0;

  objectno = -1;
  objectlist = (OBJECT **) malloc (MAXOBJECTS * sizeof (OBJECT *));

  if (objectlist)
    {
      for (i=0; i<MAXOBJECTS; i++)
	objectlist[i] = NULL;
      return 0;
    }
  else
    return 1;
}



/* sort objects in memory */

int sortcomp (OBJECT **a, OBJECT **b)
{
  return order[(*a)->type] - order[(*b)->type];
}

int compname (TABLEENTRY *a, TABLEENTRY *b)
{
  return strcmp (a->name, b->name);
}



void sort_objects()
{
  int i, j, length;
  char tempstr[100];

  /* build order array for objects */

  for (i=0; i<5000; i++)
    order[i] = 0;

  order[O_CTR] = -60;
  order[O_TOWN] = -50;
  order[O_RIVER] = -40;
  order[O_HIGHWAY] = order[O_ROAD] = -30;
  order[O_CVFR] = -20;
  order[O_VILLAGE] = -10;

  for (i=O_VOR; i<=O_BASIC_RADIO_FACILITY; i++)
    order[i] = 10;
  order[O_WAYPOINT] = 20;
  for (i=O_INTLAIRPORT; i<=O_FREE_BALLON_SITE; i++)
    order[i] = 30;
  
  qsort (objectlist, objectno+1, sizeof (OBJECT *), sortcomp);


  /* this is also the time to build the alphabetical name index */

  tableentries = 0;
  nametable = (TABLEENTRY *) malloc (sizeof (TABLEENTRY) * 2 * db_objects);

  for (i=0; i<db_objects; i++)
    if (objectlist[i]->name)
      if (strlen(objectlist[i]->name))
	if ((objectlist[i]->type < 300) || 
	    (objectlist[i]->type == O_WAYPOINT) ||
	    (objectlist[i]->type == O_LAKE) ||
	    (objectlist[i]->type == O_VILLAGE) ||
	    (objectlist[i]->type == O_TOWN))
	  {

	    if (objectlist[i]->type != O_WAYPOINT)
	      {
		sprintf (tempstr, "%s (%s)", objectlist[i]->name,
			 objecttypestring (objectlist[i]->type));

		nametable[tableentries].name = strdup (tempstr); 
		nametable[tableentries].index = i;

		tableentries++;
	      }
	    else
	      {
		if (objectlist[i]->alias)
		  {
		    sprintf (tempstr, "%s %s", objectlist[i]->name, objectlist[i]->alias);
		    nametable[tableentries].name = strdup (tempstr);
		    nametable[tableentries].index = i;
		    tableentries++;

		    sprintf (tempstr, "%s %s", objectlist[i]->alias, objectlist[i]->name);
		    nametable[tableentries].name = strdup(tempstr);
		    nametable[tableentries].index = i;
		    tableentries++;   
		  }
		else
		  {
		    nametable[tableentries].name = objectlist[i]->name;
		    nametable[tableentries].index = i;

		    tableentries++;
		  }
	      }
	  }

  
  qsort (nametable, tableentries, sizeof (TABLEENTRY), compname);

  /* build array of strings for browser */

  namearray = (char **) malloc ((1+tableentries) * sizeof (char *));

  namearray[0] = "<clear entry>";

  for (i=0; i<tableentries; i++)
    namearray[i+1] = nametable[i].name;

  tableentries++;

  /* convert underscores in names to blanks */

  for (i=0; i<tableentries; i++)
    {
      length = strlen (namearray[i]);
      for (j=0; j<length; j++)
	if (namearray[i][j] == '_')
	  namearray[i][j] = ' ';
    } 
}


/* return pointer to an object by index of string in browser */

OBJECT *objectfromnamelist (int listindex)
{
  if (listindex)
    return objectlist[nametable[listindex-1].index];
  else
    return NULL;
}




/* get object type string from type number */

char *objecttypestring (int objecttype)
{
  static char string[30];

  switch (objecttype)
    {
    case O_INTLAIRPORT: strcpy (string, "International Airport"); break;
    case O_AIRPORT: strcpy (string, "Airport"); break;
    case O_AIRPORT_CIV_MIL: strcpy (string, "Civil/Military Airport"); break;
    case O_AIRPORT_MIL: strcpy (string, "Military Airport"); break; 
    case O_AIRFIELD: strcpy (string, "Public Airfield"); break;
    case O_SPECIAL_AIRFIELD: strcpy (string, "Special Airfield"); break;
    case O_HELIPORT: strcpy (string, "Heliport"); break;
    case O_HELIPORT_AMB: strcpy (string, "Ambulance Heliport"); break;
    case O_GLIDER_SITE: strcpy (string, "Glider Site"); break;
    case O_HANG_GLIDER_SITE: strcpy (string, "Hang Glider Site"); break;
    case O_PARACHUTE_JUMPING_SITE: strcpy (string, "Parachute Site"); break;
    case O_FREE_BALLON_SITE: strcpy (string, "Ballon Site"); break;
    case O_VOR: strcpy (string, "VOR"); break;
    case O_VOR_DME: strcpy (string, "VOR/DME"); break;
    case O_VORTAC: strcpy (string, "VORTAC"); break;
    case O_TACAN: strcpy (string, "TACAN"); break;
    case O_NDB: strcpy (string, "NDB"); break;
    case O_MARKER_BEACON: strcpy (string, "Marker Beacon"); break;
    case O_BASIC_RADIO_FACILITY: strcpy (string, "Radio Facility"); break;
    case O_OBSTRUCTION: strcpy (string, "Obstruction"); break;
    case O_GROUP_OBSTRUCTION: strcpy (string, "Obstructions"); break;
    case O_FIRED_OBSTRUCTION: strcpy (string, "Fired Obstruction"); break;
    case O_FIRED_GROUP_OBSTRUCTION: strcpy (string, "Fired Obstructions"); break;
    case O_AERO_GROUND_LIGHT: strcpy (string, "Ground Light"); break;
    case O_REPORTING_POINT: strcpy (string, "Reporting Point"); break;
    case O_CTR: strcpy (string, "CTR"); break;
    case O_CVFR: strcpy (string, "CVFR"); break;
    case O_RIVER: strcpy (string, "River"); break;
    case O_LAKE: strcpy (string, "Lake"); break;
    case O_HIGHWAY: strcpy (string, "Highway"); break;
    case O_VILLAGE: strcpy (string, "Village"); break;
    case O_TOWN: strcpy (string, "Town"); break;
    case O_WAYPOINT: strcpy (string, "Waypoint"); break;
    default: strcpy (string, "unknown type");
    }

  return string;
}



/* call-back routines for the parser */

void new_location (LOCATION loc)
{
  curr_location = loc;
}


void new_elev (double elev)
{
  curr_elev = elev;
}


void new_object (int objecttype, char *identifier)
{
  int i;

  if (objectno < MAXOBJECTS-1)    /* check if we have a spare pointer */
    {
      objectno++;

      /* allocate memory for new object and see if that was successful... */

      objectlist[objectno] = (OBJECT *) malloc (sizeof(OBJECT));

      if (objectlist[objectno] == NULL)
	{
	  printf ("Out of memory - %s not saved!\n", identifier);
	  objectno--;
	}
      else
	{
	  db_objects = objectno + 1;

	  objectlist[objectno]->type = objecttype;
	  objectlist[objectno]->name = identifier;
	  objectlist[objectno]->msl = curr_elev;   curr_elev = UNKNOWN;
	  objectlist[objectno]->top_msl = curr_elev;
	  objectlist[objectno]->range = UNKNOWN;
	  objectlist[objectno]->location = curr_location;
	  objectlist[objectno]->runways = NULL;
	  objectlist[objectno]->numpoints = 0;
	  objectlist[objectno]->points = NULL;

	  /* check for waiting polygon or list of points */

	  if (nextpoint)
	    {
#define CO objectlist[objectno]
	      CO->topleft = templist[0];
	      CO->bottomright = templist[0];

	      objectlist[objectno]->points = (LOCATION *) malloc (nextpoint * sizeof (LOCATION));
	      objectlist[objectno]->numpoints = nextpoint;
	      
	      for (i=0; i<nextpoint; i++)   /* copy points from templist to object */
		{
		  objectlist[objectno]->points[i] = templist[i];

		  /* get bounding rectangle */

		  if (CO->topleft.latitude < templist[i].latitude)
		    CO->topleft.latitude = templist[i].latitude;

		  if (CO->topleft.longitude > templist[i].longitude)
		    CO->topleft.longitude = templist[i].longitude;

		  if (CO->bottomright.latitude > templist[i].latitude)
		    CO->bottomright.latitude = templist[i].latitude;

		  if (CO->bottomright.longitude < templist[i].longitude)
		    CO->bottomright.longitude = templist[i].longitude;

		}

	      nextpoint = 0;      /* delete temporary list */
	    }
	}

    }
  else
    printf ("Too many objects - %s not saved!\n", identifier);
}


void add_point (LOCATION point)
{
  if (nextpoint < MAXPOINTS-1)
    {
      templist[nextpoint] = point;
      nextpoint++;
    }
}


void set_frequency (double freq)
{
  objectlist[objectno]->frequency = freq;
}


void set_alias (char *name)
{
  objectlist[objectno]->alias = name;
}


void set_topmsl (double height)
{
  objectlist[objectno]->top_msl = height;
}


void set_range (double range)
{
  objectlist[objectno]->range = range;
}


void add_runway (int direction, int length, char surface)
{
  RUNWAYDEF *next_rwy, *tmp;

  next_rwy = (RUNWAYDEF *) malloc (sizeof(RUNWAYDEF));

  if (!next_rwy)    /* not enough memory */
    puts ("Out of memory.");
  else
    {
      tmp = objectlist[objectno]->runways;

      if (!tmp)    /* first object? */
	objectlist[objectno]->runways = next_rwy;
      else
	{
	  while (tmp->next)
	    tmp = (RUNWAYDEF *) tmp->next;      /* go to end of list */

	  tmp->next = next_rwy;
	}

      next_rwy->direction = direction;
      next_rwy->length = length;
      next_rwy->surface = surface;

      next_rwy->next = NULL;   /* mark end of list */
    }

}













