// Module PI : Peida Interactive     PIFontX
// Gestion de fontes - Implementation X11    
// LAL (Orsay) / IN2P3-CNRS     R. Ansari  97-99

#include <stdio.h>

#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>

#include "sopnamsp.h"
#include "pisysdep.h"
#include "pifontx.h"
#include PIWDG_H


/* --Methode-- */
PIFontX::PIFontX(PIFontName fn)
  : PIFontGen(fn) , mFSize(-1) 
{
GlInit();
SelectFont(fn, PI_RomanFont, PI_NormalSizeFont);
}

/* --Methode-- */
PIFontX::PIFontX(int npt, PIFontName fn, PIFontAtt fa)
  : PIFontGen(npt, fn, fa), mFSize(-1) 
{
GlInit();
SelectFontPt(fn, fa, npt);
}

/* --Methode-- */
PIFontX::PIFontX(PIFontX const & fnt)
  : PIFontGen(fnt.mFName), mFSize(-1) 
{
GlInit();
SelectFontPt(fnt.mFName, fnt.mFAtt, fnt.mFSize);
}

/* --Methode-- */
PIFontX::~PIFontX()
{
}

/* --Methode-- */
PIFontX & PIFontX::operator = (PIFontX const & fnt)
{
SelectFontPt(fnt.mFName, fnt.mFAtt, fnt.mFSize);
return(*this);
}

/* --Methode-- */
bool PIFontX::operator == (PIFontX const & fnt)
{
if ((fnt.mFName == mFName) && (fnt.mFAtt == mFAtt) && (fnt.mFSize == mFSize)) 
  return(true);
else return(false);
}

/* --Methode-- */
void PIFontX::SetFont(PIFontName fn)
{
SelectFontPt(fn, mFAtt, mFSize);
}

/* --Methode-- */
void PIFontX::SetFontAtt(PIFontAtt fa)
{
SelectFontPt(mFName, fa, mFSize);
}

/* --Methode-- */
void PIFontX::SetFontSz(PIFontSize fs)
{
SelectFont(mFName, mFAtt, fs);
}

/* --Methode-- */
void PIFontX::SetFontSzPt(int npt)
{
SelectFontPt(mFName, mFAtt, npt);
}

/* --Methode-- */
PIFontName PIFontX::GetFontName() const
{
return(mFName);
}

/* --Methode-- */
PIFontAtt PIFontX::GetFontAtt() const
{
return(mFAtt);
}

/* --Methode-- */
int PIFontX::GetFontSzPt() const
{
return(mFSize);
}


/* --Methode-- */
int PIFontX::GetFontHeight(int& asc, int& desc) const
{
char a[2];
XCharStruct  ovr;
int hd, fa, fd;
XTextExtents(mFSt, a, 0, &hd, &fa, &fd, &ovr);
asc = fa; desc = fd; 
return(fa+fd);
}

/* --Methode-- */
int PIFontX::GetStringWidth(char const* s) const
{
return(XTextWidth(mFSt, s, strlen(s)));
}


#define NMAXFONTSZ    13
#define NMAXFONTATT   4
#define NMAXFONTTYP   5

/*  Variables globales pour la gestion des fontes  */
static XFontStruct * fntst[NMAXFONTSZ][NMAXFONTATT][NMAXFONTTYP];
static int fntsz[NMAXFONTSZ] = {8,9,10,11,12,14,16,18,20,24,28,32,36};
static int TinyFontIndex = 1; 
static int SmallFontIndex = 3; 
static int NormalFontIndex = 5;
static int LargeFontIndex = 7;
static int VeryLargeFontIndex = 9;
static int HugeFontIndex = 11;
static  PIFontAtt fntatt[NMAXFONTATT] = 
        { PI_RomanFont, PI_BoldFont, PI_ItalicFont, PI_BoldItalicFont };
static  PIFontName fntname[NMAXFONTTYP] = { PI_DefaultFont, PI_CourierFont, PI_HelveticaFont, 
                                            PI_TimesFont, PI_SymbolFont};  
static XFontStruct * defnt = NULL;

/* --Methode-- */
PIFontSize PIFontX::GetFontSz() const
{
  int fnidx[6],k;
  fnidx[0] = TinyFontIndex;
  fnidx[1] = SmallFontIndex;
  fnidx[2] = NormalFontIndex;
  fnidx[3] = LargeFontIndex;
  fnidx[4] = VeryLargeFontIndex;
  fnidx[5] = HugeFontIndex;
  PIFontSize rfnsz[6] = {PI_TinySizeFont, PI_SmallSizeFont, PI_NormalSizeFont, 
			 PI_LargeSizeFont, PI_VeryLargeSizeFont, PI_HugeSizeFont};
  PIFontSize rs = PI_NormalSizeFont;
  int diff = mFSize-fntsz[NormalFontIndex];
  int diffsz = (diff < 0) ? -diff : diff;
  for(k=0; k<6; k++) {
    diff = mFSize-fntsz[fnidx[k]];
    if (diff < 0)  diff = -diff;
    if (diff < diffsz) {
      diffsz = diff; 
      rs = rfnsz[k];
    }
  }
return(rs);
}

/* --Methode-- */
void PIFontX::SelectFont(PIFontName fn, PIFontAtt fa, PIFontSize fs)
{
int isz;
switch (fs) {
  case PI_TinySizeFont:
    isz = fntsz[TinyFontIndex];
    break;
  case PI_SmallSizeFont:
    isz = fntsz[SmallFontIndex];
    break;
  case PI_NormalSizeFont:
    isz = fntsz[NormalFontIndex];
    break;
  case PI_LargeSizeFont:
    isz = fntsz[LargeFontIndex];
    break;
  case PI_VeryLargeSizeFont:
    isz = fntsz[VeryLargeFontIndex];
    break;
  case PI_HugeSizeFont:
    isz = fntsz[HugeFontIndex];
    break;
  default:
    isz = fntsz[NormalFontIndex];
    break;
  }

SelectFontPt(fn, fa, isz);
return;
}

/* --Methode-- */
void PIFontX::SelectFontPt(PIFontName fn, PIFontAtt fa, int npt)
{
if ( (mFSize > 0) && (fn == mFName) && (fa == mFAtt) && (npt == mFSize) )   return;
int dsz,i,isel, j, k;
isel = 0;
dsz = 9999;
for(i=0; i<NMAXFONTSZ; i++)
  {
  j = npt - fntsz[i];   if (j < 0)  j = -j;
  if (j < dsz)  {  isel = i; dsz = j; }
  }
i = isel;
j = 0;
switch (fa) {
  case PI_RomanFont :
    j = 0;
    break;
  case PI_BoldFont :
    j = 1;
    break;
  case PI_ItalicFont :
    j = 2;
    break;
  case PI_BoldItalicFont :
    j = 3;
    break;   
  default :
    j = 0;
    break;
  }

k = 0;
switch (fn)
 {
  case PI_DefaultFont :
    k = 0;
    break;
  case PI_CourierFont :
    k = 1;
    break;
  case PI_HelveticaFont :
    k = 2;
    break;
  case PI_TimesFont :
    k = 3;
    break;
  case PI_SymbolFont :
    k = 4;
    break;
  default :
    k = 0;
    break;
  }
LoadFontSt(i, j, k);
return;
}


// Le bazar pour recuperer des resources de .Xdefault et autres 
typedef struct 
  {
  String fntFam[5];
  } myAppData;
static myAppData  apd;

static XtResource resources[] = {
  { const_cast<char *>("fontFamilyName"), const_cast<char *>("FontFamilyName"), 
    XtRString, sizeof(String),
    /*XtOffset(apd, fntFam[0])*/ 0, XtRString, const_cast<char *>("*-courier") } ,
  { const_cast<char *>("courierfontFamilyName"), const_cast<char *>("CourierfontFamilyName"), 
    XtRString, sizeof(String),
    sizeof(String) , XtRString, const_cast<char *>("*-courier") } ,
  { const_cast<char *>("helveticafontFamilyName"), const_cast<char *>("HelveticafontFamilyName"), 
    XtRString, sizeof(String),
    2*sizeof(String) , XtRString, const_cast<char *>("*-helvetica") } ,
  { const_cast<char *>("timesfontFamilyName"), const_cast<char *>("TimesfontFamilyName"), 
    XtRString, sizeof(String),
    3*sizeof(String) , XtRString, const_cast<char *>("*-times") } ,
  { const_cast<char *>("symbolfontFamilyName"), const_cast<char *>("SymbolfontFamilyName"), 
    XtRString, sizeof(String),
    4*sizeof(String) , XtRString, const_cast<char *>("*-symbol") }
};
 
static const char * fnbi_b[4] = { "medium-r-normal", "bold-r-normal", 
                          "medium-o-normal", "bold-o-normal" };
static const char * fnbo_b[4] = { NULL, NULL, 
                          "medium-i-normal", "bold-i-normal" };

/* --Methode-- */
void PIFontX::LoadFontSt(int isz, int jat, int kfn)
{

if (!fntst[isz][jat][kfn])  // Il faut charger la fonte
  {
  char buff[256];
  int count,k;
  Display * mdsp = PIXDisplay();
  char **list = NULL;

  for (k=0; k<5; k++)  {  // Recherche de la fonte pour tailles croissantes
    sprintf(buff,"-%s-%s-*-%d-*-*-*-*-*-*-*", apd.fntFam[kfn], fnbi_b[jat], fntsz[isz]+k);
    list = XListFonts(mdsp, buff, 10, &count);
    if ((count <= 0) && (fnbo_b[jat] != NULL)) {
      if (list) XFreeFontNames(list);  
      sprintf(buff,"-%s-%s-*-%d-*-*-*-*-*-*-*", apd.fntFam[kfn], fnbo_b[jat], fntsz[isz]+k);
      list = XListFonts(mdsp, buff, 10, &count);
    }
    if (count > 0)  break;
  }
  // certaines fontes n'ont pas de version  bold ou italique
  if ( (count == 0) && (jat > 0) ) {
    for (k=0; k<5; k++)  {  // Recherche de la fonte pour tailles croissantes
      if (list) XFreeFontNames(list);  
      sprintf(buff,"-%s-%s-*-%d-*-*-*-*-*-*-*", apd.fntFam[kfn], fnbi_b[0], fntsz[isz]+k);
      list = XListFonts(mdsp, buff, 10, &count);
      if (count > 0)  break;
    }
  }
  if (count > 0) {
    for (int kkk=0; kkk<count; kkk++) {
      fntst[isz][jat][kfn] = XLoadQueryFont(mdsp, list[kkk]);
      if (fntst[isz][jat][kfn] != NULL) break;
    }
    if (list) XFreeFontNames(list);  
  }
  else  { 
    if (list) XFreeFontNames(list);  
    printf("PIFontX::LoadFontSt/ Pb font %s - Using default \n", buff);    
    fntst[isz][jat][kfn] = defnt; 
    }
  }

mFAtt = fntatt[jat];
mFSize = fntsz[isz];
mFName = fntname[kfn];
mFSt = fntst[isz][jat][kfn];
return;
}


static bool fgfntinitdone = false ;   // Flag init done
/* --Methode-- */
void PIFontX::GlInit()
{
if (fgfntinitdone) return;
fgfntinitdone = true;

Display * mdsp = PIXDisplay();

char buff[256];
int i,j,k,count;
char **list;


XtGetApplicationResources(PIXtTopWdg(), &apd, resources, 
                          XtNumber(resources), NULL, 0);
sprintf(buff,"-%s-*-*-*-*-*-*-*-*-*-*-*-*", apd.fntFam[0]);
list = NULL;
list = XListFonts(mdsp, buff, 15, &count);
if (count < 5)
  { 
  printf("PIFontX::Init %d fonts found for %s , switching to courier\n",
         count, apd.fntFam[0]);
  apd.fntFam[0] = const_cast<char *>("*-courier");
  if (list) XFreeFontNames(list);
  }
sprintf(buff,"-%s-%s-*-*-*-*-12-*-*-*-*", apd.fntFam[0], fnbi_b[0]);
list = XListFonts(mdsp, buff, 10, &count);
if (count < 1) {
  if (list) XFreeFontNames(list);
  sprintf(buff,"-*-fixed-*-*-*-*-12-*-*-*-*-*-*-*");
  list = XListFonts(mdsp, buff, 10, &count);
  if (count < 1)   {  
    if (list) XFreeFontNames(list);
    sprintf(buff,"fixed");
    list = XListFonts(mdsp, buff, 10, &count);
  }
  if (count < 1)   {  
    if (list) XFreeFontNames(list);
    strcpy(buff,"");
    list = XListFonts(mdsp, buff, 10, &count);
  }
}
if (count < 1) {  
  if (list) XFreeFontNames(list);
  printf("PIFontX::Init/ Erreur, no font found ... \n");
  defnt = NULL;
  //Reza+Bruno, 17 Juin 2008 - Il faut lancer une exception 
  }
else { 
  defnt = NULL;
  for (int kkk=0; kkk<count; kkk++) {
    defnt = XLoadQueryFont(mdsp, list[kkk]);
    if (defnt != NULL) break;
  }
  if (list) XFreeFontNames(list);  
}
for (i=0; i<NMAXFONTSZ; i++)
  for (j=0; j<NMAXFONTATT; j++)  
    for (k=0; k<NMAXFONTTYP; k++)  fntst[i][j][k] = NULL;

// Choix des trois tailles de fontes standard en fonction de 
// la taille de fonte par defaut des composantes standard
int szx, szy, szf;
PIXtAppCtx(szx, szy, szf);
int kkk, kkj, kksel, kkdsz = 9999;  
kksel = NMAXFONTSZ/2;
for(kkk=NMAXFONTSZ-1; kkk>=0; kkk--) {
  kkj = szf - fntsz[kkk];   if (kkj < 0)  kkj = -kkj;
  if (kkj < kkdsz)  {  kksel = kkk;  kkdsz = kkj; }
  }
if (kksel == NMAXFONTSZ-1)  kksel = NMAXFONTSZ-2;
NormalFontIndex = kksel;
SmallFontIndex = (kksel > 1) ? kksel-2 : 0 ;
TinyFontIndex = (kksel > 3) ? kksel-4 : 0 ;  
LargeFontIndex =  (kksel < NMAXFONTSZ-2) ? kksel+2 :  NMAXFONTSZ-1;
VeryLargeFontIndex =  (kksel < NMAXFONTSZ-4) ? kksel+4 :  NMAXFONTSZ-1;
HugeFontIndex =  (kksel < NMAXFONTSZ-6) ? kksel+6 :  NMAXFONTSZ-1;
// On garde HugeFontIndex et TinyFontIndex aux tailles extremes 
// HugeFontIndex = NMAXFONTSZ-1;

// printf("PIFontX::Init()-DBG- FontIndex= %d %d %d (SzF=%d) \n", 
//       SmallFontIndex, NormalFontIndex, BigFontIndex, szf);

return;
}
