#include <objgfx40/ogFont.h>
#include <objgfx40/objgfx40.h>

extern "C" {
  #include <string.h>
#ifdef __UBIXOS_KERNEL__
  #include <vfs/file.h>
#else
  #include <stdlib.h>
  #include <stdio.h>
#endif
  }

using namespace std;
typedef
  struct {
    char  ID[3];
    uInt8 version;
    uInt8 width, height;
    uInt8 numOfChars;
    uInt8 startingChar;
    uInt8 colourType;
    uInt8 paddington[7];
  } ogDPFHeader;

static 
bool
fileExists(const char *file)
{
#ifdef __UBIXOS_KERNEL__
  fileDescriptor *f = fopen(file, "rb");
#else
  FILE *f = fopen(file, "rb");
#endif
  if (!f)
    return false;
  fclose(f);
  return true;
}

ogBitFont::ogBitFont(void) {
#ifdef __UBIXOS_KERNEL__
  kmemset(fontDataIdx, 0, sizeof(fontDataIdx));
  kmemset(charWidthTable, 0, sizeof(charWidthTable));
  kmemset(charHeightTable, 0, sizeof(charHeightTable));
#else
  memset(fontDataIdx, 0, sizeof(fontDataIdx));
  memset(charWidthTable, 0, sizeof(charWidthTable));
  memset(charHeightTable, 0, sizeof(charHeightTable));
#endif

  fontData = NULL;
  fontDataSize = 0;
  numOfChars = 0;
  width = height = startingChar = 0;

  BGColour.red   = 0;
  BGColour.green = 0;
  BGColour.blue  = 0;
  BGColour.alpha = 0;
  
  FGColour.red   = 255;
  FGColour.green = 255;
  FGColour.blue  = 255;
  FGColour.alpha = 255;

  return;
} // ogBitFont::ogBitFont

void
ogBitFont::SetBGColor(uInt32 red, uInt32 green, uInt32 blue, uInt32 alpha) {
  BGColour.red   = red;
  BGColour.green = green;
  BGColour.blue  = blue;
  BGColour.alpha = alpha;
  return;
} // ogBitFont::SetBGColor

void
ogBitFont::SetFGColor(uInt32 red, uInt32 green, uInt32 blue, uInt32 alpha) {
  FGColour.red   = red;
  FGColour.green = green;
  FGColour.blue  = blue;
  FGColour.alpha = alpha;
  return;
} // ogBitFont::SetFGColor

ogBitFont::~ogBitFont(void) {
#ifdef __UBIXOS_KERNEL__
  kmemset(fontDataIdx, 0, sizeof(fontDataIdx));
  kmemset(charWidthTable, 0, sizeof(charWidthTable));
  kmemset(charHeightTable, 0, sizeof(charHeightTable));
#else
  memset(fontDataIdx, 0, sizeof(fontDataIdx));
  memset(charWidthTable, 0, sizeof(charWidthTable));
  memset(charHeightTable, 0, sizeof(charHeightTable));
#endif
  delete [] fontData;
  fontData = NULL;
  fontDataSize = 0;
  width = height = startingChar = 0;
  return;
} // ogBitFont::~ogBitFont;

void 
ogBitFont::CenterTextX(ogSurface& dest, int32 y, const char * textString) {
  int32 x;
  x = ((dest.ogGetMaxX()+1) - TextWidth(textString)) / 2;
  PutString(dest, x, y, textString);
  return;
} // ogBitFont::CenterTextX

void 
ogBitFont::JustifyText(ogSurface& dest, ogTextAlign horiz, ogTextAlign vert, 
                       const char * textString) {
  uInt32 x, y;

  switch (horiz) {
   case leftText:
    x = 0;
    break;
   case centerText:
    x = ((dest.ogGetMaxX())-TextWidth(textString)) / 2;
    break;
   case rightText:
    x = (dest.ogGetMaxX())-TextWidth(textString);
    break;
   default:
    return;
  } // switch

  switch (vert) {
   case topText:
    y = 0; 
    break;
   case centerText:
    y = ((dest.ogGetMaxY())-TextHeight(textString)) / 2;
    break;
   case bottomText:
    y = (dest.ogGetMaxY())-TextHeight(textString);
   default: 
    return;
  } // switch

  PutString(dest, x, y, textString);
  return;
} // ogBitFont::JustifyText

bool 
ogBitFont::Load(const char* fontFile, uInt32 offset = 0) {
#ifdef __UBIXOS_KERNEL__
  fileDescriptor * infile;
#else
  FILE * infile;
#endif
  ogDPFHeader header;
  uInt32 lresult, size;

  if (!fileExists(fontFile)) return false;

  delete [] fontData;

  infile = fopen(fontFile, "rb");
  fseek(infile, offset, SEEK_SET);
  lresult = fread(&header, sizeof(header), 1, infile);
  width = header.width;
  height = header.height;
  numOfChars = header.numOfChars;
  if (numOfChars == 0) numOfChars = 256;
  startingChar = header.startingChar;

#ifdef __UBIXOS_KERNEL__
  kmemset(fontDataIdx, 0, sizeof(fontDataIdx));
  kmemset(charWidthTable, 0, sizeof(charWidthTable));
  kmemset(charHeightTable, 0, sizeof(charHeightTable));
#else
  memset(fontDataIdx, 0, sizeof(fontDataIdx));
  memset(charWidthTable, 0, sizeof(charWidthTable));
  memset(charHeightTable, 0, sizeof(charHeightTable));
#endif
  
  size = (((uInt32)width+7) / 8)*(uInt32)height;
  fontDataSize = size* (uInt32)numOfChars;

  for (int32 tmp = startingChar; tmp <= startingChar+numOfChars-1; tmp++) {
    charWidthTable[tmp] = width;
    charHeightTable[tmp] = height;
    fontDataIdx[tmp] = (size*(tmp-startingChar));
  } // for tmp

  fontData = new uInt8[fontDataSize];

  lresult = fread(fontData, 1, fontDataSize, infile);

  fclose(infile);
  return true;
} // ogBitFont::Load

/*
bool 
ogFont::LoadFrom(const char* FontFile, uInt32 Offset) {
  return true;
} // ogFont::LoadFrom


bool 
ogFont::Save(const char* FontFile) {
  return saveTo(FontFile,0);
} // ogFont::Save
*/

uInt32 
ogBitFont::TextHeight(const char * textString) {
  uInt32 size, tmpsize;
  size = 0;
  const unsigned char * text = (const unsigned char *)textString;

  if (text != NULL)
    while (*text) {
      tmpsize = charHeightTable[*text++];
      if (tmpsize>size) size = tmpsize;
    } // while

  return size;
} // ogBitFont::TextHeight

uInt32
ogBitFont::TextWidth(const char * textString) {
  uInt32 size = 0;
  const unsigned char * text = (const unsigned char *)textString;

  if (text != NULL)
    while (*text) 
      size += charWidthTable[*text++];
  return size;
} // ogBitFont::TextWidth

/*
bool 
ogBitFont::SaveTo(const char * fontFile, int32 offset) {
  return true;
} // TDPFont::SaveTo
*/

void 
ogBitFont::PutChar(ogSurface& dest, int32 x, int32 y, const char ch) {

  uInt32 xx, xCount, yCount;
  uInt32 BGC, FGC, tColour;
  uInt8 * offset;
  uInt8 bits = 0;
  const unsigned char c = (const unsigned char)ch;

  if (fontData == NULL) return;
  if (!dest.ogAvail()) return;
 
  if (charWidthTable[c]  != 0) {
    BGC = dest.ogPack(BGColour.red, 
                      BGColour.green, 
                      BGColour.blue, 
                      BGColour.alpha); 

    BGC &= dest.ogGetAlphaMasker();

    tColour = dest.ogGetTransparentColor();

    FGC = dest.ogPack(FGColour.red, 
                      FGColour.green, 
                      FGColour.blue, 
                      FGColour.alpha); 
   
    offset = fontData;
    offset += fontDataIdx[c];

    for (yCount = 0; yCount < height; yCount++) {
      xCount = charWidthTable[c];
      xx = 0;

      do {
        if ((xx & 7) == 0) bits = *(offset++);
        if ((bits & 128) != 0)
          dest.ogSetPixel(x + xx, y+yCount , FGColour.red, FGColour.green, 
                          FGColour.blue, FGColour.alpha); 
        else
          if (BGC != tColour)
           dest.ogSetPixel(x + xx, y+yCount, BGC);

        bits += bits;
        ++xx;
      } while (--xCount);
    } // for yCount
  } // if
  return;
} // ogBitFont::PutChar

void
ogBitFont::PutString(ogSurface& dest, int32 x, int32 y, 
                     const char *textString) {

  const unsigned char *text;
  unsigned char ch;

  if (textString == NULL) return;
#ifdef __UBIXOS_KERNEL__
  if (0 == kstrlen(textString)) return;
#else
  if (0 == strlen(textString)) return;
#endif
  if (!dest.ogAvail()) return;

  text = (const unsigned char *)textString;

  while ((ch = *text++) != 0) {
    PutChar(dest, x, y, ch);
    x += charWidthTable[ch];
  } // while
  
  return;
} // ogBitFont::PutString
