/*
     PLIB - A Suite of Portable Game Libraries
     Copyright (C) 1998,2002  Steve Baker
 
     This library is free software; you can redistribute it and/or
     modify it under the terms of the GNU Library General Public
     License as published by the Free Software Foundation; either
     version 2 of the License, or (at your option) any later version.
 
     This library is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     Library General Public License for more details.
 
     You should have received a copy of the GNU Library General Public
     License along with this library; if not, write to the Free Software
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 
     For further information visit http://plib.sourceforge.net

     $Id: fnt.cxx 1939 2004-08-05 00:41:53Z puggles $
*/

#include "fntLocal.h"

#include <simgear/misc/sg_path.hxx>
#include <simgear/debug/logstream.hxx>

fntFont:: fntFont () {}
fntFont::~fntFont () {}

int fntTexFont::load ( const SGPath& path, GLenum mag, GLenum min )
{
  if (path.extension() == "txf") {
    return loadTXF ( path, mag, min ) ;
  } else {
    const auto ps = path.utf8Str();
    fntSetError ( SG_WARN,
      "fnt::load: Error - Unrecognised file format for '%s'", ps.c_str() ) ;
    return FNT_FALSE ;
  }
}

float fntTexFont::low_putch ( sgVec3 curpos, float pointsize,
                               float italic, char c )
{
  unsigned int cc = (unsigned char) c ;

  /* Auto case-convert if character is absent from font. */

  if ( ! exists [ cc ] )
  {
    if ( cc >= 'A' && cc <= 'Z' )
      cc = cc - 'A' + 'a' ;
    else
    if ( cc >= 'a' && cc <= 'z' )
      cc = cc - 'a' + 'A' ;

    if ( cc == ' ' )
    {
      curpos [ 0 ] += pointsize / 2.0f ;
      return pointsize / 2.0f ;
    }
  }

  /*
    We might want to consider making some absent characters from
    others (if they exist): lowercase 'l' could be made into digit '1'
    or letter 'O' into digit '0'...or vice versa. We could also
    make 'b', 'd', 'p' and 'q' by mirror-imaging - this would
    save a little more texture memory in some fonts.
  */

  if ( ! exists [ cc ] )
    return 0.0f ;
  
  glBegin ( GL_TRIANGLE_STRIP ) ;
    glTexCoord2f ( t_left [cc], t_bot[cc] ) ;
    glVertex3f   ( curpos[0] +          v_left [cc] * pointsize,
                   curpos[1] +          v_bot  [cc] * pointsize,
                   curpos[2] ) ;

    glTexCoord2f ( t_left [cc], t_top[cc] ) ;
    glVertex3f   ( curpos[0] + (italic + v_left [cc]) * pointsize,
                   curpos[1] +           v_top  [cc]  * pointsize,
                   curpos[2] ) ;

    glTexCoord2f ( t_right[cc], t_bot[cc] ) ;
    glVertex3f   ( curpos[0] +          v_right[cc] * pointsize,
                   curpos[1] +          v_bot  [cc] * pointsize,
                   curpos[2] ) ;

    glTexCoord2f ( t_right[cc], t_top[cc] ) ;
    glVertex3f   ( curpos[0] + (italic + v_right[cc]) * pointsize,
                   curpos[1] +           v_top  [cc]  * pointsize,
                   curpos[2] ) ;
  glEnd () ;

  float ww = ( gap + ( fixed_pitch ? width : widths[cc] ) ) * pointsize ;
  curpos[0] += ww ;
  return ww ;
}



void fntTexFont::setGlyph ( char c, float wid,
        float tex_left, float tex_right,
        float tex_bot , float tex_top  ,
        float vtx_left, float vtx_right,
        float vtx_bot , float vtx_top  )
{
  unsigned int cc = (unsigned char) c ;

  exists[cc] = FNT_TRUE ;

  widths[cc] = wid;

  t_left[cc] = tex_left ; t_right[cc] = tex_right ;
  t_bot [cc] = tex_bot  ; t_top  [cc] = tex_top   ;

  v_left[cc] = vtx_left ; v_right[cc] = vtx_right ;
  v_bot [cc] = vtx_bot  ; v_top  [cc] = vtx_top   ;
}


int fntTexFont::getGlyph ( char c, float* wid,
        float *tex_left, float *tex_right,
        float *tex_bot , float *tex_top  ,
        float *vtx_left, float *vtx_right,
        float *vtx_bot , float *vtx_top  )
{
  unsigned int cc = (unsigned char) c ;

  if ( ! exists[cc] ) return FNT_FALSE ;

  if ( wid       != NULL ) *wid       = widths [cc] ;

  if ( tex_left  != NULL ) *tex_left  = t_left [cc] ;
  if ( tex_right != NULL ) *tex_right = t_right[cc] ;
  if ( tex_bot   != NULL ) *tex_bot   = t_bot  [cc] ;
  if ( tex_top   != NULL ) *tex_top   = t_top  [cc] ;

  if ( vtx_left  != NULL ) *vtx_left  = v_left [cc] ;
  if ( vtx_right != NULL ) *vtx_right = v_right[cc] ;
  if ( vtx_bot   != NULL ) *vtx_bot   = v_bot  [cc] ;
  if ( vtx_top   != NULL ) *vtx_top   = v_top  [cc] ;

  return FNT_TRUE ;
}


void fntTexFont::getBBox ( const char *s,
                           float pointsize, float italic,
                           float *left, float *right,
                           float *bot , float *top  )
{
  float h_pos = 0.0f ;
  float v_pos = 0.0f ;
  float l, r, b, t ;

  l = r = b = t = 0.0f ;

  while ( *s != '\0' )
  {
    if ( *s == '\n' )
    {
      h_pos = 0.0f ;
      v_pos -= 1.333f ;
      s++ ;
      continue ;
    }

    unsigned int cc = (unsigned char) *(s++) ;

    if ( ! exists [ cc ] )
    {
      if ( cc >= 'A' && cc <= 'Z' )
        cc = cc - 'A' + 'a' ;
      else
      if ( cc >= 'a' && cc <= 'z' )
        cc = cc - 'a' + 'A' ;
  
      if ( cc == ' ' )
      {
        r += 0.5f ;
        h_pos += 0.5f ;

        continue ;
      }
    }

    if ( ! exists [ cc ] )
      continue ;

    if ( italic >= 0 )
    {
      if ( l >       h_pos + v_left [cc]        ) l =       h_pos + v_left [cc]          ;
      if ( r < gap + h_pos + v_right[cc]+italic ) r = gap + h_pos + v_right[cc] + italic ;
    }
    else
    {
      if ( l >       h_pos + v_left [cc]+italic ) l =       h_pos + v_left [cc] + italic ;
      if ( r < gap + h_pos + v_right[cc] )        r = gap + h_pos + v_right[cc]          ;
    }

    
    if ( b > v_pos + v_bot [cc] ) b = v_pos + v_bot [cc] ;
    if ( t < v_pos + v_top [cc] ) t = v_pos + v_top [cc] ;

    h_pos += gap + ( fixed_pitch ? width : widths[cc] ) ;
  }

  if ( left  != NULL ) *left  = l * pointsize ;
  if ( right != NULL ) *right = r * pointsize ;
  if ( top   != NULL ) *top   = t * pointsize ;
  if ( bot   != NULL ) *bot   = b * pointsize ;
}


void fntTexFont::puts ( sgVec3 curpos, float pointsize, float italic, const char *s )
{
  SGfloat origx = curpos[0] ;
    
  if ( ! bound )
    bind_texture () ;

  while ( *s != '\0' )
  {
    if (*s == '\n')
    {
      curpos[0]  = origx ;
      curpos[1] -= pointsize ;
    }
    else
      low_putch ( curpos, pointsize, italic, *s ) ;

    s++ ;
  }
}

void fntInit ()
{
  /* Empty right now */
}


void fntSetError(int level, const char* format, ...)
{
  const int bufferLength = 2048;
  char buffer[2048];
  va_list args;
  va_start (args, format);
  vsnprintf(buffer,bufferLength,format, args);
  va_end (args);

  SG_LOG(SG_GUI, static_cast<sgDebugPriority>(level), buffer);
}