#include <string.h>
#include "map.h"
#include "water.h"
#include "data.h"
#include "ship.h"
#include "globals.h"

#define PIX_BUOY 1
#define PIX_START 2
#define PIX_JUMPPAD 3
#define PIX_ROCK 4
#define PIX_NENUPHAR 5
#define PIX_SPEEDPAD 6

#define TRANS_SCALE 1.3
#define MAX_ROCK_H 35

Map::Map()
{
  Init();
}

void Map::Init()
{
  int n;

  nbuoys=0;
  buoys=NULL;
  nrocks=0;
  rocks=NULL;
  nnenuphars=0;
  nenuphars=NULL;
  nwaypoints=0;
  startx=0;
  starty=0;
  for (n=0;n<FINISH;n++) {
    waypoints[n].x0=-1;
    waypoints[n].y0=-1;
    waypoints[n].x1=-1;
    waypoints[n].y1=-1;
  }
  if (wind)
   wind_spd=ftofix((rand()%100)/4000.0);
  else
   wind_spd=0;
  wind_dir=rand()&(itofix(256)-1);
  njumppads=0;
  jumppads=NULL;
  nspeedpads=0;
  speedpads=NULL;
}

void Map::AddBuoy(int x,int y)
{
  buoys=(Buoy*)realloc(buoys,(nbuoys+1)*sizeof(Buoy));
  buoys[nbuoys].x=x<<16;
  buoys[nbuoys].y=y<<16;
  nbuoys++;
}

void Map::AddRock(int x,int y)
{
  rocks=(Rock*)realloc(rocks,(nrocks+1)*sizeof(Rock));
  rocks[nrocks].x=x<<16;
  rocks[nrocks].y=y<<16;
  rocks[nrocks].type=rand()%3;
  nrocks++;
}

void Map::AddNenuphar(int x,int y)
{
  nenuphars=(Nenuphar*)realloc(nenuphars,(nnenuphars+1)*sizeof(Nenuphar));
  nenuphars[nnenuphars].x=x<<16;
  nenuphars[nnenuphars].y=y<<16;
  nnenuphars++;
}

void Map::AddJumpPad(int x,int y)
{
  jumppads=(JumpPad*)realloc(jumppads,(njumppads+1)*sizeof(JumpPad));
  if (!jumppads) Error("Not enough memory");
  jumppads[njumppads].x=x<<16;
  jumppads[njumppads].y=y<<16;
  njumppads++;
}

void Map::AddSpeedPad(int x,int y)
{
  speedpads=(SpeedPad*)realloc(speedpads,(nspeedpads+1)*sizeof(SpeedPad));
  if (!speedpads) Error("Not enough memory");
  speedpads[nspeedpads].x=x<<16;
  speedpads[nspeedpads].y=y<<16;
  nspeedpads++;
}

void Map::AddWaypoint(int n,int x,int y)
{
  if (waypoints[n].x0==-1) {
    waypoints[n].x0=x<<16;
    waypoints[n].y0=y<<16;
  }
  else {
    waypoints[n].x1=x<<16;
    waypoints[n].y1=y<<16;
    nwaypoints++;
  }
}

int Map::Load(char *map_filename)
{
  BITMAP *pcx;
  PALETTE pal;
  int scale=20;
  int x,y;

  set_color_conversion(COLORCONV_NONE);
  strcpy(filename,map_filename);
  pcx=load_pcx(filename,pal);
  if (!pcx) {
    strcat(filename,".pcx");
    pcx=load_pcx(filename,pal);
    if (!pcx) return 0;
  }

  width=(pcx->w*scale)<<16;
  height=(pcx->h*scale)<<16;

  for (y=0;y<pcx->h;y++) for (x=0;x<pcx->w;x++) {
    switch (_getpixel(pcx,x,y)) {
      case 0:
        break;
      case PIX_BUOY:
        AddBuoy(x*scale,y*scale);
        break;
      case PIX_START:
        startx=(x*scale)<<16;
        starty=(y*scale)<<16;
        break;
      case PIX_JUMPPAD:
        AddJumpPad(x*scale,y*scale);
        break;
      case PIX_ROCK:
        AddRock(x*scale,y*scale);
        break;
      case PIX_NENUPHAR:
        AddNenuphar(x*scale,y*scale);
        break;
      case PIX_SPEEDPAD:
        AddSpeedPad(x*scale,y*scale);
        break;
      default:
        if (_getpixel(pcx,x,y)>=192 && _getpixel(pcx,x,y)<=255) {
          AddWaypoint(getpixel(pcx,x,y)-192,x*scale,y*scale);
          break;
        }
        Error("Unknown pixel code: %d\n",_getpixel(pcx,x,y));
    }
  }
  set_color_conversion(COLORCONV_TOTAL);

  return 1;
}

void Map::Unload()
{
  free(buoys);
  free(jumppads);
  free(speedpads);
  free(rocks);
  free(nenuphars);
  Init();
}

void Map::Draw(fixed x,fixed y,int sx,int sy,int sw,int sh,int DX,int DY)
{
  int n,p;
  int c=makecol(255,0,0);
  static BITMAP *scaled=NULL;
  int w,h;

  if (!scaled) {
    scaled=create_bitmap((int)(32*TRANS_SCALE),(int)(MAX_ROCK_H*TRANS_SCALE));
    if (!scaled) Error("Not enough memory");
  }

  set_clip(drawable,sx,sy,sx+sw,sy+sh);

  set_clip(
    water2,
    sx/WATERSCALE,sy/WATERSCALE,(sx+sw)/WATERSCALE-1,(sy+sh)/WATERSCALE-1
  );
  for (n=0;n<njumppads;n++) {
    if (water) {
      circle(
        water2,
        (sx+(jumppads[n].x>>16)-(x>>16))/WATERSCALE,
        (sy+(jumppads[n].y>>16)-(y>>16))/WATERSCALE,
        4,255
      );
      for (p=0;p<4;p++) putpixel(
        water2,
        (sx+(jumppads[n].x>>16)-(x>>16)+(rand()&7)-3)/WATERSCALE,
        (sy+(jumppads[n].y>>16)-(y>>16)+(rand()&7)-3)/WATERSCALE,
        255
      );
    }
    else {
      circle(
        drawable,
        sx+(jumppads[n].x>>16)-(x>>16),sy+(jumppads[n].y>>16)-(y>>16),
        8,makecol(0,255,0)
      );
    }
  }
  for (n=0;n<nspeedpads;n++) {
    if (water) {
      circle(
        water2,
        (sx+(speedpads[n].x>>16)-(x>>16))/WATERSCALE,
        (sy+(speedpads[n].y>>16)-(y>>16))/WATERSCALE,
        4,255
      );
    }
    else {
      circle(
        drawable,
        sx+(speedpads[n].x>>16)-(x>>16),sy+(speedpads[n].y>>16)-(y>>16),
        8,makecol(255,0,0)
      );
    }
  }

  if (water) {
    SWater(
      water1,water2,x>>16,y>>16,sx,sy,sw,sh,
      ((DX>>16)+WATERSCALE/2)/WATERSCALE,((DY>>16)+WATERSCALE/2)/WATERSCALE
    );
for (int k=0;k<15;k++)
    rect(water1,sx/WATERSCALE+k,sy/WATERSCALE+k,(sx+sw)/WATERSCALE-1-k,(sy+sh)/WATERSCALE-1-k,0);
    rect(
      water1,
      sx/WATERSCALE,sy/WATERSCALE,(sx+sw)/WATERSCALE-1,(sy+sh)/WATERSCALE-1,
      0
    );
  }
  else {
    drawing_mode(DRAW_MODE_COPY_PATTERN,bg,-(x>>16),-(y>>16));
    rectfill(drawable,sx,sy,sx+sw,sy+sh,0);
    solid_mode();
  }

  if (trans) {
    set_trans_blender(104,192,192,0);
    for (n=0;n<nrocks;n++) {
      w=((BITMAP*)(data[dat_rock1+rocks[n].type].dat))->w;
      h=((BITMAP*)(data[dat_rock1+rocks[n].type].dat))->h;
      stretch_blit(
        // Assuming rocks 1 2 3 follow in the data.h indices file
        (BITMAP*)(data[dat_rock1+rocks[n].type].dat),scaled,
        0,0,w,h,0,0,scaled->w,scaled->h
      );
      draw_lit_sprite(
        drawable,scaled,
        sx+(rocks[n].x>>16)-(x>>16)-(int)((32*(TRANS_SCALE))/2),
        sy+(rocks[n].y>>16)-(y>>16)-(int)((MAX_ROCK_H*(TRANS_SCALE))/2),
        128
      );
    }
  }
  for (n=0;n<nrocks;n++) {
    draw_sprite(
      drawable,
      // Assuming rocks 1 2 3 follow in the data.h indices file
      (BITMAP*)(data[dat_rock1+rocks[n].type].dat),
      sx+(rocks[n].x>>16)-(x>>16)-16,sy+(rocks[n].y>>16)-(y>>16)-MAX_ROCK_H/2
    );
  }
  for (n=0;n<nnenuphars;n++) {
    draw_sprite(
      drawable,
      (BITMAP*)(data[dat_nenuphar].dat),
      sx+(nenuphars[n].x>>16)-(x>>16),sy+(nenuphars[n].y>>16)-(y>>16)
    );
  }
  for (n=0;n<nbuoys;n++) {
    draw_sprite(
      drawable,
      (BITMAP*)(data[dat_buoy].dat),
      sx+(buoys[n].x>>16)-(x>>16),sy+(buoys[n].y>>16)-(y>>16)
    );
  }
  for (n=0;n<nwaypoints;n++) {
    line(
      drawable,
      sx+(waypoints[n].x0>>16)-(x>>16),sy+(waypoints[n].y0>>16)-(y>>16),
      sx+(waypoints[n].x1>>16)-(x>>16),sy+(waypoints[n].y1>>16)-(y>>16),
      c
    );
  }

  rect(drawable,sx,sy,sx+sw-1,sy+sh-1,makecol(255,255,255));
  rect(drawable,sx+1,sy+1,sx+sw-2,sy+sh-2,makecol(255,255,255));
}

void Map::Think()
{
  // Change the wind direction and speed randomly
  if ((rand()&255)==0) {
    wind_dir+=rand()%9-4;
    wind_spd=fmul(wind_spd,itofix(1)+(rand()%1023)-512);
  }
}

void MapViewer::Init()
{
  DX=ship->x-((sw/2)<<16);
  DY=ship->y-((sh/2)<<16);
}

void MapViewer::Draw()
{
  fixed x,y;
  int n;
  fixed wdir;
  fixed dx,dy;

  x=ship->x-((sw/2)<<16);
  y=ship->y-((sh/2)<<16);
  if (water) {
    for (n=0;n<((training|clockmode)?1:nships);n++)
     ships[n]->DrawTrail(x,y,sx,sy,sw,sh);
  }
  map->Draw(x,y,sx,sy,sw,sh,x-DX,y-DY);
  DX=x;
  DY=y;
  for (n=0;n<((training|clockmode)?1:nships);n++)
   ships[n]->Draw(x,y,sx,sy,sw,sh);

  if (marker) {
    dx=(map->waypoints[ship->waypoint].x0+map->waypoints[ship->waypoint].x1)/2
       -ship->x;
    dy=(map->waypoints[ship->waypoint].y0+map->waypoints[ship->waypoint].y1)/2
       -ship->y;
    wdir=fatan2(dy,dx);

    rotate_sprite(
      drawable,(BITMAP*)(data[dat_marker].dat),
      sx+sw/2+fixtoi(64*fcos(wdir)),
      sy+sh/2+fixtoi(64*fsin(wdir)),
      wdir
    );
  }
}

