#include "Graphics.h"
#include "swis.h"
#include <kernel.h>

extern int tick;
extern int lasttick;
extern int screen;

extern _kernel_swi_regs inreg;
extern _kernel_swi_regs outreg;


#define TILESX 10
#define TILESY 10
#define SMARTTILES 200
#define AREAS 20

// map[0] is the 'master', [1] and [2] represents what is currently
// believed to be displayed in the corresponding (+1) screen buffer
// and we run a compare to see if re-drawing is needed. 0xFF is used
// for a re-draw being required (so it's set on the tile under the player
unsigned char map[3][TILESX][TILESY];
unsigned char fullmap[10000];

unsigned char areaname[13];

char tilenamebuffer[4];
char textbuffer[63];

struct EntityLocation_s {
  short signed int X,Y;
};

struct Area_s {
  unsigned char name[16];
};

struct Area_s Areas[AREAS];

struct TilePlayer_s {
  struct EntityLocation_s location;
  struct EntityLocation_s lastlocation;
  struct EntityLocation_s hitbox_bl;
  struct EntityLocation_s hitbox_tr;
  struct EntityLocation_s drawbox_bl;
  struct EntityLocation_s drawbox_tr;
  struct EntityLocation_s mapoffset;
  struct EntityLocation_s lastmapoffset;
  struct EntityLocation_s localtile;
  int rawtile;
};

struct TilePlayer_s TilePlayer;

struct SmartTile_s {
  int Tile;
  int ActionTarget;
  unsigned char Action;
  unsigned char ActionValue;
};

struct SmartTile_s SmartTiles[SMARTTILES];

/************VVV TO BE REMOVED/MOVED TO MAPEDIT VVV***********/
void game2_savesmarttiles(char* filename)
{
  // Attempt to get file info
  inreg.r[0] = 10;
  inreg.r[1] = (int) filename;
  inreg.r[2] = 0xffd;
  inreg.r[4] = (int) SmartTiles;
  inreg.r[5] = (int) SmartTiles + (sizeof(SmartTiles));

  _kernel_swi(OS_File,&inreg,&outreg);
 
}
void game2_saveareanames(char* filename)
{
  // Attempt to get file info
  inreg.r[0] = 10;
  inreg.r[1] = (int) filename;
  inreg.r[2] = 0xffd;
  inreg.r[4] = (int) Areas;
  inreg.r[5] = (int) Areas + (sizeof(Areas));

  _kernel_swi(OS_File,&inreg,&outreg);
 
}
/************^^^ TO BE REMOVED/MOVED TO MAPEDIT ^^^***********/
void game2_loadsmarttiles(char* filename)
{
  int length;

  // Attempt to get file info
  inreg.r[0] = 5;
  inreg.r[1] = (int) filename;
  _kernel_swi(OS_File,&inreg,&outreg);

  // Length will be in R4 if it exists
  length = outreg.r[4];

  if(length > sizeof(SmartTiles))
  {
    screen_nobuffer();
    while (1)
    printf("Smarttiles exceeds %d bytes (%d bytes) object type is %d\n",sizeof(SmartTiles),length,outreg.r[0]);
    //exit(0);
  }

  // Attempt to get file info
  inreg.r[0] = 16;
  inreg.r[1] = (int) filename;
  inreg.r[2] = (int) SmartTiles;
  inreg.r[3] = 0;

  _kernel_swi(OS_File,&inreg,&outreg);
 
}

void game2_loadareanames(char* filename)
{
  int length;

  // Attempt to get file info
  inreg.r[0] = 5;
  inreg.r[1] = (int) filename;
  _kernel_swi(OS_File,&inreg,&outreg);

  // Length will be in R4 if it exists
  length = outreg.r[4];

  if(length > sizeof(Areas))
  {
    screen_nobuffer();
    while (1)
    printf("Areas exceeds %d bytes (%d bytes) object type is %d\n",sizeof(Areas),length,outreg.r[0]);
    //exit(0);
  }

  // Attempt to get file info
  inreg.r[0] = 16;
  inreg.r[1] = (int) filename;
  inreg.r[2] = (int) Areas;
  inreg.r[3] = 0;

  _kernel_swi(OS_File,&inreg,&outreg);
 
}

void game2_loadmap(char* filename)
{
  int length,i;

  // Attempt to get file info
  inreg.r[0] = 5;
  inreg.r[1] = (int) filename;
  _kernel_swi(OS_File,&inreg,&outreg);

  // Length will be in R4 if it exists
  length = outreg.r[4];

  if(length > sizeof(fullmap))
  {
    screen_nobuffer();
    printf("Map exceeds %d bytes (%d bytes) object type is %d\n",sizeof(fullmap),length,outreg.r[0]);
    exit(0);
  }
  
  // Attempt to get file info
  inreg.r[0] = 16;
  inreg.r[1] = (int) filename;
  inreg.r[2] = (int) fullmap;
  inreg.r[3] = 0;

  _kernel_swi(OS_File,&inreg,&outreg);

  for(i = 0; i < SMARTTILES; i++)
    SmartTiles[i].Tile = -1;
}

void game2_death()
{
  int currentstart = 0;
  int introframe = 0;
  sound_voices(4);

  sound_set_voice(1,"WaveSynth-Beep");
  sound_set_voice(2,"WaveSynth-Beep");
  sound_set_voice(3,"WaveSynth-Beep");
  sound_set_voice(4,"WaveSynth-Beep");
  sound_composition_init();

  sound_composition_load("music.cmpagrac");

  tick = clock();

  sound_composition_start(clock());

  draw_sprite("spacebar",(DISPLAY_X/2)-106,50);
  draw_sprite("kia",(DISPLAY_X/2)-300,500);

  screen_flipbuffer();

  while(sound_composition_incomplete())
  {
    sound_composition_tick(clock());

    if(clock() > (tick + 100))
    {
      if(input_readkey(98))
        sound_composition_stop();
    }
  }
}

void game2_briefing()
{
  screen_clear();

  draw_spritetext(
"~~~~~~~~{ chief engineers log - uss archimedes - stardate 1234567890 ==}\n\n\ndo stuff on the ship. not sure what yet. go for a wander. \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n~~~~~~~~{======================~~~~~~~~===========================}"
, 50, 950);

  draw_sprite("spacebar",(DISPLAY_X/2)-106,50);

  screen_flipbuffer();

  tick = clock();
  while(1)
  {
    if(clock() > (tick + 100))
    {
      if(input_readkey(98))
        return;
    }
  }
}

void game2_fillmap(int xoffset, int yoffset)
{
  memcpy(map[0][0],fullmap+yoffset+(xoffset*100),10);
  memcpy(map[0][1],fullmap+yoffset+(xoffset*100)+100,10);
  memcpy(map[0][2],fullmap+yoffset+(xoffset*100)+200,10);
  memcpy(map[0][3],fullmap+yoffset+(xoffset*100)+300,10);
  memcpy(map[0][4],fullmap+yoffset+(xoffset*100)+400,10);
  memcpy(map[0][5],fullmap+yoffset+(xoffset*100)+500,10);
  memcpy(map[0][6],fullmap+yoffset+(xoffset*100)+600,10);
  memcpy(map[0][7],fullmap+yoffset+(xoffset*100)+700,10);
  memcpy(map[0][8],fullmap+yoffset+(xoffset*100)+800,10);
  memcpy(map[0][9],fullmap+yoffset+(xoffset*100)+900,10);
}

void game2_setup()
{
  screen_flipbuffer();
  screen_clear();
  screen_flipbuffer();
  screen_clear();
  
  TilePlayer.location.X = 102;
  TilePlayer.location.Y = 102;
  
  TilePlayer.hitbox_bl.X = 0;
  TilePlayer.hitbox_bl.Y = 0;
  TilePlayer.hitbox_tr.X = 80;
  TilePlayer.hitbox_tr.Y = 80;
  
  TilePlayer.drawbox_bl.X = 0;
  TilePlayer.drawbox_bl.Y = 0;
  TilePlayer.drawbox_tr.X = 80;
  TilePlayer.drawbox_tr.Y = 80;
  
  memset(map[0],0xFF,100);
  memset(map[1],0xFF,100);
  memset(map[2],0xFF,100);

  game2_loadmap("m2_map");
  game2_loadsmarttiles("m2_smart");
  game2_loadareanames("m2_areas");
  game2_fillmap(TilePlayer.mapoffset.X,TilePlayer.mapoffset.Y);
}

int game2_check_collide()
{
  int x,y,hit;

  hit = 0;

  for(x = 0; x < TILESX; x++)
  {
    for(y = 0; y < TILESY; y++)
    {
      // Finds any tile we collide with
      if(game_hitbox_collide(
      (TilePlayer.location.X + TilePlayer.hitbox_bl.X),(TilePlayer.location.Y + TilePlayer.hitbox_bl.Y),
      (TilePlayer.hitbox_tr.X - TilePlayer.hitbox_bl.X),(TilePlayer.hitbox_tr.Y - TilePlayer.hitbox_bl.Y),
      x*100,y*100,
      100,100
      ))
      {
        if(((map[0][x][y] >> 7)  & 0x01))
        {
          hit = 1;
        }
      }
    }
  }

  return hit;
}

void game2_tick_input()
{
  char movedy = 0;

  // Store in case we have a vertical collide
  TilePlayer.lastlocation.X = TilePlayer.location.X;
  TilePlayer.lastlocation.Y = TilePlayer.location.Y;
  TilePlayer.lastmapoffset.X = TilePlayer.mapoffset.X;
  TilePlayer.lastmapoffset.Y = TilePlayer.mapoffset.Y;

  if(input_readkey(57))// Up arrow
  {
    TilePlayer.location.Y += 3 * (tick - lasttick);
    if(TilePlayer.location.Y > (910))
    {
      TilePlayer.location.Y = 100;
      TilePlayer.mapoffset.Y += 10;
      game2_fillmap(TilePlayer.mapoffset.X,TilePlayer.mapoffset.Y);
    }
    movedy = 1;
  }
  else if(input_readkey(41))// Down arrow
  {
    TilePlayer.location.Y -= 3 * (tick - lasttick);
    if(TilePlayer.location.Y < (10))
    {
      if(TilePlayer.mapoffset.Y > 0)
      {
        TilePlayer.location.Y = 900;
        TilePlayer.mapoffset.Y -= 10;
        game2_fillmap(TilePlayer.mapoffset.X,TilePlayer.mapoffset.Y);
      }else{
        TilePlayer.location.Y = TilePlayer.lastlocation.Y;
      }
    }
    movedy = 1;
  }


  if(game2_check_collide())
  {
    TilePlayer.location.X = TilePlayer.lastlocation.X;
    TilePlayer.location.Y = TilePlayer.lastlocation.Y;
    TilePlayer.mapoffset.X = TilePlayer.lastmapoffset.X;
    TilePlayer.mapoffset.Y = TilePlayer.lastmapoffset.Y;
  }

  // Dont allow horizontal and vertical - makes movement sketchy
  if(movedy == 1)
    return;

  // Store in case we have a horizontal collide
  TilePlayer.lastlocation.X = TilePlayer.location.X;
  TilePlayer.lastlocation.Y = TilePlayer.location.Y;

  if(input_readkey(121))// Right arrow
  {
    TilePlayer.location.X += 3 * (tick - lasttick);
    if(TilePlayer.location.X > (910))
    {
      TilePlayer.location.X = 100;
      TilePlayer.mapoffset.X += 10;
      game2_fillmap(TilePlayer.mapoffset.X,TilePlayer.mapoffset.Y);
    }
  }
  else if(input_readkey(25))// Left arrow
  {
    TilePlayer.location.X -= 3 * (tick - lasttick);
    if(TilePlayer.location.X < (10))
    {
      if(TilePlayer.mapoffset.X > 0)
      {
        TilePlayer.location.X = 900;
        TilePlayer.mapoffset.X -= 10;
        game2_fillmap(TilePlayer.mapoffset.X,TilePlayer.mapoffset.Y);
      }else{
        TilePlayer.location.X = TilePlayer.lastlocation.X;
      }
    }
  }

  if(game2_check_collide())
  {
    TilePlayer.location.X = TilePlayer.lastlocation.X;
    TilePlayer.location.Y = TilePlayer.lastlocation.Y;
  }
}

int game2_tick()
{
  int x;
  int y;
  int i;

  lasttick = tick;
  tick = clock();

  screen_flipbuffer();

  if(1)
  {
    // Fill the map0 with our chunk of the full map
    game2_fillmap(TilePlayer.mapoffset.X,TilePlayer.mapoffset.Y);
    
    draw_spritetext("#############", 1020, 950);
    draw_spritetext(areaname, 1020, 950);

    for(x = 0; x < TILESX; x++)
    {
      for(y = 0; y < TILESY; y++)
      {
        // Finds any tile we collide with
        if(game_hitbox_collide(
        (TilePlayer.location.X + TilePlayer.drawbox_bl.X),(TilePlayer.location.Y + TilePlayer.drawbox_bl.Y),
        (TilePlayer.hitbox_tr.X - TilePlayer.drawbox_bl.X),(TilePlayer.drawbox_tr.Y - TilePlayer.drawbox_bl.Y),
        x*100,y*100,
        100,100
        ))
        {
          map[1][x][y] = 255;
          map[2][x][y] = 255;
        }

        // Find the tile under our centre of mass
        if(game_hitbox_collide(
        (TilePlayer.location.X +  TilePlayer.hitbox_bl.X + (TilePlayer.hitbox_tr.X/2)),(TilePlayer.location.Y + TilePlayer.hitbox_bl.Y + (TilePlayer.hitbox_tr.Y/2)),
        (1),(1),
        x*100,y*100,
        100,100
        ))
        {
          TilePlayer.localtile.X = x;
          TilePlayer.localtile.Y = y;
        }

        // Redraw any tiles we're overlapping
        if(map[0][x][y] ^ map[screen+1][x][y])
        {
          map[screen+1][x][y] = map[0][x][y];
          if(map[screen+1][x][y] < 128)
            sprintf(tilenamebuffer,"%i",map[screen+1][x][y]);
          else
            sprintf(tilenamebuffer,"%i",(map[screen+1][x][y]-128));

          draw_tile(tilenamebuffer,x*100,y*100);
        }
      }
    }

    TilePlayer.rawtile = (TilePlayer.mapoffset.Y) + TilePlayer.localtile.Y + (TilePlayer.mapoffset.X * 100) + (TilePlayer.localtile.X * 100);

    // Trigger any smart tiles for our centre of mass
    for(i = 0; i < SMARTTILES; i++)
    {
      if(SmartTiles[i].Tile == TilePlayer.rawtile)
      {
        // Change tile sprite
        if(SmartTiles[i].Action == 0)
          fullmap[SmartTiles[i].ActionTarget] = SmartTiles[i].ActionValue;
        else if(SmartTiles[i].Action == 1)
          sprintf(areaname,"%s",Areas[SmartTiles[i].ActionValue].name);
      }
    }

    game2_tick_input();

    draw_sprite("man",TilePlayer.location.X,TilePlayer.location.Y);

#ifdef M2_DEBUG_HITBOXES
    draw_rectangle(
    (TilePlayer.location.X + TilePlayer.hitbox_bl.X),
    (TilePlayer.location.Y + TilePlayer.hitbox_bl.Y),
    (TilePlayer.location.X + TilePlayer.hitbox_tr.X),
    (TilePlayer.location.Y + TilePlayer.hitbox_tr.Y)
    );
    draw_rectangle(
    (TilePlayer.location.X + TilePlayer.drawbox_bl.X),
    (TilePlayer.location.Y + TilePlayer.drawbox_bl.Y),
    (TilePlayer.location.X + TilePlayer.drawbox_tr.X),
    (TilePlayer.location.Y + TilePlayer.drawbox_tr.Y)
    );
#endif
    return 0;
  }else{
/*    screen_flipbuffer();
    screen_clear();
    game2_death();
    return 1;*/
  }
}
