#include "textDisplay.h"
#include "global.h"
#include "displays.h"
#include "graph.h"
#include "pixmaps.h"
#include <string.h>

// really should check the right edge for linebreaking purposes.

struct link {
  int x, y;
  int x2, y2;
  void *ret_data;
  void (*callback)(void *);
  int contains(int X, int Y)
    {return ((X > x) && (X < x2) && (Y > y) && (Y < y2));} 
};

TextDisplay::TextDisplay(int w, int h) : WDisplay(NULL) {
  width = w; height = h;
  SetTabs(0);
  x = 0; y = 0;
  lineHeight = LineHeight;
}

TextDisplay::~TextDisplay() {
  while (links)
    delete links.RemoveHead();
}

void TextDisplay::Setup() {
  CreateButtons();
  CreateDrawingArea(width, height, this);
}

static void textCloseHandler(TextDisplay *d) {
  delete d;
}

void TextDisplay::CreateButtons() {
  AddButton("Close", textCloseHandler, this);
}

TextDisplay &TextDisplay::WriteStr(char *str) {
  WriteStr(str, FontWidth*strlen(str));
  return *this;
}

TextDisplay &TextDisplay::WriteStr(char *str, int width) {
  WDisplay::WriteStr(x,y,str,white);
  x += width;
  return *this;
}

TextDisplay &TextDisplay::WriteInt(int i) {
  char str[20];
  sprintf(str, "%d", i);
  return WriteStr(str);
}

TextDisplay &TextDisplay::HyperStr(char *str, void (*callback)(void *), void *ret_data)
{
  link *l = new link;
  l->x = x; l->y = y;
  l->callback = callback; l->ret_data = ret_data;
  WriteStr(str);
  l->x2 = x; l->y2 = y+lineHeight;
  links.Insert(l);
  return *this;
}

void TextDisplay::GetEvent(EventType event, int x, int y, char */*data*/)
{
  if (event != MOUSE_LEFT)
    return;
  link *l;
  Lister<link *> linkl = links;
  while (linkl) {
    l = linkl.Elem();
    if (l->contains(x,y)) {
      l->callback(l->ret_data);
      return;
    }
    linkl.Next();
  }
}

TextDisplay &TextDisplay::DrawPixmap(CPixmap *handle, int ownerId) {
  int w,h;
  WDisplay::DrawPixmap(x, y, handle, ownerId);
  handle->GetInfo(w, h);
  x += w;
  if (h > lineHeight)
    lineHeight = h;
  return *this;
}

TextDisplay &TextDisplay::NewLine() {
  x = tabs[0];
  y += lineHeight;
  lineHeight = LineHeight;
  return *this;
}

TextDisplay &TextDisplay::VSpace(int size) {
  x = 0;
  y += size;
  return *this;
}

TextDisplay &TextDisplay::HSpace(int size) {
  x += size;
  return *this;
}

TextDisplay &TextDisplay::SetTabs(int t1, int t2, int t3, int t4, int t5) {
  tabs[0] = t1;
  tabs[1] = t2;
  tabs[2] = t3;
  tabs[3] = t4;
  tabs[4] = t5;
  return *this;
}

TextDisplay &TextDisplay::operator << (TextCode code)
{
  switch (code) {
  case NEWLINE:
    return NewLine();
  case TAB:
    return Tab();
  }
  return *this;
}

TextDisplay &TextDisplay::Tab() {
  int i;
  for (i = 0; i < 5; i++) {
    if (tabs[i] > x) {
      x = tabs[i];
      return *this;
    }
  }
  return NewLine();
}

void TextDisplay::Update()
{;}

ScreenCoord TextDisplay::TranslateScreen(MapCoord /*c*/)
{ return ScreenCoord(0,0);}
