#include "Editor.h"

int make_map = 0;
int slide_start_x = -1;
int slide_start_y = -1;
EditPanel edit_panel;
Cursor editor_cursor;
SDL_Surface *map_screen;
#define SAVE_X 260
#define SAVE_Y 0
#define SAVE_WIDTH 550
#define SAVE_HEIGHT 550

/**
   The editor-specific map drawing event.
   This is called before the map is sent to the screen.
 */
void
makeMap()
{
  if(!(map_screen = SDL_CreateRGBSurface(SDL_SWSURFACE,
                                         (SAVE_WIDTH - SAVE_X) * TILE_W,
                                         SAVE_HEIGHT * TILE_H,
                                         screen->format->BitsPerPixel,
                                         0, 0, 0, 0))) {
    fprintf(stderr, "Error creating surface: %s\n", SDL_GetError());
    fflush(stderr);
    return;
  }
  cursor.pos_x = SAVE_X;
  cursor.pos_y = SAVE_Y;
  make_map = 1;
  drawMap();
}

void
beforeDrawToScreen()
{
  SDL_Rect pos;
  int screen_center_x, screen_center_y;

  // save map images
  if(make_map) {
    if(cursor.pos_y >= SAVE_HEIGHT) {
      make_map = 0;
      SDL_Flip(map_screen);
      fprintf(stderr, "saving map.bmp\n");
      SDL_SaveBMP(map_screen, "map.bmp");
      fprintf(stderr, "done saving map.bmp\n");
      SDL_FreeSurface(map_screen);
    } else {
      pos.x = (cursor.pos_x - SAVE_X) * TILE_W;
      pos.y = cursor.pos_y * TILE_H;
      pos.w = screen->w;
      pos.h = screen->h;
      SDL_BlitSurface(screen, NULL, map_screen, &pos);
      SDL_Flip(map_screen);

      cursor.dir = DIR_UPDATE;
      map.redraw = 1;
      fprintf(stderr, "x=%d y=%d\n", cursor.pos_x, cursor.pos_y);
      if(cursor.pos_x < SAVE_WIDTH) {
        cursor.pos_x += screen->w / TILE_W;
      } else {
        cursor.pos_x = SAVE_X;
        cursor.pos_y += screen->h / TILE_H;
      }
    }
  }
  // draw the cursor
  screen_center_x = (screen->w / TILE_W) / 2;
  screen_center_y = (screen->h / TILE_H) / 2;
  pos.x = screen_center_x * TILE_W;
  pos.y = screen_center_y * TILE_H;
  pos.w = TILE_W;
  pos.h = TILE_H;
  SDL_FillRect(screen, &pos,
               SDL_MapRGBA(screen->format, 0xa0, 0xa0, 0x00, 0x00));

  pos.x = editor_cursor.pos_x * TILE_W;
  pos.y = editor_cursor.pos_y * TILE_H;
  pos.w = TILE_W;
  pos.h = TILE_H;
  SDL_FillRect(screen, &pos,
               SDL_MapRGBA(screen->format, 0x00, 0xa0, 0x00, 0x00));

  // draw the edit panel
  drawEditPanel();
}

void
editorAfterScreenFlipped()
{
}

void
drawSlide(int x1, int y1, int x2, int y2)
{
  int sx, sy, x, y;
  Position pos;

  if(x1 == x2 || y1 == y2) {
    showMapStatus("error cant draw slide");
  }
  // swap
  if(y1 > y2) {
    sx = x1;
    sy = y1;
    x1 = x2;
    y1 = y2;
    x2 = sx;
    y2 = sy;
  }
  x = x1;
  for(y = y1; y < y2; y++) {
    pos.pos_x = x;
    pos.pos_y = y;
    setImageNoCheck(LEVEL_MAIN, x, y, img_slideback);
    if(x1 < x2) {
      // NW -> SE slide
      setImageNoCheck(LEVEL_FORE, x - 1, y, img_slide_right[2]);
      setImageNoCheck(LEVEL_FORE, x, y, img_slide_right[0]);
      setImageNoCheck(LEVEL_FORE, x + 1, y, img_slide_right[1]);
      x++;
    } else {
      // NE -> SW slide
      setImageNoCheck(LEVEL_FORE, x - 1, y, img_slide_left[1]);
      setImageNoCheck(LEVEL_FORE, x, y, img_slide_left[0]);
      setImageNoCheck(LEVEL_FORE, x + 1, y, img_slide_left[2]);
      x--;
    }
  }
  showMapStatus("added slide");
  drawMap();
}

void
drawRect(int x1, int y1, int x2, int y2)
{
  int x, y;
  Position pos;
  SDL_Surface *img;

  img = images[edit_panel.image_index]->image;
  for(y = y1; y < y2; y += img->h / TILE_H) {
    for(x = x1; x < x2; x += img->w / TILE_W) {
      pos.pos_x = x;
      pos.pos_y = y;
      setImagePosition(edit_panel.level, edit_panel.image_index, &pos);
    }
  }
  showMapStatus("added rectangle");
  drawMap();
}

/**
   Main editor event handling
*/
void
editorMainLoop(SDL_Event * event)
{
  int n;
  Position pos;
  switch (event->type) {
  case SDL_MOUSEMOTION:
    editor_cursor.pos_x = event->motion.x / TILE_W;
    editor_cursor.pos_y = event->motion.y / TILE_H;
    if(event->motion.x <= TILE_W) {
      cursor.pos_x--;
      if(cursor.pos_x < 0)
        cursor.pos_x = 0;
      cursor.dir = DIR_NONE;
      map.redraw = 1;
    }
    if(event->motion.x > screen->w - TILE_W) {
      cursor.pos_x++;
      if(cursor.pos_x >= map.w)
        cursor.pos_x = map.w - 1;
      cursor.dir = DIR_NONE;
      map.redraw = 1;
    }
    if(event->motion.y <= TILE_H) {
      cursor.pos_y--;
      if(cursor.pos_y < 0)
        cursor.pos_y = 0;
      cursor.dir = DIR_NONE;
      map.redraw = 1;
    }
    if(event->motion.y > screen->h - EDIT_PANEL_HEIGHT - TILE_H) {
      cursor.pos_y++;
      if(cursor.pos_y >= map.h)
        cursor.pos_y = map.h - 1;
      cursor.dir = DIR_NONE;
      map.redraw = 1;
    }

    break;
  case SDL_MOUSEBUTTONUP:
    switch (event->button.button) {
    case SDL_BUTTON_LEFT:
      pos.pos_x = map.top_left_x + editor_cursor.pos_x;
      pos.pos_y = map.top_left_y + editor_cursor.pos_y;
      setImagePosition(edit_panel.level, edit_panel.image_index, &pos);
      break;
    case SDL_BUTTON_MIDDLE:
      pos.pos_x = map.top_left_x + editor_cursor.pos_x;
      pos.pos_y = map.top_left_y + editor_cursor.pos_y;
      setImagePosition(edit_panel.level, EMPTY_MAP, &pos);
      break;
    case SDL_BUTTON_RIGHT:
      n = selectIcon();
      if(n > -1)
        edit_panel.image_index = n;
      /*
         edit_panel.image_index++;
         if(edit_panel.image_index >= image_count) {
         edit_panel.image_index = 0;
         }
       */
      drawMap();
      break;
    default:
      break;
    }
    break;
  case SDL_KEYDOWN:
    //  printf("The %s key was pressed! scan=%d\n", SDL_GetKeyName(event->key.keysym.sym), event->key.keysym.scancode);
    switch (event->key.keysym.sym) {

    case SDLK_DOWN:
      cursor.pos_y++;
      if(cursor.pos_y >= map.h)
        cursor.pos_y = map.h - 1;
      cursor.dir = DIR_NONE;
      map.redraw = 1;
      break;
    case SDLK_UP:
      cursor.pos_y--;
      if(cursor.pos_y < 0)
        cursor.pos_y = 0;
      cursor.dir = DIR_NONE;
      map.redraw = 1;
      break;
    case SDLK_RIGHT:
      cursor.pos_x++;
      if(cursor.pos_x >= map.w)
        cursor.pos_x = map.w - 1;
      cursor.dir = DIR_NONE;
      map.redraw = 1;
      break;
    case SDLK_LEFT:
      cursor.pos_x--;
      if(cursor.pos_x < 0)
        cursor.pos_x = 0;
      cursor.dir = DIR_NONE;
      map.redraw = 1;
      break;

      /*
         case SDLK_LEFT: 
         cursor.dir = DIR_LEFT;
         break;
         case SDLK_RIGHT: 
         cursor.dir = DIR_RIGHT;
         break;
         case SDLK_UP: 
         cursor.dir = DIR_UP;
         break;
         case SDLK_DOWN: 
         cursor.dir = DIR_DOWN;
         break;
       */
    case SDLK_PAGEDOWN:
      cursor.pos_y += screen->h / TILE_H;
      if(cursor.pos_y >= map.h)
        cursor.pos_y = map.h - 1;
      cursor.dir = DIR_NONE;
      map.redraw = 1;
      break;
    case SDLK_PAGEUP:
      cursor.pos_y -= screen->h / TILE_H;
      if(cursor.pos_y < 0)
        cursor.pos_y = 0;
      cursor.dir = DIR_NONE;
      map.redraw = 1;
      break;
    case SDLK_END:
      cursor.pos_x += screen->w / TILE_W;
      if(cursor.pos_x >= map.w)
        cursor.pos_x = map.w - 1;
      cursor.dir = DIR_NONE;
      map.redraw = 1;
      break;
    case SDLK_HOME:
      cursor.pos_x -= screen->w / TILE_H;
      if(cursor.pos_x < 0)
        cursor.pos_x = 0;
      cursor.dir = DIR_NONE;
      map.redraw = 1;
      break;
    case SDLK_RETURN:
      setImage(edit_panel.level, edit_panel.image_index);
      break;
    case SDLK_i:
      n = selectIcon();
      if(n > -1)
        edit_panel.image_index = n;
      drawMap();
      break;
    case SDLK_DELETE:
    case SDLK_BACKSPACE:
      setImage(edit_panel.level, EMPTY_MAP);
      break;
    case SDLK_1:
      edit_panel.level = LEVEL_BACK;
      drawMap();
      break;
    case SDLK_2:
      edit_panel.level = LEVEL_MAIN;
      drawMap();
      break;
    case SDLK_3:
      edit_panel.level = LEVEL_FORE;
      drawMap();
      break;
    case SDLK_5:
      edit_panel.image_index--;
      if(edit_panel.image_index < 0) {
        edit_panel.image_index = image_count - 1;
      }
      drawMap();
      break;
    case SDLK_6:
      edit_panel.image_index++;
      if(edit_panel.image_index >= image_count) {
        edit_panel.image_index = 0;
      }
      drawMap();
      break;
    case SDLK_7:
      edit_panel.image_index = 0;
      drawMap();
      break;
    case SDLK_l:
      loadMap(1);
      break;
    case SDLK_m:
      makeMap();
      break;
    case SDLK_s:
      saveMap();
      break;
    case SDLK_ESCAPE:
      map.quit = 1;
      break;
    case SDLK_q:
      slide_start_x = map.top_left_x + editor_cursor.pos_x;
      slide_start_y = map.top_left_y + editor_cursor.pos_y;
      showMapStatus("slide started");
      break;
    case SDLK_w:
      if(slide_start_x > -1 && slide_start_y > -1) {
        drawSlide(slide_start_x, slide_start_y,
                  map.top_left_x + editor_cursor.pos_x,
                  map.top_left_y + editor_cursor.pos_y);
      } else {
        showMapStatus("press q first!");
      }
      break;
    case SDLK_e:
      if(slide_start_x > -1 && slide_start_y > -1) {
        drawRect(slide_start_x, slide_start_y,
                 map.top_left_x + editor_cursor.pos_x,
                 map.top_left_y + editor_cursor.pos_y);
      } else {
        showMapStatus("press q first!");
      }
      break;
    default:
      break;
    }
    break;
  case SDL_KEYUP:
    //printf("The %s key was released! scan=%d\n", SDL_GetKeyName(event->key.keysym.sym), event->key.keysym.scancode);
    cursor.dir = DIR_NONE;
    break;
  }
}

void
drawEditPanel()
{
  SDL_Rect rect;
  int level;
  char s[80];

  rect.x = 0;
  rect.y = 0;
  rect.w = edit_panel.image->w;
  rect.h = edit_panel.image->h;
  SDL_FillRect(edit_panel.image, &rect,
               SDL_MapRGBA(screen->format, 0x2, 0x0, 0x0, 0x0));

  rect.x = 0;
  rect.y = 0;
  rect.w = edit_panel.image->w;
  rect.h = 5;
  SDL_FillRect(edit_panel.image, &rect,
               SDL_MapRGBA(screen->format, 0x00, 0x00, 0x90, 0x00));


  // draw which level is being drawn
  for(level = LEVEL_BACK; level < LEVEL_COUNT; level++) {
    rect.x = 10 + (level * 40);
    rect.y = 10;
    rect.w = 20;
    rect.h = 20;
    SDL_FillRect(edit_panel.image, &rect,
                 (level == edit_panel.level ?
                  SDL_MapRGBA(screen->format, 0xff, 0x00, 0x00, 0x00) :
                  SDL_MapRGBA(screen->format, 0xff, 0xff, 0xff, 0x00)));
  }

  // draw which image is used
  rect.x = 200;
  rect.y = 10;
  rect.w = images[edit_panel.image_index]->image->w;
  rect.h = images[edit_panel.image_index]->image->h;
  SDL_BlitSurface(images[edit_panel.image_index]->image, NULL,
                  edit_panel.image, &rect);

  // draw some instructions
  drawString(edit_panel.image, 10, 35, "change level 123");
  drawString(edit_panel.image, 10, 35 + FONT_HEIGHT, "change image 567");
  drawString(edit_panel.image, 10, 35 + FONT_HEIGHT * 2, "slide  q  w");
  drawString(edit_panel.image, 400, 5, "editor");
  drawString(edit_panel.image, 400, 5 + FONT_HEIGHT, "draw enter");
  drawString(edit_panel.image, 400, 5 + FONT_HEIGHT * 2, "erase del");


  // draw it on the screen
  rect.x = 0;
  rect.y = screen->h - edit_panel.image->h;
  rect.w = edit_panel.image->w;
  rect.h = edit_panel.image->h;
  SDL_BlitSurface(edit_panel.image, NULL, screen, &rect);
  //  SDL_Flip(screen);


  sprintf(s, "x%d y%d level%d dir%d", cursor.pos_x, cursor.pos_y,
          edit_panel.level, cursor.dir);
  drawString(screen, 5, 5, s);
  sprintf(s, "spx%d spy%d px%d py%d", cursor.speed_x, cursor.speed_y,
          cursor.pixel_x, cursor.pixel_y);
  drawString(screen, 5, 5 + FONT_HEIGHT, s);
  sprintf(s, "mouse x%d y%d", editor_cursor.pos_x, editor_cursor.pos_y);
  drawString(screen, 5, 5 + FONT_HEIGHT * 2, s);
}

void
resetEditPanel()
{
  edit_panel.level = LEVEL_MAIN;
  edit_panel.image_index = 0;
}

void
initEditor()
{
  //  map = NULL;
  if(!(edit_panel.image = SDL_CreateRGBSurface(SDL_HWSURFACE,
                                               screen->w, EDIT_PANEL_HEIGHT,
                                               screen->format->BitsPerPixel,
                                               0, 0, 0, 0))) {
    fprintf(stderr, "Error creating surface: %s\n", SDL_GetError());
    fflush(stderr);
    return;
  }
  editor_cursor.pos_x = editor_cursor.pos_y = 0;
  make_map = 0;
}

void
editMap()
{
  int i, x, y;
  int step_x, step_y;
  Image *img;

  resetMap();

  // set our painting events
  map.beforeDrawToScreen = beforeDrawToScreen;
  map.afterScreenFlipped = editorAfterScreenFlipped;

  // our event handling
  map.handleMapEvent = editorMainLoop;

  // add some tiles in the background
  img = images[img_back];
  step_x = img->image->w / TILE_W;
  step_y = img->image->h / TILE_H;
  for(y = 0; y < map.h; y += step_y) {
    for(x = 0; x < map.w; x += step_x) {
      i = x + (y * map.w);
      map.image_index[LEVEL_BACK][i] = img_back;
      // make a border
      if(y == 0 || y == map.h - 4 || x == 0 || x == map.w - 4) {
        map.image_index[LEVEL_MAIN][i] = img_rock;
      }
    }
  }

  // reset the cursor
  resetCursor();

  // initialize the edit panel
  resetEditPanel();

  // try to load an existing map
  loadMap(0);
  drawMap();

  // start the map's main loop
  moveMap();
}
