#include "mapdisplay.h"
#include "global.h"
#include "world.h"
#include "displays.h"
#include "player.h"
#include "units.h"
#include "trans.h"
#include "city.h"
#include "keyboard.h"
#include "pixmaps.h"
#include <stdlib.h>

MapDisplay::MapDisplay() : WDisplay(NULL), topleft(0,0) {
  world = NULL;
  cursorOn = -1;
}

MapDisplay::MapDisplay(World *w, Player *p) : WDisplay(p), topleft(0,0) {
  world = w;
  cursorOn = -1;
}

MapDisplay::~MapDisplay() {;}

void acceptHandler(MapDisplay *disp) {
  disp->GetEvent(KEYBOARD, 'a', 0, NULL);
}

void MapDisplay::Setup() {
  CreateButtons();
  CreateMenus();
  CreateDrawingArea(ScreenWidth, ScreenHeight, this);
}

void commHandler(char *key, MapDisplay *disp) {
  disp->GetEvent(KEYBOARD, *key, 0, NULL);
}

void reportHandler(void *f, MapDisplay *disp) {
  void (*func)(Player *) = (void (*)(Player *))f;
  func(disp->GetPlayer());
}

void helpHandler(void *f, void *) {
  void (*func)() = (void (*)())f;
  func();
}

void MapDisplay::CreateButtons() {
  AddButton("Accept", acceptHandler, this);
}

void MapDisplay::CreateMenus() {
  AddMenu("Game", GameControlMenu, commHandler, this);
  AddMenu("Orders", OrderMenu, commHandler, this);
  AddMenu("Reports", ReportMenu, reportHandler, this);
  AddMenu("Help", HelpMenu, helpHandler, NULL);
};

void MapDisplay::Update()
{
  if (player != NULL) {
    ShowPlayerInfo();
    if (world != NULL) {
      world->Draw(this, topleft);
      world->DrawMainMap(this);
    }
  }
}

void MapDisplay::ShowPlayerInfo()
{
  int y = PlayerInfoY;
  FillRect(0, y, HorizSpace-1, 4*LineHeight, black);
  DrawPixmap(0, y, &money_pic);
  WriteInt(ResourceIconWidth, y, player->money, 5, white);
  WriteStr(0, y+LineHeight, Sciences[player->researching].name, white);
  y += 2*LineHeight;
  DrawPixmap(22, y, &bulb_pic);
  int per = (player->scienceAcc*100)/player->needScience;
  WriteInt(22+ResourceIconWidth, y, per > 100 ? 100 : per, 3, white);
  WriteStr(22+ResourceIconWidth+3*FontWidth, y, "%", white);

  y += LineHeight;
  char text[10];
  sprintf(text, "%2d/%2d/%2d", player->luxuries/10, player->tax/10, (100-player->luxuries-player->tax)/10);
  WriteStr(0, y, text, white);
}

void MapDisplay::Center(MapCoord c)
{
  topleft = c.left(SquaresWide/2).up(SquaresHigh/2);
  Update();
}

void MapDisplay::ShowPiece(MapCoord c, ulong /*id*/)
{
  if (Visible(c)) {
    ScreenCoord s = TranslateScreen(c);
    if (s.x >= 1 && s.x < SquaresWide-1 && s.y >= 1 && s.y < SquaresHigh-1)
      return;
  }
  Center(c);
}

void MapDisplay::ShowPieceInfo(Unit *u)
{
  int y = UnitInfoY;

  FillRect(0, y, HorizSpace-1, 4*LineHeight, black);
  WriteStr(0, y,Objects[u->Type()].name,white);
  WriteStr(0,y+LineHeight,u->Veteran() ? "Veteran" : "Green",white);
  if (u->cityId)
    WriteStr(0,y+2*LineHeight,trans->TransCity(u->cityId)->name,white);
  else
    WriteStr(0,y+2*LineHeight,"None",white);
  char n[5];
  sprintf(n,"%2.1f",u->numMoves);
  WriteStr(0,y+3*LineHeight,n,white);
}

void MapDisplay::ColorMainMap(MapCoord coord, int color)
{
  FillRect(coord.x*MainMapWidth/maxX, coord.y*MainMapHeight/maxY+VertSpace, 1, 1, color);
}

void MapDisplay::ScrollUp()
{
  topleft = topleft.up();
  BlitMap(0, 0, SquaresWide, SquaresHigh-1, 0, 1);
  world->Draw(this, topleft, SquaresWide, 1);
}

void MapDisplay::ScrollDown()
{
  BlitMap(0, 1, SquaresWide, SquaresHigh-1, 0, 0);
  world->Draw(this, topleft.down(SquaresHigh), SquaresWide, 1);
  topleft = topleft.down();
}

void MapDisplay::ScrollLeft()
{
  topleft = topleft.left();
  BlitMap(0, 0, SquaresWide-1, SquaresHigh, 1, 0);
  world->Draw(this, topleft, 1, SquaresHigh);
}

void MapDisplay::ScrollRight()
{
  BlitMap(1, 0, SquaresWide-1, SquaresHigh, 0, 0);
  world->Draw(this, topleft.right(SquaresWide), 1, SquaresHigh);
  topleft = topleft.right();
}

ScreenCoord MapDisplay::TranslateScreen(MapCoord coord)
{
  Offset delta = coord-topleft;
  return ScreenCoord(HorizSpace+SquareWidth*delta.x,VertSpace+SquareHeight*delta.y);
}

MapCoord MapDisplay::TranslateWorld(ScreenCoord coord)
{
  if ((coord.x > HorizSpace) && (coord.y > VertSpace)) // zoomed map
    return topleft.down((coord.y-VertSpace)/SquareHeight).right((coord.x-HorizSpace)/SquareWidth);

  else if ((coord.x < MainMapWidth) && (coord.y > VertSpace) // mainmap
	   && (coord.y < VertSpace+MainMapHeight))
    return MapCoord(coord.x*maxX/MainMapWidth,
		    (coord.y-VertSpace)*maxY/MainMapHeight);

  return topleft.down(SquaresHigh/2).right(SquaresWide/2); // off map
}

void CursorFunc(int, MapDisplay *display) {
  display->DisplayCursor();
}

void MapDisplay::EnableCursor(MapCoord coord, ulong id)
{
  ShowPiece(coord, id);
  cursorUnit = trans->TransUnit(id);
  ShowPieceInfo(cursorUnit);
  if (cursorOn != -1) DisableCursor();
  cursor = coord;
  cursorOn = 1;
  DisplayCursor();
  screen->StartTimer(CURSOR_TIMER, 500, CursorFunc, this);
}

void MapDisplay::DisableCursor()
{
  if (cursorOn == -1) return;
  screen->StopTimer(CURSOR_TIMER);
  if (cursorOn == 0)
    world->Draw(this, cursor, 1, 1);
  else
    world->MarkSquare(this, cursor, -1);
  cursorOn = -1;
}

// true if position is on the screen
int MapDisplay::Visible(MapCoord c)
{
  MapCoord bottomright = topleft.down(SquaresHigh-1).right(SquaresWide-1);
  int right = bottomright.x;
  int left = topleft.x;
  int top = topleft.y;
  int bottom = bottomright.y;
  if ((right > left && (c.x < left || c.x > right)) ||
      (right < left && (c.x > right && c.x < left)))
    return 0;
  if ((bottom > top && (c.y < top || c.y > bottom)) ||
      (bottom < top && (c.y > bottom && c.y < top)))
    return 0;
  return 1;
}

void MapDisplay::DisplayCursor()
{
  if (cursorOn == -1) return;
  if ((cursorOn == 0) || (state == IN_SELECT)) {
    world->DrawBase(this, cursor);
    cursorUnit->Draw(this);
    world->MarkSquare(this, cursor, white);
  }
  else {
    world->DrawBase(this, cursor);
    world->MarkSquare(this, cursor, -1);
  }
  cursorOn ^= 1;
}

void MapDisplay::GetEvent(EventType event, int x, int y, char *data)
{
  if (state == IN_SELECT)
    return;

  MapCoord coord = TranslateWorld(ScreenCoord(x,y));
  DisableCursor();
  if (event == MOUSE_RIGHT) { // right button, center the square
    /* int wx, wy;
      if (x >= HorizSpace || y < VertSpace || y >= VertSpace+64) {
      FixX(x);
      FixY(y);
      TranslateWorld(x, y, wx, wy);
      }
      else {
      y -= VertSpace;
      wx = (x*world->MaxX())/HorizSpace;
      wy = (y*world->MaxY())/64;
      }*/
    Center(coord);
  }
  else if (currTurn == player->id) {
    // moveturn

    if (player->doneMoving || player->initiatedSave)
      return;
    if (event == MOUSE_LEFT) {
      player->WakeUnits(coord);
    }
    else if (event == KEYBOARD) {
      int key = x;
      if (MovementKey(key))
	player->MoveCurrUnit(key);
      else if (key == 'h')
	player->currUnit->SetHomeCity(world->WhichCity(player->currUnit->coord));
      else if (key == 'n')
	player->NextUnit();
      else
	player->UnitOrders(key);

      player->CheckCurrUnit();
    }
  }
  else {
    // city turn

    if (event == MOUSE_LEFT) {
      /*FixX(x); FixY(y);
      int wx, wy;
      TranslateWorld(x, y, wx, wy);*/
      if (world->WhichCity(coord) != 0) {
	City *city = trans->TransCity(world->WhichCity(coord));
	if (city->ownerId == player->id)
	  city->Show();
      } 
    }
    else if (event == KEYBOARD) {
      if ((x == 'a') && (players[currTurn]->doneMoving))
	player->AcceptMoves();

      else if (x == 'S')
	player->InitiateSave();
      
      else if (MovementKey(x)) {
	int xinc = MoveXDir(x), yinc = MoveYDir(x);
	if (yinc < 0) ScrollUp();
	if (yinc > 0) ScrollDown();
	if (xinc < 0) ScrollLeft();
	if (xinc > 0) ScrollRight();
      }
    }
  }
  WDisplay::GetEvent(event,x,y,data);
  if (!player->doneMoving && currTurn == player->id && player->currUnit != NULL)
    EnableCursor(player->currUnit->coord, player->currUnit->id);
  Update();
}

void MapDisplay::SetWorld(World *W) {
  w = W;
  maxX = w->MaxX();
  maxY = w->MaxY();
}
