/* all-units.m,
 *
 * This contains a list of the units for use in the map editor and
 * when loading/saving maps.
 */

#include <allegro.h>
#include <assert.h>
#include "common.h"
#include "debug.inc"
#include "units/all-units.h"
#include "units/all-units.inc"


#define MAX_AIR_UNITS		36
#define MAX_GROUND_UNITS	23


typedef struct {
    BOOL loaded, required;
} data_helper_t;


static data_helper_t air_data[MAX_AIR_UNITS];
static data_helper_t ground_data[MAX_GROUND_UNITS];


unsigned int total_air_classes, total_ground_classes;
Class air_units_table[MAX_AIR_UNITS];
Class ground_units_table[MAX_GROUND_UNITS];

/*--------------------------------------------------------------*/
/* Datafiles.							*/
/*--------------------------------------------------------------*/

BOOL load_unit_data_for(Class class, BOOL air)
{
    int i, end;
    Class *classes;
    data_helper_t *data_table;

    if (air) {
	end = total_air_classes;
	classes = air_units_table;
	data_table = air_data;
    }
    else {
	end = total_ground_classes;
	classes = ground_units_table;
	data_table = ground_data;
    }

    for (i = 0; i < end; i++)
	if (class == classes[i])
	    break;

    data_table[i].required = YES;

    if (not [classes[i] loadPrerequisites])
	return NO;

    if (not data_table[i].loaded) {
	if (not (data_table[i].loaded = [classes[i] loadData]))
	    fprintf(stderr, "Error loading %s datafiles.\n", [classes[i] name]);
    }

    return data_table[i].loaded;
}

static void unload_unnecessary_unit_data_in_list(Class list[], data_helper_t data[], unsigned int n)
{
    while (n > 0) {
	n--;

	if (data[n].loaded && not data[n].required) {
#ifdef DEBUG_LOG_SHUTDOWN_UNITS
	    printf("Shutting down %s.\n", [list[n] name]);
#endif
	    [list[n] shutdown];
	    data[n].loaded = NO;
	}
    }
}

void unload_unnecessary_unit_data(void)
{
    unload_unnecessary_unit_data_in_list(air_units_table, air_data, total_air_classes);
    unload_unnecessary_unit_data_in_list(ground_units_table, ground_data, total_ground_classes);
}

void mark_all_unit_data_unnecessary(void)
{
    unsigned int i;

    for (i = 0; i < total_air_classes; i++)
	air_data[i].required = NO;

    for (i = 0; i < total_ground_classes; i++)
	ground_data[i].required = NO;
}

/*--------------------------------------------------------------*/

static Class find_class_by_name_in_list(const char *name, Class list[], unsigned int n)
{
    while (n > 0) {
	n--;
	if (streq(name, [list[n] name]))
	    return list[n];
    }

    return nil;
}

Class find_class_by_name(const char *name, BOOL air)
{
    if (air)
	return find_class_by_name_in_list(name, air_units_table, total_air_classes);
    else
	return find_class_by_name_in_list(name, ground_units_table, total_ground_classes);
}

/*--------------------------------------------------------------*/

static void add_unit(Class *table, unsigned int *num_classes, unsigned int max, Class c)
{
    assert(*num_classes+1 < max);
    table[*num_classes] = c;
    (*num_classes)++;
}

void make_all_units_tables(void)
{
#define ADD_AIR_UNIT(u)		add_unit(air_units_table, &total_air_classes, MAX_AIR_UNITS, [u class])
#define ADD_GROUND_UNIT(u)	add_unit(ground_units_table, &total_ground_classes, MAX_GROUND_UNITS, [u class])

    /* We don't want units to register themselves so we can keep the
       ordering for REdit. */

    /*========== AIR UNITS ==========*/
    /* Big Burgers. */
    ADD_AIR_UNIT(BabyBoy);
    ADD_AIR_UNIT(Challenger);

    /* Brutus's Legion. */
    ADD_AIR_UNIT(Deceiver);
    ADD_AIR_UNIT(Schemer);

    /* Cargo. */
    ADD_AIR_UNIT(Cargo);
    ADD_AIR_UNIT(CargoHealth);

    /* Fire Brand. */
    ADD_AIR_UNIT(FireFlea);
    ADD_AIR_UNIT(FireFly);
    ADD_AIR_UNIT(FireFox);

    /* Insecticons. */
    ADD_AIR_UNIT(Mozzie);
    ADD_AIR_UNIT(DragonFly);
    ADD_GROUND_UNIT(MozzieHatch);

    /* IX. */
    ADD_AIR_UNIT(LittleDeath);
    ADD_AIR_UNIT(Fear);

    /* Laserjets. */
    ADD_AIR_UNIT(Battler);
    ADD_AIR_UNIT(Conquerer);
    ADD_AIR_UNIT(BattleCruiser);

    /* Nostalgic Collection. */
    ADD_AIR_UNIT(Kamikaze);
    ADD_AIR_UNIT(KamikazeCenter);
    ADD_AIR_UNIT(KamikazeCharger);
    ADD_AIR_UNIT(KamikazeHook);
    ADD_AIR_UNIT(Bug);
    ADD_AIR_UNIT(Cruiser);

    /* Something. */
    ADD_AIR_UNIT(Stumpy);
    ADD_AIR_UNIT(Stubby);
    ADD_AIR_UNIT(MsHoover);

    /* Spacers. */
    ADD_AIR_UNIT(Grunt);
    ADD_AIR_UNIT(Moan);

    ADD_AIR_UNIT(Centipede);
    ADD_AIR_UNIT(Strumble);
    ADD_AIR_UNIT(Lint);
    ADD_AIR_UNIT(LintReverse);
    ADD_AIR_UNIT(HunterSeeker);

    /*========== GROUND UNITS ==========*/
    /* Baleog's Turrets. */
    ADD_GROUND_UNIT(Stone);
    ADD_GROUND_UNIT(Viking);
    ADD_GROUND_UNIT(Anvil);

    /* Captain LeChimp. */
    ADD_GROUND_UNIT(SeaCucumber);
    ADD_GROUND_UNIT(SeaDog);
    ADD_GROUND_UNIT(SeaDogSweeper);
    ADD_GROUND_UNIT(SeaUrchin);

    /* Lizards. */
    ADD_GROUND_UNIT(Newt);
    ADD_GROUND_UNIT(Gecko);
    ADD_GROUND_UNIT(Lizard);

    /* L'odeur Animale. */
    ADD_GROUND_UNIT(Armadillo);
    ADD_GROUND_UNIT(ArmadilloHatch);
    ADD_GROUND_UNIT(Hippo);
    ADD_GROUND_UNIT(HippoHatch);
    ADD_GROUND_UNIT(Elephant);
    ADD_GROUND_UNIT(ElephantReverse);

    /* Space Turrets. */
    ADD_GROUND_UNIT(Tripe);
    ADD_GROUND_UNIT(Hunter);

    ADD_GROUND_UNIT(Basturk);
    ADD_GROUND_UNIT(Hatch);


    /*========== BOSSES ==========*/
    ADD_GROUND_UNIT(MiniBoss0);
    ADD_AIR_UNIT(MiniBoss1);
    ADD_AIR_UNIT(Boss0);
    ADD_AIR_UNIT(Boss1);

    /*========== You aren't supposed to use these ==========*/
    /*
      ADD_AIR_UNIT(Unit);
      ADD_AIR_UNIT(BasicFlyer);
      ADD_AIR_UNIT(BasicFollower);
      ADD_GROUND_UNIT(BasicTank);
      ADD_GROUND_UNIT(BasicTurret);
    */

#undef ADD_GROUND_UNIT
#undef ADD_AIR_UNIT
}

void shutdown_special_units(void)
{
    /* XXX?  Special stuff. */
    [Player shutdown];
    [Robot shutdown];
    [Satellite shutdown];
}
