#include <stdarg.h>
#include <stdio.h>
#include "defs.h"
#include "display.h"
#include "world.h"
#include "city.h"
#include "trans.h"
#include "units.h"
#include "player.h"

// -1 if no cursor, 0 if cursor state is inverted
// 1 is cursor state is piece shown
static int cursorOn = -1;
int WDisplay::white;

WDisplay::WDisplay(World *world)
{
  maxX = world->MaxX();
  maxY = world->MaxY();
  left = top = 0;
  where = SHOWING_MAP;
}

void WDisplay::AllocColors()
{
  white = screen->AllocColor("#ffffffffffff");
}

WDisplay::~WDisplay()
{
  DisableCursor();
}

void WDisplay::Message(int color, char *format, ...)
{
  char str[256];
  va_list ap;
  va_start(ap, format);
  vsprintf(str, format, ap);
  va_end(ap);
  screen->DisplayMessage(str, color);
}

void WDisplay::ShowPlayerInfo()
{
  if (where != SHOWING_MAP) return;
  int y = 64+VertSpace+2;
  Player *p = players[playerId];
  screen->FillRect(0, y, HorizSpace-1, 30, City::black);
  screen->DrawPixmap(0, y+1, City::hMoney);
  screen->WriteInt(8, y, p->money, 5, City::white);
  if (p->researching != NULL)
    screen->WriteStr(0, y+10, p->researching, City::white);
  screen->WriteInt(0, y+20, p->tax/10, 2, City::white);
  screen->DrawPixmap(22, y+21, City::hBulb);
  int per = (p->scienceAcc*100)/p->needScience;
  screen->WriteInt(30, y+20, per > 100 ? 100 : per, 3,
		   City::white);
  screen->WriteStr(54, y+20, "%", City::white);
}

void WDisplay::ShowMap()
{
  if (where != SHOWING_MAP) {
    screen->Clear();
    where = SHOWING_MAP;
    Update();
  }
}

void WDisplay::ShowCityInfo(class City *ptr)
{
  if (where != SHOWING_CITY || city != ptr) {
    where = SHOWING_CITY;
    city = ptr;
    Update();
  }
}

void WDisplay::Update()
{
  if (where == SHOWING_MAP) {
    ShowPlayerInfo();
    world->Draw(left, top);
    world->DrawMainMap();
  }
  else
    city->InfoScreen();
}

void WDisplay::Center(int wx, int wy)
{
  left = (wx-SquaresWide/2+maxX) % maxX;
  top = (wy-SquaresHigh/2+maxY) % maxY;
  Update();
}

void WDisplay::ShowPiece(int worldx, int worldy, ulong id)
{
  ShowMap();
  if (Visible(worldx, worldy)) {
    int sx, sy;
    TranslateScreen(worldx, worldy, sx, sy);
    if (sx >= 1 && sx < SquaresWide-1 && sy >= 1 && sy < SquaresHigh-1)
      return;
  }

  left = (worldx-SquaresWide/2+maxX) % maxX;
  top = (worldy-SquaresHigh/2+maxY) % maxY;

  Update();
}

void WDisplay::ShowCity(int worldx, int worldy, ulong id)
{
  ShowMap();
  if (Visible(worldx, worldy)) {
    int sx, sy;
    TranslateScreen(worldx, worldy, sx, sy);
    if (sx >= 1 && sx < SquaresWide-1 && sy >= 1 && sy < SquaresHigh-1)
      return;
  }

  // center the city on the screen
  left = (worldx-SquaresWide/2+maxX) % maxX;
  top = (worldy-SquaresHigh/2+maxY) % maxY;

  Update();
}

void WDisplay::BlitMap(int x1, int y1, int w, int h, int x2, int y2)
{
  screen->BitBlt(x1*SquareWidth+HorizSpace, y1*SquareHeight+VertSpace,
		 w*SquareWidth, h*SquareHeight,
		 x2*SquareWidth+HorizSpace, y2*SquareHeight+VertSpace);
}

void WDisplay::ScrollUp()
{
  top = (top+maxY-1) % maxY;
  BlitMap(0, 0, SquaresWide, SquaresHigh-1, 0, 1);
  world->Draw(left, top, SquaresWide, 1, 0, 0);
}

void WDisplay::ScrollDown()
{
  BlitMap(0, 1, SquaresWide, SquaresHigh-1, 0, 0);
  world->Draw(left, top + SquaresHigh, SquaresWide, 1, 0, SquaresHigh-1);
  top = (top+1) % maxY;
}

void WDisplay::ScrollLeft()
{
  left = (left+maxX-1) % maxX;
  BlitMap(0, 0, SquaresWide-1, SquaresHigh, 1, 0);
  world->Draw(left, top, 1, SquaresHigh, 0, 0);
}

void WDisplay::ScrollRight()
{
  BlitMap(1, 0, SquaresWide-1, SquaresHigh, 0, 0);
  world->Draw(left + SquaresWide, top, 1, SquaresHigh, SquaresWide-1, 0);
  left = (left+1) % maxX;
}

void WDisplay::TranslateScreen(int worldx, int worldy,
			      int &screenx, int &screeny)
{
  screenx = (worldx - left + world->MaxX()) % world->MaxX();
  screeny = (worldy - top + world->MaxY()) % world->MaxY();
}

void WDisplay::TranslateWorld(int screenx, int screeny,
			     int &worldx, int &worldy)
{
  worldx = (left + screenx) % world->MaxX();
  worldy = (top + screeny) % world->MaxY();
}

void WDisplay::EnableCursor(int worldx, int worldy, ulong id)
{
  ShowPiece(worldx, worldy, id);
  if (cursorOn != -1) DisableCursor();
  cursorx = worldx;
  cursory = worldy;
  cursorUnit = trans->TransUnit(id);
  TranslateScreen(cursorx, cursory, cursorsx, cursorsy);
  world->DrawBase(cursorx, cursory, cursorsx, cursorsy);
  cursorOn = 0;
  screen->StartTimer(CURSOR_TIMER, 500, DisplayCursor);
}

void WDisplay::DisableCursor()
{
  if (cursorOn == -1) return;
  screen->StopTimer(CURSOR_TIMER);
  if (cursorOn == 0)
    world->Draw(cursorx, cursory, 1, 1, cursorsx, cursorsy);
  else
    world->MarkSquare(cursorx, cursory, -1);
  cursorOn = -1;
}

// true if position is on the screen
int WDisplay::Visible(int worldx, int worldy)
{
  if (where != SHOWING_MAP) return 0;
  int right = (left+SquaresWide-1) % world->MaxX();
  if ((right > left && (worldx < left || worldx > right)) ||
      (right < left && (worldx > right && worldx < left)))
    return 0;
  int bot = (top+SquaresHigh-1) % world->MaxY();
  if (((bot > top) && (worldy < top || worldy > bot)) ||
      (bot < top) && (worldy > bot && worldy < top))
    return 0;
  return 1;
}

void DisplayCursor(int timer)
{
  if (cursorOn == -1) return;
  if (cursorOn == 0) {
    world->DrawBase(display->cursorx, display->cursory,
		    display->cursorsx, display->cursorsy);
    display->cursorUnit->Draw(display->cursorsx*SquareWidth+HorizSpace,
			      display->cursorsy*SquareHeight+VertSpace);
    world->MarkSquare(display->cursorx, display->cursory, display->white);
  }
  else {
    world->DrawBase(display->cursorx, display->cursory,
		    display->cursorsx, display->cursorsy);
    world->MarkSquare(display->cursorx, display->cursory, -1);
  }
  cursorOn ^= 1;
}
