/*
* fonts_u.c
* Copyright (C) 1999-2004 A.J. van Os; Released under GNU GPL
*
* Description:
* Functions to deal with fonts (Unix version)
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "antiword.h"
#include "fontinfo.h"

/* Don't use fonts, just plain text */
static BOOL             bUsePlainText = TRUE;
/* Which character set should be used */
static encoding_type    eEncoding = encoding_neutral;


/*
* pOpenFontTableFile - open the Font translation file
*
* Returns the file pointer or NULL
*/
FILE *
pOpenFontTableFile(void)
{
       FILE            *pFile;
       const char      *szHome, *szAntiword, *szGlobalFile;
       char            szEnvironmentFile[PATH_MAX+1];
       char            szLocalFile[PATH_MAX+1];

       szEnvironmentFile[0] = '\0';
       szLocalFile[0] = '\0';

       /* Try the environment version of the fontnames file */
       szAntiword = szGetAntiwordDirectory();
       if (szAntiword != NULL && szAntiword[0] != '\0') {
               if (strlen(szAntiword) +
                   sizeof(FILE_SEPARATOR FONTNAMES_FILE) >=
                   sizeof(szEnvironmentFile)) {
                       werr(0,
                       "The name of your ANTIWORDHOME directory is too long");
                       return NULL;
               }
               sprintf(szEnvironmentFile, "%s%s",
                       szAntiword,
                       FILE_SEPARATOR FONTNAMES_FILE);
               DBG_MSG(szEnvironmentFile);

               pFile = fopen(szEnvironmentFile, "r");
               if (pFile != NULL) {
                       return pFile;
               }
       }

       /* Try the local version of the fontnames file */
       szHome = szGetHomeDirectory();
       if (strlen(szHome) +
           sizeof(FILE_SEPARATOR ANTIWORD_DIR FILE_SEPARATOR FONTNAMES_FILE) >=
           sizeof(szLocalFile)) {
               werr(0, "The name of your HOME directory is too long");
               return NULL;
       }

       sprintf(szLocalFile, "%s%s",
               szHome,
               FILE_SEPARATOR ANTIWORD_DIR FILE_SEPARATOR FONTNAMES_FILE);
       DBG_MSG(szLocalFile);

       pFile = fopen(szLocalFile, "r");
       if (pFile != NULL) {
               return pFile;
       }

       /* Try the global version of the fontnames file */
       szGlobalFile = GLOBAL_ANTIWORD_DIR FILE_SEPARATOR FONTNAMES_FILE;
       DBG_MSG(szGlobalFile);

       pFile = fopen(szGlobalFile, "r");
       if (pFile != NULL) {
               return pFile;
       }

       if (szEnvironmentFile[0] != '\0') {
               werr(0, "I can not open your fontnames file.\n"
                       "Neither '%s' nor\n"
                       "'%s' nor\n"
                       "'%s' can be opened for reading.",
                       szEnvironmentFile, szLocalFile, szGlobalFile);
       } else {
               werr(0, "I can not open your fontnames file.\n"
                       "Neither '%s' nor\n"
                       "'%s' can be opened for reading.",
                       szLocalFile, szGlobalFile);
       }
       return NULL;
} /* end of pOpenFontTableFile */

/*
* vCloseFont - close the current font, if any
*/
void
vCloseFont(void)
{
       NO_DBG_MSG("vCloseFont");
       /* For safety: to be overwritten at the next call of tOpenfont() */
       eEncoding = encoding_neutral;
       bUsePlainText = TRUE;
} /* end of vCloseFont */

/*
* tOpenFont - make the specified font the current font
*
* Returns the font reference number
*/
drawfile_fontref
tOpenFont(UCHAR ucWordFontNumber, USHORT usFontStyle, USHORT usWordFontSize)
{
       options_type    tOptions;
       const char      *szOurFontname;
       size_t  tIndex;
       int     iFontnumber;

       NO_DBG_MSG("tOpenFont");
       NO_DBG_DEC(ucWordFontNumber);
       NO_DBG_HEX(usFontStyle);
       NO_DBG_DEC(usWordFontSize);

       /* Keep the relevant bits */
       usFontStyle &= FONT_BOLD|FONT_ITALIC;
       NO_DBG_HEX(usFontStyle);

       vGetOptions(&tOptions);
       eEncoding = tOptions.eEncoding;
       bUsePlainText = tOptions.eConversionType != conversion_draw &&
                       tOptions.eConversionType != conversion_ps &&
                       tOptions.eConversionType != conversion_pdf;

       if (bUsePlainText) {
               /* Plain text, no fonts */
               return (drawfile_fontref)0;
       }

       iFontnumber = iGetFontByNumber(ucWordFontNumber, usFontStyle);
       szOurFontname = szGetOurFontname(iFontnumber);
       if (szOurFontname == NULL || szOurFontname[0] == '\0') {
               DBG_DEC(iFontnumber);
               return (drawfile_fontref)0;
       }
       NO_DBG_MSG(szOurFontname);

       for (tIndex = 0; tIndex < elementsof(szFontnames); tIndex++) {
               if (STREQ(szFontnames[tIndex], szOurFontname)) {
                       NO_DBG_DEC(tIndex);
                       return (drawfile_fontref)tIndex;
               }
       }
       return (drawfile_fontref)0;
} /* end of tOpenFont */

/*
* tOpenTableFont - make the table font the current font
*
* Returns the font reference number
*/
drawfile_fontref
tOpenTableFont(USHORT usWordFontSize)
{
       options_type    tOptions;
       int     iWordFontnumber;

       NO_DBG_MSG("tOpenTableFont");

       vGetOptions(&tOptions);
       eEncoding = tOptions.eEncoding;
       bUsePlainText = tOptions.eConversionType != conversion_draw &&
                       tOptions.eConversionType != conversion_ps &&
                       tOptions.eConversionType != conversion_pdf;

       if (bUsePlainText) {
               /* Plain text, no fonts */
               return (drawfile_fontref)0;
       }

       iWordFontnumber = iFontname2Fontnumber(TABLE_FONT, FONT_REGULAR);
       if (iWordFontnumber < 0 || iWordFontnumber > (int)UCHAR_MAX) {
               DBG_DEC(iWordFontnumber);
               return (drawfile_fontref)0;
       }

       return tOpenFont((UCHAR)iWordFontnumber, FONT_REGULAR, usWordFontSize);
} /* end of tOpenTableFont */

/*
* szGetFontname - get the fontname
*/
const char *
szGetFontname(drawfile_fontref tFontRef)
{
       fail((size_t)(UCHAR)tFontRef >= elementsof(szFontnames));
       return szFontnames[(int)(UCHAR)tFontRef];
} /* end of szGetFontname */

/*
* lComputeStringWidth - compute the string width
*
* Note: the fontsize is specified in half-points!
*       the stringlength is specified in bytes, not characters!
*
* Returns the string width in millipoints
*/
long
lComputeStringWidth(const char *szString, size_t tStringLength,
       drawfile_fontref tFontRef, USHORT usFontSize)
{
       USHORT  *ausCharWidths;
       UCHAR   *pucChar;
       long    lRelWidth;
       size_t  tIndex;
       int     iFontRef;

       fail(szString == NULL);
       fail(usFontSize < MIN_FONT_SIZE || usFontSize > MAX_FONT_SIZE);

       if (szString[0] == '\0' || tStringLength == 0) {
               /* Empty string */
               return 0;
       }

       if (eEncoding == encoding_utf_8) {
               fail(!bUsePlainText);
               return lChar2MilliPoints(
                       utf8_strwidth(szString, tStringLength));
       }

       if (bUsePlainText) {
               /* No current font, use "systemfont" */
               return lChar2MilliPoints(tStringLength);
       }

       if (eEncoding == encoding_cyrillic) {
               /* FIXME: until the character tables are available */
               return (tStringLength * 600L * (long)usFontSize + 1) / 2;
       }

       DBG_DEC_C(eEncoding != encoding_latin_1 &&
               eEncoding != encoding_latin_2, eEncoding);
       fail(eEncoding != encoding_latin_1 &&
               eEncoding != encoding_latin_2);

       /* Compute the relative string width */
       iFontRef = (int)(UCHAR)tFontRef;
       if (eEncoding == encoding_latin_2) {
               ausCharWidths = ausCharacterWidths2[iFontRef];
       } else {
               ausCharWidths = ausCharacterWidths1[iFontRef];
       }
       lRelWidth = 0;
       for (tIndex = 0, pucChar = (UCHAR *)szString;
            tIndex < tStringLength;
            tIndex++, pucChar++) {
               lRelWidth += (long)ausCharWidths[(int)*pucChar];
       }

       /* Compute the absolute string width */
       return (lRelWidth * (long)usFontSize + 1) / 2;
} /* end of lComputeStringWidth */

/*
* tCountColumns - count the number of columns in a string
*
* Note: the length is specified in bytes!
*       A UTF-8 a character can be 0, 1 or 2 columns wide.
*
* Returns the number of columns
*/
size_t
tCountColumns(const char *szString, size_t tLength)
{
       fail(szString == NULL);

       if (eEncoding != encoding_utf_8) {
               /* One byte, one character, one column */
               return tLength;
       }
       return (size_t)utf8_strwidth(szString, tLength);
} /* end of tCountColumns */

/*
* tGetCharacterLength - the length of the specified character in bytes
*
* Returns the length in bytes
*/
size_t
tGetCharacterLength(const char *szString)
{
       fail(szString == NULL);

       if (eEncoding != encoding_utf_8) {
               return 1;
       }
       return (size_t)utf8_chrlength(szString);
} /* end of tGetCharacterLength */