/*! \file newfont.cpp
    \brief Handling the fonts of ASC.

    The routines for displaying fonts can be found in #basegfx.cpp (function #showtext ).
    Although the file name contains is called newfont, the time when this was actually the case is long past (1993)...

*/

/*
    This file is part of Advanced Strategic Command; http://www.asc-hq.de
    Copyright (C) 1994-2005  Martin Bickel  and  Marc Schellenberger

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; see the file COPYING. If not, write to the 
    Free Software Foundation, Inc., 59 Temple Place, Suite 330, 
    Boston, MA  02111-1307  USA
*/

#include <cstring>
#include <stdio.h>
#include <errno.h>
#include <stdarg.h>
#include <stdlib.h>
#include <math.h>
#include "global.h"
#include "tpascal.inc"
#include "newfont.h"
#include "stack.h"
#include "basestrm.h"
#include "misc.h"
#include "basegfx.h"

#define blockread(a,b,c) fread(b,1,c,a)
#define seek(a,b) fseek(a,b,SEEK_SET)

const char* fontid = "I\'m a font file on your Disk. Leave me alone !\x01A\x0A0";

#define spacewidthkey 'n'

typedef dacpalette256 dacpal;

tfontsettings activefontsettings;

void expand(void* p1, void* q1, int size)
{
   char* src = (char*) p1;
   char* dst = (char*) q1;

   dst[0] = src[0];
   dst[1] = src[1];

   src+=2;
   dst+=2;

   while ( size ) {
      char al = *(src++);
      for ( int i = 0; i < 8; i++ )
         if ( size ) {
            if ( al & (1 << i ))
               dst[i] = 1;
            else
               dst[i] = 0;
   
            size--;
         }
      dst += 8;
   }
}


void toldfont::read ( tnstream& stream )
{
   stream.readdata ( &id, sizeof ( id ));
   stream.readdata ( &name, sizeof ( name ));
   number = stream.readChar();
   color = stream.readChar();
   for ( int i = 0; i < 256; ++i ) {
      character[i].width = stream.readChar();
      character[i].size = stream.readWord();
      character[i].diskposition = stream.readInt();
      character[i].memposition = (char*) stream.readInt();
      character[i].dummy = stream.readChar();
   }
   height = stream.readWord();
   for ( int i = 0; i < 256; ++i )
      kernchartable[i] = stream.readChar();
   for ( int i = 0; i < 101; ++i )
      for ( int j = 0; j < 101; ++j )
         kerning[i][j] = stream.readChar();

   dummy = stream.readWord();
   useems = stream.readChar();
   caps = stream.readChar();
   palette = (dacpalette256*) stream.readInt();
   groundline = stream.readChar();
}

pfont        loadfont( pnstream stream )
{
   toldfont     *font1;
   char *p;
   void         *q;
   int      ll, ll2;
   int i;

   font1 = new toldfont;
   font1->read ( *stream );

   font1->id[47] = 0;

   if ( strncmp(font1->id,fontid, 46) )
      return (NULL);

   font1->useems = false;
   font1->palette = NULL;

   for (i = 0; i <= 255; i++) {
      if ( font1->character[i].size ) {
         ll2 = ( font1->character[i].size / 8 + 1) * 8;
         q = new char [ ll2+2 ];
         font1->character[i].memposition = (char*) q;

         if (font1->color == false) {
            ll = font1->character[i].size / 8 + 1;
            p = new char [ ll + 2 ];

            *((Uint16*)p) = stream->readWord();

            stream->readdata ( p +2, ll );
            expand( p, q, font1->character[i].size );
            delete[] p;
         } else {
            *((Uint16*)q) = stream->readWord();
            stream->readdata ( ((char*)q)+2, font1->character[i].size  );
         }

         Uint16* pg = (Uint16*) q;
         if (*pg != font1->character[i].size) {
            printf("invalid size of character %c\n",i);
         } /* endif */
         *pg = font1->character[i].width;
      } else {
        if (i == 32) {
           ll = font1->height * ( font1->character[spacewidthkey].width - 2 );
           p = new char [ ll+2 ];
           Uint16* pg = (Uint16*) p;
           memset(p,0,ll+2);
           *pg = font1->character[spacewidthkey].width - 2;
           font1->character[i].width = font1->character[spacewidthkey].width - 2;
           font1->character[i].size = ll;
           font1->character[i].memposition = (char*) p;
        } /* endif */
     }
   }


  if (font1->color) {
     if ( font1->palette ) {
        font1->palette = (dacpalette256*) new char [ sizeof ( dacpalette256 ) ];
        stream->readdata ( font1->palette, sizeof(dacpalette256));
     }
   } else
      font1->palette = NULL;



   pfont font2   = new ( tfont );
   font2->name   = strdup ( font1->name );
   font2->color  = font1->color;
   font2->caps   = font1->caps ;
   font2->height = font1->height;
   font2->groundline = font1->groundline;
   font2->palette    = font1->palette;
   for (i = 0; i < 256 ;i++ ) {
      font2->character[i].width     =  font1->character[i].width;    
      font2->character[i].size      =  font1->character[i].size;
      font2->character[i].memposition =font1->character[i].memposition;
      for (int j = 0; j < 256 ; j++ ) {
          font2->kerning[j][i] = font1->kerning[font1->kernchartable[i]] [font1->kernchartable[j]];
          if ( font2->kerning[j][i] > 10  ||  font2->kerning[j][i] < - 10 )
             printf("%c%c\n",i,j);
      }


   } /* endfor */


   delete font1 ;

   return font2;
}



void shrinkfont ( pfont font, int diff )
{
   if ( font ) 
      for (int i = 0; i < 256 ;i++ ) 
         if (font->character[i].size ) 
            for (int j = 0; j < 256 ; j++ ) 
               if (font->character[j].size ) 
                  font->kerning[i][j] += diff;

}

int gettextwdth ( const char* txt, pfont font )
{
   int i, result;

   result = 0;
   if (font == NULL)
      font = activefontsettings.font;
   if (font == NULL)
      return 0;

   i=0;
   while (txt[i] != 0) {
      if (font->character[txt[i]].size) {
         result +=2 + font->character[txt[i]].width;
         if ( txt[i+1] )                          //          if ((txt[i+1] != 0) && (txt[i+1] != ' ')) 
            result += font->kerning[txt[i+1]][txt[i]];
      } /* endif */
      i++;
   } /* endwhile */
   if (result > 2) {
      result -= 2;
   } else {
      result = 0;
   } /* endif */

   return result;
}


void         showtext3( const char *       txt,
                       int         xpos,
                       int         ypos)
{
   // collategraphicoperations cgo ( xpos, ypos, max ( activefontsettings.height, activefontsettings->font.height ),;

    char         *s, *s2, *s3;
    int         i, j,k;
    int         newx; 
    signed char  cnt;
    int         orgjus; 


   if (txt[0] == 0)
       return;
   npush( activefontsettings );
   s2 = new char [ 255 ];
   s  = new char [ 255 ];
   s3 = new char [ 255 ];
   s2[0] = 0;

   i = 0;
   cnt = 0; 
   do { 
      if (txt[i] != '~') {
         s2[cnt] = txt[i];
         cnt++;
         s2[cnt] = 0;
      } /* endif */
      i++;
   }  while ( txt[i] != 0 );

   cnt = -2;
   showtext2(s2,xpos,ypos); 
   i = 0;
   orgjus = activefontsettings.justify; 

   while ((txt[i] != '~') && (txt[i] != 0)) {
      i++;
   } /* endwhile */
   
   while (txt[i] != 0) {
      cnt+=2; 

      j = i + 1; 
      s[0] = 0;
      s3[0] = 0;
      k=0;
      activefontsettings.background = 255;

      while ((txt[j] != '~') && ( txt[j] != 0)) {
         s[k] = txt[j];
         k++;
         s[k] = 0;
         j++;
      } 

      if (s[0] != 0) {
         strncpy( s3, s2, k+i-cnt );
         s3[k+i-cnt]=0;
         if (orgjus == lefttext) { 
            newx = xpos + gettextwdth(s3, NULL) - gettextwdth(s,NULL);
         } 
         else 
            if (orgjus == centertext) { 
               newx = xpos + (activefontsettings.length - gettextwdth(s2, NULL)) / 2 + gettextwdth(s3,NULL) - gettextwdth(s,NULL) + 1;
            } 
            else 
               if (orgjus == righttext) { 
                  newx = xpos + 1 + (activefontsettings.length - gettextwdth(s2, NULL)) + gettextwdth(s3,NULL) - gettextwdth(s,NULL);
               } 
         activefontsettings.color = activefontsettings.markcolor; 
         activefontsettings.justify = lefttext; 
         showtext2(s,newx,ypos); 
      } 
      i = j + 1; 
      while ((txt[i] != '~') && (txt[i] != 0))
        i++;
   } 
   delete[] s3;
   delete[] s;
   delete[] s2;

   npop( activefontsettings );
} 






void         showtext3c( const char *       txt,
                       int         xpos,
                       int         ypos)
{
   // collategraphicoperations cgo;

    int         i, j,k;
    int         newx;
    int          cnt;
    int         orgjus; 


   npush( activefontsettings );
   char s2[1000];
   char s[1000];
   char s3[1000];
   s2[0] = 0;

   i = 0;
   cnt = 0; 
   while ( txt[i] ) { 
      if (txt[i] != '~') {
         s2[cnt] = txt[i];
         cnt++;
         s2[cnt] = 0;
      } /* endif */
      i++;
   } 

   cnt = -2;
   showtext2c(s2,xpos,ypos); 
   i = 0;
   orgjus = activefontsettings.justify; 

   while ((txt[i] != '~') && (txt[i] )) 
      i++;
   
   while ( txt[i] ) {
      cnt+=2; 

      j = i + 1; 
      s[0] = 0;
      s3[0] = 0;
      k=0;
      activefontsettings.background = 255;

      while ((txt[j] != '~') && ( txt[j] != 0)) {
         s[k] = txt[j];
         k++;
         s[k] = 0;
         j++;
      } 

      if (s[0] != 0) {
         strncpy( s3, s2, k+i-cnt );
         s3[k+i-cnt]=0;
         if (orgjus == lefttext) { 
            newx = xpos + gettextwdth(s3, NULL) - gettextwdth(s,NULL);
         } 
         else 
            if (orgjus == centertext) { 
               newx = xpos + (activefontsettings.length - gettextwdth(s2, NULL)) / 2 + gettextwdth(s3,NULL) - gettextwdth(s,NULL) + 1;
            } 
            else 
               if (orgjus == righttext) { 
                  newx = xpos + 1 + (activefontsettings.length - gettextwdth(s2, NULL)) + gettextwdth(s3,NULL) - gettextwdth(s,NULL);
               } 
         activefontsettings.font = activefontsettings.markfont; 
         activefontsettings.justify = lefttext; 
         showtext2c(s,newx,ypos); 
      } 
      i = j + 1;
      while ((txt[i] != '~') && (txt[i] != 0))
        i++;
   }

   npop( activefontsettings );
} 

void showtext4 ( const char* TextToOutput, int x1, int y1, ... )
{
   va_list paramlist;
   va_start ( paramlist, y1 );

   char tempbuf[1000];

   vsprintf( tempbuf, TextToOutput, paramlist );
   va_end ( paramlist );
   showtext2 ( tempbuf, x1, y1 );
}

void showtext4c ( const char* TextToOutput, int x1, int y1, ... )
{
   va_list paramlist;
   va_start ( paramlist, y1 );

   char tempbuf[1000];

   vsprintf( tempbuf, TextToOutput, paramlist );
   va_end ( paramlist );
   showtext2c ( tempbuf, x1, y1 );
}

class InitNewfont {
         public:
           InitNewfont ( void )
           {
              memset( &activefontsettings, 0, sizeof ( activefontsettings ));
           };
      } initnewfont;

char* int2string ( int i, char* buf )
{
   if ( i >= 0 ) {
      itoa ( i, buf, 10 );
   } else {
      buf[0] = '-';
      i = -i;
      itoa ( i, &buf[1], 10 );
   }
   if ( gettextwdth ( buf, NULL ) > activefontsettings.length   &&  activefontsettings.length) {
      char buf2[50];

      int pot  = (int) log10 ( double(i) );
      int base = (int) pow ( 10, pot );
      int first = i / base;
      int rest = i - first * base;

      buf2[0] = digit[ first ][0];
      int p = 1;
      buf2[p] = 'E';
      buf2[p+1] = 0;
      strcat ( buf2, strrr ( pot ));

      while ( gettextwdth ( buf2, NULL ) < activefontsettings.length) {
         strcpy ( buf, buf2 );
         base /= 10;
         if ( p == 1 )
            buf2[p++] = '.';
         buf2[p++] = digit[ rest /  base ][0];
         rest = rest % base;

         buf2[p] = 'E';
         buf2[p+1] = 0;
         strcat ( buf2, strrr ( pot ));
      } /* endwhile */
   }
   return buf;

}
