#include "../include/zf.h"

struct ZfLevel
{
  char* name;
    char* skybox_filename;
    char* heightmap_filename;
    char* flux_filename;
    char* hives_filename;
    char* wasps_filename;
    char* hexfluxfields_filename;
    char* fluxrings_filename;
    char* batteryrings_filename;
    char* tierrings_filename;
    char* drones_filename;
    char* droids_filename;
    char* eels_filename;
    char* hudmessages_filename;
    char* landscape_filename;
    char* boss_filename;
    char* leeches_filename;
};

static void
write(FILE* stream, ZfLevel* level)
{
    /* to do */
    /* this current HACK! assumes that the images are saved already */
    fprintf(stream, "ZfLevel\n{\n");
    
    fprintf(stream, "name = %s\n",
            level->name);
    fprintf(stream, "skybox_filename = %s\n",
            level->skybox_filename);
    fprintf(stream, "heightmap_filename = %s\n",
            level->heightmap_filename);
    fprintf(stream, "flux_filename = %s\n",
            level->flux_filename);
    fprintf(stream, "hives_filename = %s\n",
            level->hives_filename);
    fprintf(stream, "wasps_filename = %s\n",
            level->wasps_filename);
    fprintf(stream, "hexfluxfields_filename = %s\n",
            level->hexfluxfields_filename);
    fprintf(stream, "fluxrings_filename = %s\n",
            level->fluxrings_filename);
    fprintf(stream, "batteryrings_filename = %s\n",
            level->batteryrings_filename);
    fprintf(stream, "tierrings_filename = %s\n",
            level->tierrings_filename);
    fprintf(stream, "drones_filename = %s\n",
            level->drones_filename);
    fprintf(stream, "droids_filename = %s\n",
            level->droids_filename);
    fprintf(stream, "eels_filename = %s\n",
            level->eels_filename);
    fprintf(stream, "hudmessages_filename = %s\n",
            level->hudmessages_filename);
    fprintf(stream, "landscape_filename = %s\n",
            level->landscape_filename);
    fprintf(stream, "boss_filename = %s\n",
	    level->boss_filename);
    fprintf(stream, "leeches_filename = %s\n",
	    level->leeches_filename);

    fprintf(stream, "}\n");
}

/*!
  \todo landscape_filename is not read correctly
*/
static void
read(ZfLevel* level, FILE* stream)
{
    char buffer[FILENAME_STRING_LENGTH];

    fscanf(stream, "ZfLevel\n{\n");

    /* read name */
    fscanf(stream, "name = %s\n",
            &buffer);
    level->name = strdup(buffer);

    /* read skybox filename */
    fscanf(stream, "skybox_filename = %s\n",
            &buffer);
    level->skybox_filename = strdup(buffer);
    //printf("level->skybox_filename = %s\n", level->skybox_filename);

    /* read heightmap filename */
    fscanf(stream, "heightmap_filename = %s\n",
            &buffer);
    level->heightmap_filename = strdup(buffer);
    //printf("level->heightmap_filename = %s\n", level->heightmap_filename);

    /* read flux filename */
    fscanf(stream, "flux_filename = %s\n",
	   &buffer);
    level->flux_filename = strdup(buffer);
    //printf("level->flux_filename = %s\n", level->flux_filename);

    /* hives */
    fscanf(stream, "hives_filename = %s\n",
            &buffer);
    level->hives_filename = strdup(buffer);
    //printf("level->hives_filename = %s\n", level->hives_filename);

    /* wasps */
    fscanf(stream, "wasps_filename = %s\n",
            &buffer);
    level->wasps_filename = strdup(buffer);
    //printf("level->wasps_filename = %s\n", level->wasps_filename);
    
    /* hex flux fields */
    fscanf(stream, "hexfluxfields_filename = %s\n",
            &buffer);
    level->hexfluxfields_filename = strdup(buffer);
    //printf("level->hexfluxfields_filename = %s\n", level->hexfluxfields_filename);

    /* flux rings */
    fscanf(stream, "fluxrings_filename = %s\n",
            &buffer);
    level->fluxrings_filename = strdup(buffer);
    //printf("level->fluxrings_filename = %s\n", level->fluxrings_filename);

    /* battery rings */
    fscanf(stream, "batteryrings_filename = %s\n",
            &buffer);
    level->batteryrings_filename = strdup(buffer);
    //printf("level->batteryrings_filename = %s\n", level->batteryrings_filename);

    /* tierrings */
    fscanf(stream, "tierrings_filename = %s\n",
            &buffer);
    level->tierrings_filename = strdup(buffer);
    //printf("level->tierrings_filename = %s\n", level->tierrings_filename);

    /* get drones filename */
    fscanf(stream, "drones_filename = %s\n",
            &buffer);
    level->drones_filename = strdup(buffer);
    //printf("level->drones_filename = %s\n", level->drones_filename);

    /* get droids filename */
    fscanf(stream, "droids_filename = %s\n",
            &buffer);
    level->droids_filename = strdup(buffer);
    //printf("level->droids_filename = %s\n", level->droids_filename);

    /* get eels filename */
    fscanf(stream, "eels_filename = %s\n",
            &buffer);
    level->eels_filename = strdup(buffer);
    //printf("level->eels_filename = %s\n", level->eels_filename);

    /* get hudmessages filename */
    fscanf(stream, "hudmessages_filename = %s\n",
            &buffer);
    level->hudmessages_filename = strdup(buffer);
    //printf("level->hudmessages_filename = %s\n", level->hudmessages_filename);
    
    /* get landscape filename */
    fscanf(stream, "landscape_filename = %s\n",
            &buffer);
    level->landscape_filename = strdup(buffer);
    //printf("level->landscape_filename = %s\n", level->landscape_filename);

    /* get boss filename */
    fscanf(stream, "boss_filename = %s\n",
            &buffer);
    level->boss_filename = strdup(buffer);
    //printf("level->boss_filename = %s\n", level->boss_filename);

    /* get leeches filename */
    fscanf(stream, "leeches_filename = %s\n",
            &buffer);
    level->leeches_filename = strdup(buffer);
    //printf("level->leeches_filename = %s\n", level->leeches_filename);

    fscanf(stream, "}\n");
}

ZfLevel*
zf_level_new(void)
{
    return g_new(ZfLevel, 1);
}

void
zf_level_close(ZfLevel* level)
{    
    g_free(level);
}

/*!
  \brief Writes a level.zf file using the supplied information. Information
  required are texture filename, colours filename and detail_texture_filename.
  Box is generated automatically. Level is written to a file specified by
  output_filename.
*/
void
zf_level_write_file(ZfLevel* level, char* output_filename)
{
    FILE* fp;
    
    printf("%s() : START\n", __FUNCTION__);

    fp = fopen(output_filename, "w");

    write(fp, level);

    printf("%s() : END\n", __FUNCTION__);    
}

ZfLevel*
zf_level_read_file(char* input_filename)
{
    FILE* fp;
    ZfLevel* level;

    //printf("%s() : START\n", __FUNCTION__);

    /* create a level */
    level = zf_level_new();

    /* open the filename for reading */
    fp = fopen(input_filename, "r");

    /* read data from file */
    read(level, fp);

    /* close the file */
    fclose(fp);

    //printf("%s() : END\n", __FUNCTION__);

    return level;
}

/*!
  \todo Incomplete!
*/
void
zf_level_print(ZfLevel* level)
{
    FILE* fp;

    fp = fopen("stdout", "w");

    write(fp, level);

    fclose(fp);
}

static char** add_name(unsigned int num_names, char** old_names, char* new_name)
{
    unsigned int i;
    char**       new_names;

    //printf("%s() : START : num_names = %u\n", __FUNCTION__, num_names);

    /* create new array */
    new_names = (char**) malloc ((num_names + 1) * sizeof(char*));

    /* copy old names t new array */
    for (i = 0 ; i < num_names ; i++)
    {
	new_names[i] = old_names[i];
    }

    /* add new name to array */
    new_names[num_names] = new_name;

    /* free old_names */
    if (old_names)
	free(old_names);

    return new_names;
}

/*!
  \todo Return values rather than print out. Must malloc the char**.
*/
char** zf_level_search_directory(unsigned int* num_filenames, char* directory)
{
    DIR*           dir;
    struct dirent* ent;
    char*          extension;
    char**         levels = 0;

    /*
    printf("%s() : searching for levels in %s\n",
	   __FUNCTION__,
	   directory);
    */

    /* get directory */
    dir = opendir(directory);

    /* check correct load */
    if(!dir)
    {
	fprintf(stderr,
		"%s() : ERROR : couldn't open directory %s\n",
		__FUNCTION__,
		directory);
	/* what to do? */
	return NULL;
    }
    
    /* print filenames with extension .zfl */
    while((ent = readdir(dir)) != NULL)
    {
	/* check each filename for trailing full stop */
	extension = strrchr(ent->d_name, '.');
	
	/* if full stop not found, discard */
	if (!extension)
	    continue;
	
	if (strcmp(extension, ".zfl") == 0)
	{
	    /* print it */
	    //puts(ent->d_name);

	    /* add to array */
	    //printf("%s() : adding %s to array\n", __FUNCTION__, ent->d_name);
	    levels = add_name(*num_filenames, levels, strdup(ent->d_name));
	    //printf("done\n");
	    //printf("old num = %u\n", *num_filenames);
	    *num_filenames = *num_filenames + 1;
	    //printf("new num = %u\n", *num_filenames);
	}
    }
    
    return levels;
}

/*!
  \todo All loads should check that the filename is not NULL

  \todo Small wierdness with water and boss_target, are these hacks?
*/

void zf_level_load(ZfLevel* level)
{
    zf_animation_system_init();
    zf_collision_system_init();
    
    zf_render_system_init();
    zf_trigger_system_init();
    zf_particle_system_init();

    zf_audio_init();

    zf_skybox_init(level->skybox_filename);
    zf_camera_init();
    zf_heightmap_init(level->heightmap_filename);  /* water is init-ed inside this*/

    zf_flux_init(level->flux_filename);

    zf_ship_init();    

    zf_weapon_control_init();
    zf_laser_init();
    zf_missile_init();
     
    zf_tritor_init();

    zf_bomb_init();
    zf_explosion_init();
    zf_shield_init();
    zf_debris_init();

    zf_hive_init(level->hives_filename);
    zf_leech_init(level->leeches_filename);

    zf_hexfluxfield_init(level->hexfluxfields_filename);
    zf_flux_ring_init(level->fluxrings_filename);
    zf_battery_ring_init(level->batteryrings_filename);
    zf_tier_ring_init(level->tierrings_filename);
    
    zf_drone_init(level->drones_filename);
    zf_drone_pickup_init();

    zf_droid_missile_init();       
    zf_droid_init(level->droids_filename);
    zf_eel_segment_init(level->eels_filename);
    zf_enemy_missile_init();
    
    zf_hud_init(level->hudmessages_filename);
    zf_cross_hair_init();

    /* landscape filename */
    if (level->landscape_filename)
	zf_landscape_object_init(level->landscape_filename);


    zf_score_indicator_init();

    zf_boss_target_init(); /* no file needed, as boss file will store it - MUST BE BEFORE boss_init()*/
    zf_boss_init(level->boss_filename);

}

#if 1
/*!
  \todo set funcs should free old string if it exists.
*/
/*SET*/
void zf_level_set_skybox_file       (ZfLevel* level, char* filename)
{
    level->skybox_filename = strdup(filename);
}

void zf_level_set_heightmap_file    (ZfLevel* level, char* filename)
{
    level->heightmap_filename = strdup(filename);
}

void zf_level_set_flux_file         (ZfLevel* level, char* filename)
{
    level->flux_filename = strdup(filename);
}

void zf_level_set_hives_file        (ZfLevel* level, char* filename)
{
    level->hives_filename = strdup(filename);
}

void zf_level_set_wasps_file        (ZfLevel* level, char* filename)
{
    level->wasps_filename = strdup(filename);
}

void zf_level_set_hexfluxfields_file(ZfLevel* level, char* filename)
{
    level->hexfluxfields_filename = strdup(filename);
}

void zf_level_set_fluxrings_file    (ZfLevel* level, char* filename)
{
    level->fluxrings_filename = strdup(filename);
}

void zf_level_set_batteryrings_file (ZfLevel* level, char* filename)
{
    level->batteryrings_filename = strdup(filename);
}

void zf_level_set_tierrings_file    (ZfLevel* level, char* filename)
{
    level->tierrings_filename = strdup(filename);
}

void zf_level_set_drones_file       (ZfLevel* level, char* filename)
{
    level->drones_filename = strdup(filename);
}

void zf_level_set_droids_file       (ZfLevel* level, char* filename)
{
    level->droids_filename = strdup(filename);
}

void zf_level_set_eels_file         (ZfLevel* level, char* filename)
{
    level->eels_filename = strdup(filename);
}

void zf_level_set_hudmessages_file  (ZfLevel* level, char* filename)
{
    level->hudmessages_filename = strdup(filename);
}

void zf_level_set_landscape_file    (ZfLevel* level, char* filename)
{
    level->landscape_filename = strdup(filename);
}

void zf_level_set_boss_file          (ZfLevel* level, char* filename)
{
    level->boss_filename = strdup(filename);
}

void zf_level_set_leeches_file       (ZfLevel* level, char* filename)
{
    level->leeches_filename = strdup(filename);
}

/*GET*/

char* zf_level_get_skybox_file       (ZfLevel* level)
{
    return level->skybox_filename;
}

char* zf_level_get_heightmap_file    (ZfLevel* level)
{
    return level->heightmap_filename;
}

char* zf_level_get_flux_file         (ZfLevel* level)
{
    return level->flux_filename;
}

char* zf_level_get_hives_file        (ZfLevel* level)
{
    return level->hives_filename;
}

char* zf_level_get_wasps_file        (ZfLevel* level)
{
    return level->wasps_filename;
}

char* zf_level_get_hexfluxfields_file(ZfLevel* level)
{
    return level->hexfluxfields_filename;
}

char* zf_level_get_fluxrings_file    (ZfLevel* level)
{
    return level->fluxrings_filename;
}

char* zf_level_get_batteryrings_file (ZfLevel* level)
{
    return level->batteryrings_filename;
}

char* zf_level_get_tierrings_file    (ZfLevel* level)
{
    return level->tierrings_filename;
}

char* zf_level_get_drones_file       (ZfLevel* level)
{
    return level->drones_filename;
}

char* zf_level_get_droids_file       (ZfLevel* level)
{
    return level->droids_filename;
}

char* zf_level_get_eels_file         (ZfLevel* level)
{
    return level->eels_filename;
}

char* zf_level_get_hudmessages_file  (ZfLevel* level)
{
    return level->hudmessages_filename;
}

char* zf_level_get_landscape_file    (ZfLevel* level)
{
    return level->landscape_filename;
}

char* zf_level_get_boss_file         (ZfLevel* level)
{
    return level->boss_filename;
}

char* zf_level_get_leeches_file      (ZfLevel* level)
{
    return level->leeches_filename;
}
#endif

void zf_level_get_level_name_from_file(char* name, char* filename)
{
#if 1
    FILE*    fp;
    ZfLevel* level;
    char     buffer[FILENAME_STRING_LENGTH];
    char     full_filename[FILENAME_STRING_LENGTH];

    //printf("%s() : START\n", __FUNCTION__);

    /* create the full filename */
    sprintf(full_filename, "../data/level/");
    strcat(full_filename, filename);

    /* open the filename for reading */
    fp = fopen(full_filename, "r");

    /* read data from file */
    fscanf(fp, "ZfLevel\n{\n");

    /* read name */
    fscanf(fp, "name = %s\n",
	   &buffer);
    //printf("%s() : got name %s\n", __FUNCTION__, buffer);
    strncpy(name, buffer, FILENAME_STRING_LENGTH);    

    /* close the file */
    fclose(fp);

    //printf("%s() : END\n", __FUNCTION__);
#else
    strncpy(name, "test name", FILENAME_STRING_LENGTH);
#endif
}
