/* world.c
 *
 * Represents a map.
 *
 * (c) 2006, Joseph Curtis
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "display.h"
#include "world.h"
#include "player.h"
#include "input.h"

#ifndef x86
#include <pspdebug.h>
//#define printf pspDebugScreenPrintf
#endif



/* The default world */
struct world *default_world;

struct world *create_world() {
  struct world *w;

  printf("create_world:\n");

  w = calloc(1, sizeof(struct world));

#ifndef x86
  w->graphics = loadImage("images/SCENERYC.png");
  if(w->graphics == NULL)
    printf("Failed to load scenery.\n");
  w->army_graphics = loadImage("images/ARMIESC.png");
  if(w->army_graphics == NULL)
    printf("Failed to load army graphics.\n");
  w->font = loadImage("images/FANTS.png");
  if (w->font == NULL)
    printf("Failed to load font graphics.\n");
  w->graphics2 = loadImage("images/avatars.png");
  if (w->graphics2 == NULL)
    printf("Failed to load more graphics.\n");
  
#endif
#ifdef x86
  SDL_Surface *tmp;

  tmp = IMG_Load("images/SCENERYC.png");
  w->graphics = SDL_DisplayFormat(tmp);
  SDL_FreeSurface(tmp);

  tmp = IMG_Load("images/ARMIESC.png");
  w->army_graphics = SDL_DisplayFormat(tmp);
  SDL_FreeSurface(tmp);

  tmp = IMG_Load("images/FANTS.png");
  w->font = SDL_DisplayFormat(tmp);
  SDL_FreeSurface(tmp);

  tmp = IMG_Load("images/avatars.png");
  w->graphics2 = SDL_DisplayFormat(tmp);
  SDL_FreeSurface(tmp);

#endif

  w->num_players = NUM_PLAYERS;

  return w;
}


int destroy_world(struct world *w) {
  free(w->map);
  free(w->towns);
  free(w->armies);
#ifndef x86
  free(w->graphics);
  free(w->army_graphics);
  free(w->font);
#endif
  free(w);
  return 1;
}


// TODO: error checking here and below

int save_world(struct world *w, char * file) {
  FILE *f;

  f = fopen(file, "w");

  if(f == NULL)
    return (int)NULL;

  /* write the eight ints */
  fwrite(w, sizeof(int), 8, f);

 /* write the command */
  fwrite(w->command, sizeof(char), 1, f);

  /* write the name */
  fwrite(w->name, sizeof(char), WORLD_NAME_LENGTH, f);

  /* write the cells */
  fwrite(w->map, sizeof(struct cell), w->width*w->height, f);
  /* write the towns */
  fwrite(w->towns, sizeof(struct town), w->num_towns, f);
  /* write the armies */
  fwrite(w->armies, sizeof(struct army_group), w->num_armies, f);
  /* write the players */
  fwrite(w->players, sizeof(struct player), w->num_players, f);

  return 1;
}


int load_world(struct world *w, char *file) {
 FILE *f;

 f = fopen(file, "r");
 
 if(f == NULL)
   return NULL;

 w = realloc(w, sizeof(struct world));
 printf("realloc'ed world\n");

 /* read the eight ints */
 fread(w, sizeof(int), 8, f);
 printf("read six ints, %d, %d, %d, %d, %d, %d\n", w->width, w->height,
	w->num_towns, w->num_armies, w->vis_x, w->vis_y);

 /* read the command */
 fread(w->command, sizeof(char), 1, f);

 /* read the name */
 fread(w->name, sizeof(char), WORLD_NAME_LENGTH, f);
 printf("read the name: %s\n", w->name);

 w->map = realloc(w->map, sizeof(struct cell) * w->width * w->height);
 printf("realloc'ed map\n");
 /* read the cells */

 printf("read %d cells\n",  fread(w->map, sizeof(struct cell), w->width*w->height, f));

 w->towns = realloc(w->towns, sizeof(struct town) * w->num_towns);
 // printf("realloc'ed the towns\n");
 /* read the towns */

 printf("read %d towns\n",  fread(w->towns, sizeof(struct town), w->num_towns, f));

 w->armies = realloc(w->armies, sizeof(struct army_group) * w->num_armies);
 // printf("realloc'ed the armies\n");
 /* read the armies */

 printf("read %d armies\n",  fread(w->armies, sizeof(struct army_group), w->num_armies, f));

 w->players = realloc(w->players, sizeof(struct player) * w->num_players);
  /* read the players */
  fread(w->players, sizeof(struct player), w->num_players, f);
 return 1;
}

int load_world_text(struct world *w, char *file) {
  FILE *f;
  int i, j;

  printf("load_world_text:\n");
  
  f = fopen(file, "r");

  if (f == NULL)
    return (int)NULL;

   w = realloc(w, sizeof(struct world));
   
   /* read the first line */
   fscanf(f, "%d %d %d %d %d %d %d %d %d %s\n", &(w->width), &(w->height),
	  &(w->num_towns), &(w->num_armies), &(w->num_players), &(w->vis_x),
	  &(w->vis_y), &(w->turn), &(w->command), w->name);

   printf("Read first line\n");

   w->map = realloc(w->map, sizeof(struct cell) * w->width * w->height);
   w->towns = realloc(w->towns, sizeof(struct town) * w->num_towns);
   w->armies = realloc(w->armies, sizeof(struct army_group) * w->num_armies);
   w->players = realloc(w->players, sizeof(struct player) * w->num_players);
 
   printf("Realloced\n");

   for (j=0;j<w->height;j++) {
     for (i=0;i<w->width;i++) {
       fscanf(f, "%d ", &(w->map[I(i, j, w->width)].image));
     }
   }

   printf("Read cells\n");

   for (i=0;i<w->num_towns;i++) {
     printf("About to read town %d\n", i);
     
     fscanf(f, "%s %d %d %d %d %d %d %d\n", w->towns[i].name, &(w->towns[i].x),
     	    &(w->towns[i].y), &(w->towns[i].image), &(w->towns[i].defence),
     	    &(w->towns[i].owner), &(w->towns[i].income),
     	    &(w->towns[i].num_production));
     
     /*fscanf(f, "%s %d %d %d\n", w->towns[i].name, &(w->towns[i].x),
       &(w->towns[i].y), &(w->towns[i].image));*/
     printf("Finished reading town %d\n", i);
     
     for (j=0;j<w->towns[i].num_production;j++) {
       fscanf(f, "%d %d %d\n", &(w->towns[i].production[j].type), 
       	      &(w->towns[i].production[j].time),
	      &(w->towns[i].production[j].cost));
     }
     printf("Finished town %d's production info\n", i);
     
     w->towns[i].current_production = -1;
     printf("Read town %d\n", i);
   }

   w->selected_army = -1;

   printf("Read towns\n");

   //fclose(file);

   return 1;
}



int setup_default_world() {
  int i, j;
  
  default_world = create_world();

  default_world->width = 11;
  default_world->height = 19;

  strcpy(default_world->name, "Defaultia");

  default_world->map = malloc(sizeof(struct cell)*default_world->width*default_world->height);

  for(i=0;i<(default_world->height)*(default_world->width);i++)
      default_world->map[i].image = 9;

  for (i=0;i<default_world->width;i++)
    default_world->map[i].image = 8;
  for (i=0;i<default_world->width;i++)
    default_world->map[I(i, (default_world->height-1), default_world->width)].image = 8;
  for(i=0;i<default_world->height;i++)
    default_world->map[I(0, i, default_world->width)].image = 8;
  for(i=0;i<default_world->height;i++)
    default_world->map[I((default_world->width-1), i, default_world->width)].image = 8;

  for (i=0;i<default_world->width;i++)
    default_world->map[I(i, (default_world->height/2), default_world->width)].image = 8;
  for (i=0;i<default_world->height;i++)
    default_world->map[I((default_world->width/2), i, default_world->width)].image = 8;

  //  default_world->vis_x = ((default_world->width*CELL_WIDTH) / 2) - ((VIS_WIDTH * CELL_WIDTH) / 2);
  VISX_SET(default_world->vis_x, ((default_world->width*CELL_WIDTH) / 2) - ((VIS_WIDTH * CELL_WIDTH) / 2));

  //  default_world->vis_y = ((default_world->height*CELL_HEIGHT) / 2) - ((VIS_HEIGHT * CELL_HEIGHT) / 2);
  VISY_SET(default_world->vis_y, ((default_world->height*CELL_HEIGHT) / 2) - ((VIS_HEIGHT * CELL_HEIGHT) / 2));

#ifndef x86
  default_world->graphics = loadImage("images/SCENERY.png");
  if(!default_world->graphics) {
    printf("Image load failed!\n");
  } else {
    printf("After show_world\n");
  }
#endif
  
  return 1;
}




void print_world(struct world *w) {
  int i, j;

  printf("Name: %s\n", w->name);
  printf("width: %d, height: %d\n", w->width, w->height);
  printf("num_towns: %d, num_armies: %d\n", w->num_towns, w->num_armies);
  printf("vis_x: %d, vis_y: %d\n\n", w->vis_x, w->vis_y);
  
  for (j=0;j<w->height;j++) {
    for(i=0;i<w->width;i++) {
      printf("%3d ", w->map[I(i, j, w->width)].image);
    }
    printf("\n");
  }

  for(i=0;i<w->num_towns;i++) {
    printf("%s: %d, %d, %d\n", w->towns[i].name, w->towns[i].x,
	   w->towns[i].y, w->towns[i].image);
  }
  
}


void create_test_army(struct world *w) {
  printf("create_test_army:\n");

  w->num_armies = 1;
  w->armies = realloc(w->armies, sizeof(struct army_group) * w->num_armies);
  
  w->armies[0].num_armies = 1;
  w->armies[0].on_top = 0;
  w->armies[0].a[0].type = light_infantry;
  strcpy(w->armies[0].a[0].name, "Jo's Magnificent!");
  w->armies[0].a[0].moves_left = light_infantry.max_moves;
  w->armies[0].a[0].x = 5;
  w->armies[0].a[0].y = 5;

  //  print_army(w->armies[0].a[0]);

}

// TODO:  All this in a file
void create_test_player(struct world *w) {
  printf("create_test_player:\n");

  w->num_players = 8;
  w->players = realloc(w->players, sizeof(struct player) * w->num_players);
  memset(w->players, 0, sizeof(struct player) * w->num_players);
  printf("realloced players\n");

  
  w->num_armies = 0;
  /*w->armies = realloc(w->armies, sizeof(struct army_group) * w->num_armies);
  memset(w->armies, 0, sizeof(struct army_group) * w->num_armies);
  */

  strcpy(w->players[0].name, "Sirians");
  w->players[0].team = SIRIANS;
  w->players[0].num_cities = 1;
  w->players[0].income = 50;
  w->players[0].upkeep = 0;
  w->players[0].gold = 100;
  w->players[0].type = HUMAN;
  w->players[0].capital = 0;
  /*  w->armies[0].num_armies = 5;
  w->armies[0].a[0].type = hero;
  strcpy(w->armies[0].a[0].name, "Leofsunu");
  w->armies[0].a[0].moves_left = hero.max_moves;
  w->armies[0].a[0].x = w->towns[w->players[0].capital].x;
  w->armies[0].a[0].y = w->towns[w->players[0].capital].y;
  w->armies[0].a[0].team = SIRIANS;*/
  //  w->armies[0].selected = SELECT_GROUP;

  strcpy(w->players[1].name, "Storm Giants");
  w->players[1].team = STORM_GIANTS;
  w->players[1].num_cities = 1;
  w->players[1].income = 50;
  w->players[1].upkeep = 0;
  w->players[1].gold = 100;
  w->players[1].type = WARLORD;
  w->players[1].capital = 1;
  /*w->armies[1].num_armies = 7;
  w->armies[1].a[0].type = hero;
  strcpy(w->armies[1].a[0].name, "Sir Gareth");
  w->armies[1].a[0].moves_left = hero.max_moves;
  w->armies[1].a[0].x = w->towns[w->players[1].capital].x;
  w->armies[1].a[0].y = w->towns[w->players[1].capital].y;
  w->armies[1].a[0].team = STORM_GIANTS;*/
  //w->armies[1].selected = SELECT_GROUP;

  strcpy(w->players[2].name, "Grey Dwarves");
  w->players[2].team = GREY_DWARVES;
  w->players[2].num_cities = 1;
  w->players[2].income = 50;
  w->players[2].upkeep = 0;
  w->players[2].gold = 100;
  w->players[2].type = HUMAN;
  w->players[2].capital = 2;
  /*w->armies[2].num_armies = 1;
  w->armies[2].a[0].type = hero;
  strcpy(w->armies[2].a[0].name, "Byrthnoth");
  w->armies[2].a[0].moves_left = hero.max_moves;
  w->armies[2].a[0].x = w->towns[w->players[2].capital].x;
  w->armies[2].a[0].y = w->towns[w->players[2].capital].y;
  w->armies[2].a[0].team = GREY_DWARVES;
  */

  strcpy(w->players[3].name, "Orcs of Kor");
  w->players[3].team = ORCS_OF_KOR;
  w->players[3].num_cities = 1;
  w->players[3].income = 50;
  w->players[3].upkeep = 0;
  w->players[3].gold = 100;
  w->players[3].type = HUMAN;
  w->players[3].capital = 3;
  /*  w->armies[3].num_armies = 1;
  w->armies[3].a[0].type = hero;
  strcpy(w->armies[3].a[0].name, "Lord Falkner");
  w->armies[3].a[0].moves_left = hero.max_moves;
  w->armies[3].a[0].x = w->towns[w->players[3].capital].x;
  w->armies[3].a[0].y = w->towns[w->players[3].capital].y;
  w->armies[3].a[0].team = ORCS_OF_KOR;
  */
  strcpy(w->players[4].name, "Elvallie");
  w->players[4].team = ELVALLIE;
  w->players[4].num_cities = 1;
  w->players[4].income = 50;
  w->players[4].upkeep = 0;
  w->players[4].gold = 100;
  w->players[4].type = HUMAN;
  w->players[4].capital = 4;
  /*  w->armies[4].num_armies = 1;
  w->armies[4].a[0].type = hero;
  strcpy(w->armies[4].a[0].name, "Duke Tintagel");
  w->armies[4].a[0].moves_left = hero.max_moves;
  w->armies[4].a[0].x = w->towns[w->players[4].capital].x;
  w->armies[4].a[0].y = w->towns[w->players[4].capital].y;
  w->armies[4].a[0].team = ELVALLIE;
  */

  strcpy(w->players[5].name, "Selentines");
  w->players[5].team = SELENTINES;
  w->players[5].num_cities = 1;
  w->players[5].income = 50;
  w->players[5].upkeep = 0;
  w->players[5].gold = 100;
  w->players[5].type = HUMAN;
  w->players[5].capital = 5;
  /*  w->armies[5].num_armies = 1;
  w->armies[5].a[0].type = hero;
  strcpy(w->armies[5].a[0].name, "Ladie Lai");
  w->armies[5].a[0].moves_left = hero.max_moves;
  w->armies[5].a[0].x = w->towns[w->players[5].capital].x;
  w->armies[5].a[0].y = w->towns[w->players[5].capital].y;
  w->armies[5].a[0].team = SELENTINES;
  */

  strcpy(w->players[6].name, "Horse Lords");
  w->players[6].team = HORSE_LORDS;
  w->players[6].num_cities = 1;
  w->players[6].income = 50;
  w->players[6].upkeep = 0;
  w->players[6].gold = 100;
  w->players[6].type = HUMAN;
  w->players[6].capital = 6;
  /*  w->armies[6].num_armies = 1;
  w->armies[6].a[0].type = hero;
  strcpy(w->armies[6].a[0].name, "Leofsunu");
  w->armies[6].a[0].moves_left = hero.max_moves;
  w->armies[6].a[0].x = w->towns[w->players[6].capital].x;
  w->armies[6].a[0].y = w->towns[w->players[6].capital].y;
  w->armies[6].a[0].team = HORSE_LORDS;
  */

  strcpy(w->players[7].name, "Lord Bane");
  w->players[7].team = LORD_BANE;
  w->players[7].num_cities = 1;
  w->players[7].income = 50;
  w->players[7].upkeep = 0;
  w->players[7].gold = 100;
  w->players[7].type = HUMAN;
  w->players[7].capital = 7;
  /*  w->armies[7].num_armies = 1;
  w->armies[7].a[0].type = hero;
  strcpy(w->armies[7].a[0].name, "Leofsunu");
  w->armies[7].a[0].moves_left = hero.max_moves;
  w->armies[7].a[0].x = w->towns[w->players[7].capital].x;
  w->armies[7].a[0].y = w->towns[w->players[7].capital].y;
  w->armies[7].a[0].team = LORD_BANE;*/
  //  w->armies[7].selected = SELECT_GROUP;

  return;
}

/**
 * TODO: Calculate productions
 */
void start_turn(struct world *w, struct display *d) {
  w->turn++;

  struct player p = w->players[w->turn%w->num_players];

  w->command = CMD_DIALOGUE;
  

  /* centre on capital */
  //  VISX_SET(w->vis_x, (((w->towns[p.capital].x+1) * CELL_WIDTH) - (SCREEN_WIDTH/2)));
  //  VISY_SET(w->vis_y, (((w->towns[p.capital].y+1) * CELL_HEIGHT) - (SCREEN_HEIGHT/2)));

  w->vis_x = ((w->towns[p.capital].x+1) * CELL_WIDTH) - (SCREEN_WIDTH/2);  
  w->vis_y = ((w->towns[p.capital].y+1) * CELL_HEIGHT) - (SCREEN_HEIGHT/2);

  if(w->vis_y>(w->height*CELL_HEIGHT)-SCREEN_HEIGHT-1)
    w->vis_y=w->height*CELL_HEIGHT-SCREEN_HEIGHT-1;
  if(w->vis_y<0)
    w->vis_y=0;    

  if(w->vis_x>(w->width*CELL_WIDTH)-SCREEN_WIDTH-1)
    w->vis_x=w->width*CELL_WIDTH-SCREEN_WIDTH-1;
  if(w->vis_x<0)
    w->vis_x=0;


  sprintf(d->status_bar_text, "%s: Press X when ready!", p.name);
  update(d, w);
  wait_on_x();

  /* change selected town to player's capital */
  w->selected_town = p.capital;

  if (w->turn < 8) {
    /* emerge a hero! */
    sprintf(d->status_bar_text, "In %s, a hero emerges!",
	    w->towns[p.capital].name);
    update(d, w);
    wait_on_x();
    emerge_hero(w);
    /* now default to the production panel */
    production(w, d);
  } else {
    w->command = CMD_NONE;
  }


  /* decrement production forwarding moves */
  /* production forwarding report in conjunction with above */

  /* decrement all productions */
  /* production report in conjunction with above */

  update(d, w);
}


void emerge_hero(struct world *w) {
  w->num_armies++;
  w->armies = realloc(w->armies, sizeof(struct army_group) * w->num_armies);
  // memset(w->armies[w->num_armies], 0, sizeof(struct army_group));

  //  fprintf(stderr, "Armies: %d\n", w->num_armies);

  /*  w->armies[w->num_armies-1].num_armies = 1;
  w->armies[0].a[0].type = hero;
  strcpy(w->armies[0].a[0].name, "Leofsunu");
  w->armies[0].a[0].moves_left = hero.max_moves;
  w->armies[0].a[0].x = w->towns[w->players[0].capital].x;
  w->armies[0].a[0].y = w->towns[w->players[0].capital].y;
  w->armies[0].a[0].team = SIRIANS;
  */
    
  w->armies[w->num_armies-1].num_armies = 1;
  w->armies[w->num_armies-1].a[0].type = hero;
  strcpy(w->armies[w->num_armies-1].a[0].name, hero_name());
  w->armies[w->num_armies-1].a[0].moves_left = hero.max_moves;
  w->armies[w->num_armies-1].a[0].x =
    w->towns[w->players[w->turn%w->num_players].capital].x;
  w->armies[w->num_armies-1].a[0].y =
    w->towns[w->players[w->turn%w->num_players].capital].y;
  w->armies[w->num_armies-1].a[0].team = w->turn%w->num_players;
  w->armies[w->num_armies-1].selected = SELECT_NONE;
  
}

char * hero_name() {
  return "Leofsunu";
}


void production(struct world *w, struct display *d) {
  int done = 0;
  int selected = w->towns[w->selected_town].current_production;
  struct player p = w->players[w->turn%w->num_players];

  w->command = CMD_PROD;
  w->selected_town = p.capital;
  update(d, w);

  //  if (w->command == CMD_PROD) {
  //    if(w->towns[w->selected_town].num_production > 0) {
  //      w->towns[w->selected_town].current_production = 0;
  //    }
  //  }

  // TODO: Button switch here.  Annoying that it breaks down the
  // abstraction but I cannot easily see another way to do it :-( Make
  // a generic wait function in input.c which returns which button was
  // pressed.

  while (!done) {
    switch(wait_on_input()) {
    case PSP_CTRL_CROSS:
      if(w->towns[w->selected_town].num_production > 0)
	selected  = 0;
      break;
    case PSP_CTRL_CIRCLE:
      if(w->towns[w->selected_town].num_production > 1)
	selected  = 1;
      break;
    case PSP_CTRL_TRIANGLE:
      if(w->towns[w->selected_town].num_production > 2)
	selected  = 2;
      break;
    case PSP_CTRL_SQUARE:
      if(w->towns[w->selected_town].num_production > 3)
	selected  = 3;
      break;
    case PSP_CTRL_START:
      done = 1;
      break;
    case PSP_CTRL_SELECT:
      selected = -1;
    }

    w->towns[w->selected_town].current_production = selected;
    w->towns[w->selected_town].current_production_turns = w->towns[w->selected_town].production[selected].time;

    update(d, w);
  }
  //  wait_on_x();
  w->command = CMD_NONE;
}



void select_next_army(struct world *w) {
  if (w->selected_army < w->num_armies-1)
    w->selected_army++;
  else
    w->selected_army = 0;
}


void select_prev_army(struct world *w) {
  if(w->selected_army > 0)
    w->selected_army--;
  else
    w->selected_army = w->num_armies-1;
}

