// Module PI : Peida Interactive     PIGraphicAtt 
// PIGraphicAtt - Implementation     R. Ansari  2002
// (C) LAL (Orsay) / IN2P3-CNRS  DAPNIA/SPP (Saclay) / CEA

#include "sopnamsp.h"
#include "pigratt.h"
#include <ctype.h>
#include "strutilxx.h"

#include <stdio.h>
#include <map>

//++
// Class	PIGraphicAtt
// Lib		PI
// include	pigratt.h
//
//	Classe gestionnaire des attributs graphiques.
//	(couleur, marker, lignes, ...)
//--
//++
// Links	Voir aussi
// PIGraphic
// PIFont
// PILineAtt
//--

//++
// Titre	Constructeurs
//--
//++
// PIGraphicAtt()
//	Constructeur - Initialisation de tous les attributs aux valeurs par défaut.
// PIGraphicAtt(PIGraphicAtt const & att)
//	Constructeur de copie
// PIGraphicAtt(vector<string> & att, bool rmdecatt)
//	Cosntructeur avec décodage des attributs à partir d'un vecteur de string
//	"att". Si "rmdecatt == true", les attributs décodés sont supprimés du
//	vecteur de départ.
//--

PIGraphicAtt::PIGraphicAtt()
{
  InitGrAttStrings();   // Init attributes decoding maps
  SetDefaultAtt();
}

PIGraphicAtt::PIGraphicAtt(PIGraphicAtt const & att)
{
  InitGrAttStrings();   // Init attributes decoding maps
  CopyFrom(att);
}

PIGraphicAtt::PIGraphicAtt(vector<string> & att, bool rmdecatt)
{
  InitGrAttStrings();   // Init attributes decoding maps
  // Initialize attributes
  SetDefaultAtt();
  // Decode attributes from strings 
  DecodeAttStrings(att, rmdecatt);
}

PIGraphicAtt::~PIGraphicAtt()
{
}

//++
// Titre	Méthodes
//--
//++
// void CopyFrom(PIGraphicAtt const & att)
//	Copie les attributs à partir de l'objet "att".
// bool Compare(PIGraphicAtt const & att)
//	Comparison de deux objets de type PIGraphicAtt. Renvoie "true"
//	si attributs identiques.
// void	SetDefaultAtt()
//	Initialise les attributs aux valeurs par défaut.
// PIGraphicAtt& operator = (PIGraphicAtt const & att)
//	Opérateur d'affectation. Appelle *CopyFrom()*
// bool operator == (PIGraphicAtt const & att)
//	Opérateur d'égalité. Appelle *Compare()*
// bool operator != (PIGraphicAtt const & att)
//	Opérateur d'inégalité. Appelle *Compare()*
// void UpdateFrom(PIGraphicAtt const & att)
//	Met à jour les attributs initialisés à partir de l'objet "att".
// int  DecodeAttStrings(vector<string> & att, bool rmdecatt=true)
//	Décode les attributs  à partir du vecteur de string "att".
//	Si "rmdecatt == true", les attributs décodés sont supprimés du
//	vecteur de départ.
// int  AttToStrings(vector<string> & att) const
//	Renvoie dans "att" les attributs sous forme de string Décodeable 
//	par *DecodeAttStrings()* . Retourne le nombre d'éléments ajoutés.
// unsigned long DecodeTextPosDirAtt(vector<string> & att, bool rmdecatt=true)
//	Décode les attributs de direction et de positionnement de tracé de texte
//	à partir du vecteur de string "att" (méthode statique).
//	Si "rmdecatt == true", les attributs décodés sont supprimés du
//	vecteur de départ. 
//	Retourne le flag de positionnement.
//--

void PIGraphicAtt::SetDefaultAtt()
{
  SetColAtt();
  SetLineAtt();
  SetFontAtt();
  mNotDefFnt = false;
  SetMarkerAtt(1);
  SetArrowMarkerAtt(5);
  SetColMapId();
}

void PIGraphicAtt::CopyFrom(PIGraphicAtt const & att)
{
  mFCol = att.mFCol;
  mBCol = att.mBCol;
  mLAtt = att.mLAtt;
  mFnt = att.mFnt;
  mNotDefFnt = att.mNotDefFnt;
  mMSz = att.mMSz;
  mMrk = att.mMrk;
  mArrowMrkSz = att.mArrowMrkSz;
  mArrowMrk = att.mArrowMrk;
  mCmapid = att.mCmapid;
  mRevCmap = att.mRevCmap;
}

bool PIGraphicAtt::Compare(PIGraphicAtt const & att)
{
  if (mFCol != att.mFCol) return false;
  if (mBCol != att.mBCol) return false;
  if (mLAtt != att.mLAtt) return false;
  bool fnteq = (mFnt == att.mFnt);
  if (!fnteq)  return false;
  if (mMSz != att.mMSz) return false;
  if (mMrk != att.mMrk)  return false;
  if (mArrowMrkSz != att.mArrowMrkSz) return false;
  if (mArrowMrk != att.mArrowMrk) return false;
  if (mCmapid != att.mCmapid) return false;
  if (mRevCmap != att.mRevCmap) return false;

  return true;
}

// PIGraphicAtt::DecodeAttStrings(vector<string> & att, bool rmdecatt)
// Voir apres InitGrAttStrings()


void PIGraphicAtt::UpdateFrom(PIGraphicAtt const & att)
{
  if (att.mFCol != PI_NotDefColor)  mFCol = att.mFCol;
  if (att.mBCol != PI_NotDefColor)  mBCol = att.mBCol;
  if (att.mLAtt != PI_NotDefLineAtt)  mLAtt = att.mLAtt;
  if (att.mNotDefFnt) mFnt = att.mFnt;
  //  if ( (att.mFnt.GetFontName() != PI_DefaultFont) || 
  //       (att.mFnt.GetFontAtt() != PI_NotDefFontAtt) ||
  //     (att.mFnt.GetFontSize() != PI_NotDefFontSize) )  mFnt = att.mFnt;
  if (att.mMrk != PI_NotDefMarker) {
    mMSz = att.mMSz;
    mMrk = att.mMrk;
  }
  if (att.mArrowMrk != PI_NotDefArrowMarker) {
    mArrowMrkSz = att.mArrowMrkSz;
    mArrowMrk = att.mArrowMrk;
  }
  if (att.mCmapid != CMAP_OTHER) {
    mCmapid = att.mCmapid;
    mRevCmap = att.mRevCmap;
  }

}

void PIGraphicAtt::SetFontAtt(PIFontSize fsz, PIFontAtt fat)
{
  mNotDefFnt = true;
  mFnt.SetFontAtt(fat);
  mFnt.SetFontSz(fsz);
}

void PIGraphicAtt::SetFontAtt(PIFontName fn, PIFontSize fsz, PIFontAtt fat)
{
  mNotDefFnt = true;
  mFnt.SetFont(fn);
  mFnt.SetFontAtt(fat);
  mFnt.SetFontSz(fsz);
}


// -------------------------------------------------------------------- 
// Variables globales pour decodage de chaines d'attributs graphiques
// -------------------------------------------------------------------- 

typedef map<string, PIColors, less<string> > GrAttColors;
typedef map<string, PILineAtt, less<string> > GrAttLines;
typedef map<string, PIFontName, less<string> > GrAttFontNames;
struct gratt_fontatt {
  PIFontAtt fatt;
  PIFontSize fsz;
};
typedef map<string, gratt_fontatt, less<string> > GrAttFonts;
struct gratt_marker {
  PIMarker mrk;
  int msz;
};
typedef map<string, gratt_marker, less<string> > GrAttMarkers;
struct gratt_arrowmarker {
  PIArrowMarker amrk;
  int amsz;
};
typedef map<string, gratt_arrowmarker, less<string> > GrAttArrowMarkers;
typedef map<string, CMapId, less<string> > GrAttColMaps;

static bool gratt_init_done = false;
static GrAttColors* GrAcolors = NULL;
static GrAttLines* GrAlines = NULL;
static GrAttFonts* GrAfonts = NULL;
static GrAttFontNames* GrAfontNames = NULL;
static GrAttMarkers* GrAmarkers = NULL;
static GrAttArrowMarkers* GrAarrowMarkers = NULL;
static GrAttColMaps* GrAcmaps = NULL;

#define GRA_NCOLMX 25
static PIColors GrAcolTab[GRA_NCOLMX] = 
  { PI_Black, PI_White, PI_Grey, PI_Red, PI_Blue, PI_Green,  
    PI_Yellow, PI_Magenta, PI_Cyan, PI_Turquoise, PI_NavyBlue, PI_Orange, 
    PI_SiennaRed, PI_Purple, PI_LimeGreen, PI_Gold, PI_Violet, PI_VioletRed, 
    PI_BlueViolet, PI_DarkViolet, PI_SkyBlue, PI_RoyalBlue , PI_ForestGreen, 
    PI_OrangeRed, PI_Brown };

void PIGraphicAtt::InitGrAttStrings()
{
  if (gratt_init_done) return;

  GrAcolors = new GrAttColors;
  GrAttColors& GrAcol = *GrAcolors;
  PIColors gic;
  // Les couleurs
  gic = PI_NotDefColor;
  GrAcol["defcol"] = gic;
  gic = PI_Black;
  GrAcol["black"] = gic;
  gic = PI_White;
  GrAcol["white"] = gic;
  gic = PI_Grey;
  GrAcol["grey"] = gic;
  gic = PI_Red;
  GrAcol["red"] = gic;
  gic = PI_Blue;
  GrAcol["blue"] = gic;
  gic = PI_Green;
  GrAcol["green"] = gic;
  gic = PI_Yellow;
  GrAcol["yellow"] = gic;
  gic = PI_Magenta;
  GrAcol["magenta"] = gic;
  
  gic = PI_Cyan;
  GrAcol["cyan"] = gic;
  gic = PI_Turquoise;
  GrAcol["turquoise"] = gic;
  gic = PI_NavyBlue;
  GrAcol["navyblue"] = gic;
  gic = PI_Orange;
  GrAcol["orange"] = gic;
  gic = PI_SiennaRed;
  GrAcol["siennared"] = gic;
  gic = PI_Purple;
  GrAcol["purple"] = gic;
  gic = PI_LimeGreen;
  GrAcol["limegreen"] = gic;
  gic = PI_Gold;
  GrAcol["gold"] = gic;
  gic = PI_Violet;
  GrAcol["violet"] = gic;
  gic = PI_VioletRed;
  GrAcol["violetred"] = gic;
  gic = PI_BlueViolet;
  GrAcol["blueviolet"] = gic;
  gic = PI_DarkViolet;
  GrAcol["darkviolet"] = gic;
  gic = PI_SkyBlue;
  GrAcol["skyblue"] = gic;
  gic = PI_RoyalBlue;
  GrAcol["royalblue"] = gic;
  gic = PI_ForestGreen;
  GrAcol["forestgreen"] = gic;
  gic = PI_OrangeRed;
  GrAcol["orangered"] = gic;
  gic = PI_Brown;
  GrAcol["brown"] = gic;

// Les attributs de lignes
  PILineAtt gil;
  GrAlines = new GrAttLines;
  GrAttLines& GrAlin = *GrAlines;

  gil = PI_NotDefLineAtt;
  GrAlin["defline"] = gil;
  gil = PI_NormalLine;
  GrAlin["normalline"] = gil;
  gil = PI_ThinLine;
  GrAlin["thinline"] = gil;
  gil = PI_ThickLine;
  GrAlin["thickline"] = gil;
  gil = PI_DashedLine;
  GrAlin["dashedline"] = gil;
  gil = PI_ThinDashedLine;
  GrAlin["thindashedline"] = gil;
  gil = PI_ThickDashedLine;
  GrAlin["thickdashedline"] = gil;
  gil = PI_DottedLine;
  GrAlin["dottedline"] = gil;
  gil = PI_ThinDottedLine;
  GrAlin["thindottedline"] = gil;
  gil = PI_ThickDottedLine;
  GrAlin["thickdottedline"] = gil;
  gil = PI_DashDottedLine;
  GrAlin["dashdottedline"] = gil;
  gil = PI_ThinDashDottedLine;
  GrAlin["thindashdottedline"] = gil;
  gil = PI_ThickDashDottedLine;
  GrAlin["thickdashdottedline"] = gil;

  // Noms de fontes
  GrAfontNames = new GrAttFontNames;
  GrAttFontNames& GrAfontnm = *GrAfontNames;
  PIFontName gifn;
  gifn = PI_DefaultFont;
  GrAfontnm["deffont"] = gifn;
  gifn = PI_CourierFont;
  GrAfontnm["courierfont"] = gifn;
  gifn = PI_HelveticaFont;
  GrAfontnm["helveticafont"] = gifn;
  gifn = PI_TimesFont;
  GrAfontnm["timesfont"] = gifn;
  gifn = PI_SymbolFont;
  GrAfontnm["symbolfont"] = gifn;

  // Attributs de fontes 
  GrAfonts = new GrAttFonts;
  GrAttFonts& GrAfnt = *GrAfonts;
  gratt_fontatt gifa;

  gifa.fsz = PI_NotDefFontSize;
  gifa.fatt = PI_NotDefFontAtt;
  GrAfnt["deffontatt"] = gifa;
  gifa.fsz = PI_NormalSizeFont;
  gifa.fatt = PI_RomanFont;
  GrAfnt["normalfont"] = gifa;
  gifa.fatt = PI_BoldFont;
  GrAfnt["boldfont"] = gifa;
  gifa.fatt = PI_ItalicFont;
  GrAfnt["italicfont"] = gifa;
  gifa.fatt = PI_BoldItalicFont;
  GrAfnt["bolditalicfont"] = gifa;
  gifa.fsz = PI_SmallSizeFont;
  gifa.fatt = PI_RomanFont;
  GrAfnt["smallfont"] = gifa;
  gifa.fatt = PI_BoldFont;
  GrAfnt["smallboldfont"] = gifa;
  gifa.fatt = PI_ItalicFont;
  GrAfnt["smallitalicfont"] = gifa;
  gifa.fatt = PI_BoldItalicFont;
  GrAfnt["smallbolditalicfont"] = gifa;
  gifa.fsz = PI_LargeSizeFont;
  gifa.fatt = PI_RomanFont;
  GrAfnt["bigfont"] = gifa;
  GrAfnt["largefont"] = gifa;
  gifa.fatt = PI_BoldFont;
  GrAfnt["bigboldfont"] = gifa;
  gifa.fatt = PI_ItalicFont;
  GrAfnt["bigitalicfont"] = gifa;
  GrAfnt["largeitalicfont"] = gifa;
  gifa.fatt = PI_BoldItalicFont;
  GrAfnt["bigbolditalicfont"] = gifa;
  GrAfnt["largebolditalicfont"] = gifa;
  gifa.fsz = PI_HugeSizeFont;
  gifa.fatt = PI_RomanFont;
  GrAfnt["hugefont"] = gifa;
  gifa.fatt = PI_BoldFont;
  GrAfnt["hugeboldfont"] = gifa;
  gifa.fatt = PI_ItalicFont;
  GrAfnt["hugeitalicfont"] = gifa;
  gifa.fatt = PI_BoldItalicFont;
  GrAfnt["hugebolditalicfont"] = gifa;


// Les markers 
  GrAmarkers = new GrAttMarkers;
  GrAttMarkers& GrAmrk = *GrAmarkers;
  const char* mrkn[11] = {"dotmarker", "plusmarker", "crossmarker", 
			  "circlemarker", "fcirclemarker", 
			  "boxmarker", "fboxmarker", 
			  "trianglemarker", "ftrianglemarker", 
			  "starmarker", "fstarmarker"};
  PIMarker mrk[11] = {PI_DotMarker, PI_PlusMarker, PI_CrossMarker, 
		      PI_CircleMarker, PI_FCircleMarker, 
		      PI_BoxMarker, PI_FBoxMarker, 
		      PI_TriangleMarker, PI_FTriangleMarker, 
		      PI_StarMarker, PI_FStarMarker};

  
  gratt_marker gim;
  gim.msz = 1;
  gim.mrk = PI_NotDefMarker;
  GrAmrk["defmarker"] = gim;
  int j;
  for(j=0; j<11; j++) {
    string smrk;
    char buff[32];
    for(int m=1; m<16; m+=2) {
      sprintf(buff,"%d",m);
      smrk = (string)mrkn[j] + (string)buff;
      gim.mrk = mrk[j];  gim.msz = m;
      GrAmrk[smrk] = gim;
    }
  }

// Les fleches - ArrowMarkers 
  GrAarrowMarkers = new GrAttArrowMarkers;
  GrAttArrowMarkers& GrAarrmrk = *GrAarrowMarkers;
  const char* arrmrkn[5] = {"basicarrow", 
			    "trianglearrow", "ftrianglearrow", 
			    "arrowshapedarrow", "farrowshapedarrow"};
  PIArrowMarker arrmrk[5] = {PI_BasicArrowMarker, 
			     PI_TriangleArrowMarker, PI_FTriangleArrowMarker, 
			     PI_ArrowShapedArrowMarker, PI_FArrowShapedArrowMarker};
  
  gratt_arrowmarker giam;
  giam.amsz = 7;
  giam.amrk = PI_NotDefArrowMarker;
  GrAarrmrk["defarrow"] = giam;
 
  for(j=0; j<5; j++) {
    string smrk;
    char buff[32];
    for(int m=5; m<17; m+=2) {
      sprintf(buff,"%d",m);
      smrk = (string)arrmrkn[j] + (string)buff;
      giam.amrk = arrmrk[j];  giam.amsz = m;
      GrAarrmrk[smrk] = giam;
    }
  }

  // Les tables de couleurs 
  GrAcmaps = new GrAttColMaps;
  GrAttColMaps& GrAcmp = *GrAcmaps;
  CMapId gicm;
  gicm = CMAP_OTHER;
  GrAcmp["defcmap"] = gicm;
  for(int kcc=0; kcc<PIColorMap::NumberStandardColorMaps(); kcc++) {
    gicm = PIColorMap::GetStandardColorMapId(kcc);
    string colname = PIColorMap::GetStandardColorMapName(kcc);
    for(unsigned int jll=0; jll<colname.length(); jll++)
      colname[jll] = tolower(colname[jll]);
    GrAcmp[colname] = gicm;
  }


  gratt_init_done = true;

}

int PIGraphicAtt::DecodeAttStrings(vector<string> & att, bool rmdecatt)
{
  if (att.size() == 0)  return(0);  
  vector<string> udatt;
  unsigned int k = 0;
  int ndec = att.size();
  for( k=0; k<att.size(); k++ ) {
    bool fgdec = false;
    string gratt = att[k];
    // Valeurs par defaut 
    if (gratt == "default") { 
      SetDefaultAtt();  
      fgdec = true;
    }
    // Decodage couleur avant-plan/arriere-plan avec fgcolor=colname ou bgcolor=colname
    else if ( (gratt.substr(0, 8) == "fgcolor=") || (gratt.substr(0, 8) == "bgcolor=") ||  
	 (gratt.substr(0, 6) == "color=") ) {
      string scol;
      bool sfgc = true;
      if (gratt[0] != 'c')  {
	if (gratt[0] == 'b') sfgc = false;
	scol = gratt.substr(8);
      }
      else scol = gratt.substr(6);

      GrAttColors& GrAcol = *GrAcolors;
      GrAttColors::const_iterator itc = GrAcol.find(scol);
      PIColors cdcol = PI_NotDefColor;
      fgdec = false;
      if (itc != GrAcol.end())  { 
	cdcol = (*itc).second;  fgdec = true;  
      }
      if (sfgc) mFCol = cdcol;
      else mBCol = cdcol;
      fgdec = true;
    }
    // Decodage de fonte sous forme de font=FontName,FontAtt,FontSizePt
    else if (gratt.substr(0, 5) == "font=") {
      PIFontName dfn = PI_DefaultFont;
      int dfsz = 10;
      PIFontAtt dfa = PI_RomanFont;
      vector<string> fna;
      FillVStringFrString(gratt.substr(5), fna, ',');
      if (fna.size() > 0) {
	if (fna[0] == "courier") dfn = PI_CourierFont;
	else if (fna[0] == "helvetica") dfn = PI_HelveticaFont;
	else if (fna[0] == "times") dfn = PI_TimesFont;
	else if (fna[0] == "symbol") dfn = PI_SymbolFont;
      }
      if (fna.size() > 1) {
	if (fna[1] == "roman") dfa = PI_RomanFont;
	else if (fna[1] == "bold") dfa = PI_BoldFont;
	else if (fna[1] == "italic") dfa = PI_ItalicFont;
	else if (fna[1] == "bolditalic") dfa = PI_BoldItalicFont;
      }
      if (fna.size() > 2) dfsz = atoi(fna[2].c_str());
      //      cout << "DBG-GRATT: " << fna[0] << " " << fna[1] << " " << dfsz << endl;
      mFnt.SetFont(dfn);
      mFnt.SetFontAtt(dfa);
      mFnt.SetFontSzPt(dfsz);
      if (fna.size() > 0) mNotDefFnt = true;
      else  mNotDefFnt = false;
      fgdec = true;
    }
    // Decodage d'attribut de ligne sous forme de line=dashtype,width
    else if (gratt.substr(0, 5) == "line=") {
      PILineDash dld = PI_LineSolid;
      int dlw = 1;
      vector<string> lna;
      FillVStringFrString(gratt.substr(5), lna, ',');
      if (lna.size() > 0) {
	if (lna[0] == "solid") dld = PI_LineSolid;
	else if (lna[0] == "dashed") dld = PI_LineDashed;
	else if (lna[0] == "dotted") dld = PI_LineDotted;
	else if (lna[0] == "dashdotted") dld = PI_LineDashDotted;
      }
      if (lna.size() > 1) dlw = atoi(lna[1].c_str());
      mLAtt.SetLineWidth(dlw);
      mLAtt.SetLineDash(dld);
      fgdec = true;
    }
    // decodage de marker sous forme de marker=type,size
    else if (gratt.substr(0, 7) == "marker=") {
      PIMarker dmrk = PI_NotDefMarker;
      int dmsz = 1;
      vector<string> mka;
      FillVStringFrString(gratt.substr(7), mka, ',');
      if (mka.size() > 0) {
	if (mka[0] == "dot") dmrk = PI_DotMarker;
	else if (mka[0] == "plus") dmrk = PI_PlusMarker;
  	else if (mka[0] == "cross") dmrk = PI_CrossMarker;
      	else if (mka[0] == "circle") dmrk = PI_CircleMarker;
      	else if (mka[0] == "fcircle") dmrk = PI_FCircleMarker;
      	else if (mka[0] == "box") dmrk = PI_BoxMarker;
      	else if (mka[0] == "fbox") dmrk = PI_FBoxMarker;
      	else if (mka[0] == "triangle") dmrk = PI_TriangleMarker;
      	else if (mka[0] == "ftriangle") dmrk = PI_FTriangleMarker;
      	else if (mka[0] == "star") dmrk = PI_StarMarker;
      	else if (mka[0] == "fstar") dmrk = PI_FStarMarker;
      }
      if (mka.size() > 1) dmsz = atoi(mka[1].c_str());
      mMrk = dmrk;  
      mMSz = dmsz;
      fgdec = true;
    }
    // decodage de arrowmarker sour forme de arrow=type,size
    else if (gratt.substr(0, 6) == "arrow=") {
      PIArrowMarker darr = PI_NotDefArrowMarker;
      int dasz = 3;
      vector<string> mka;
      FillVStringFrString(gratt.substr(6), mka, ',');
      if (mka.size() > 0) {
	if (mka[0] == "basic") darr = PI_BasicArrowMarker;
      	else if (mka[0] == "triangle") darr = PI_TriangleArrowMarker;
      	else if (mka[0] == "ftriangle") darr = PI_FTriangleArrowMarker;
      	else if (mka[0] == "arrowshaped") darr = PI_ArrowShapedArrowMarker;
      	else if (mka[0] == "farrowshaped") darr = PI_FArrowShapedArrowMarker;
      }
      if (mka.size() > 1) dasz = atoi(mka[1].c_str());
      mArrowMrk = darr;
      mArrowMrkSz = dasz;
      fgdec = true;
    }
    
    // Inversion d'indexage de ColorMap
    else if (gratt == "revcmap")  { 
      mRevCmap = true;  fgdec = true;
    }
    if (fgdec) continue;

    // Si c'est un colormap
    fgdec = false;
    GrAttColMaps& GrAcmp = *GrAcmaps;
    GrAttColMaps::const_iterator itcm = GrAcmp.find(gratt);
    if (itcm != GrAcmp.end())  { 
      mCmapid = (*itcm).second;  
      fgdec = true;  continue; 
    }
    if (fgdec) continue;

    // Le decodage ancienne maniere (avant Mai 2003)
    // Si c'est une couleur
    GrAttColors& GrAcol = *GrAcolors;
    GrAttColors::const_iterator itc = GrAcol.find(gratt);
    fgdec = false;
    if (itc != GrAcol.end())  { 
      mFCol = (*itc).second;  fgdec = true;  continue; 
    }
    if (fgdec) continue;
    // Si c'est un attribut de lignes
    fgdec = false;
    GrAttLines& GrAlin = *GrAlines;
    GrAttLines::const_iterator itl = GrAlin.find(gratt);
    if (itl != GrAlin.end())  { 
      mLAtt = (*itl).second;  fgdec = true;  continue; 
    }
    if (fgdec) continue;
    // Si c'est un nom de fontes
    fgdec = false;
    GrAttFontNames& GrAfontnm = *GrAfontNames;
    GrAttFontNames::const_iterator itfn = GrAfontnm.find(gratt);
    if (itfn != GrAfontnm.end()) { 
      mFnt.SetFont((*itfn).second);  
      mNotDefFnt = true;  fgdec = true;  continue; 
    }
    if (fgdec) continue;
    // Si c'est un attribut de fontes
    fgdec = false;
    GrAttFonts& GrAfnt = *GrAfonts;
    GrAttFonts::const_iterator itfa = GrAfnt.find(gratt);
    if (itfa != GrAfnt.end()) {
      mFnt.SetFontAtt((*itfa).second.fatt);  
      mFnt.SetFontSz((*itfa).second.fsz); 
      mNotDefFnt = true;  fgdec = true;  continue; 
    }
    if (fgdec) continue;
    // Si c'est un attribut de markers
    fgdec = false;
    GrAttMarkers& GrAmrk = *GrAmarkers;
    GrAttMarkers::const_iterator itm = GrAmrk.find(gratt);
    if (itm != GrAmrk.end()) {
      mMrk = (*itm).second.mrk;  
      mMSz = (*itm).second.msz;  
      fgdec = true;  continue; 
    }
    if (fgdec) continue;
    // Si c'est un attribut de ArrowMarker (fleche)
    fgdec = false;
    GrAttArrowMarkers& GrAarrmrk = *GrAarrowMarkers;
    GrAttArrowMarkers::const_iterator itam = GrAarrmrk.find(gratt);
    if (itam != GrAarrmrk.end()) {
      mArrowMrk = (*itam).second.amrk;  
      mArrowMrkSz = (*itam).second.amsz;  
      fgdec = true;  continue; 
    }
    if (fgdec) continue;
    
    ndec--;
    if (rmdecatt)  udatt.push_back(gratt);
  }
  if (rmdecatt)  att = udatt;
  return(ndec);
}

int PIGraphicAtt::AttToStrings(vector<string> & att) const
{
  // On ne vide pas (ne met pas a zero) att, mais on ajoute derriere.
  //  att.push_back("??GraphicAtt??");
  char sbuff[32];
  string astr;
  int naj = 0;
  // ------ Attribut de couleur
  for (GrAttColors::const_iterator it = GrAcolors->begin(); 
       it != GrAcolors->end(); it++) 
    if ( (*it).second == mFCol ) {
      att.push_back((*it).first); 
      naj++;
      break;
    }
  // ------ Attribut de ligne
  astr = "line=";
  if (mLAtt.GetLineDash() == PI_LineSolid) astr += "solid,";
  else if (mLAtt.GetLineDash() == PI_LineDashed) astr += "dashed,";
  else if (mLAtt.GetLineDash() == PI_LineDotted) astr += "dotted";
  else if (mLAtt.GetLineDash() == PI_LineDashDotted) astr += "dashdotted";
  else astr += "solid,";
  sprintf(sbuff,"%d",mLAtt.GetLineWidth());
  astr += sbuff;
  att.push_back(astr); 
  naj++;
  // ------ Attribut de fonte
  astr = "font=";
  if (mFnt.GetFontName() == PI_CourierFont) astr += "courier,";
  else if (mFnt.GetFontName() == PI_HelveticaFont) astr += "helvetica,";
  else if (mFnt.GetFontName() == PI_TimesFont) astr += "times,";
  else if (mFnt.GetFontName() == PI_SymbolFont) astr += "symbol,";
  else astr += "courier,";
  if (mFnt.GetFontAtt() == PI_RomanFont) astr += "roman,";
  else if (mFnt.GetFontAtt() == PI_BoldFont) astr += "bold,";
  else if (mFnt.GetFontAtt() == PI_ItalicFont) astr += "italic,";
  else if (mFnt.GetFontAtt() == PI_BoldItalicFont) astr += "bolditalic,";
  else astr += "roman,";
  sprintf(sbuff,"%d",mFnt.GetFontSize());
  astr += sbuff;
  att.push_back(astr); 
  naj++;
  // ------ Attribut de table de couleur
  for (GrAttColMaps::const_iterator it = GrAcmaps->begin(); 
       it != GrAcmaps->end(); it++) 
    if ( (*it).second == mCmapid ) {
      att.push_back((*it).first); 
      naj++;
      break;
    }
  // Inversion d'indexage de ColorMap
  //  else if (gratt == "revcmap")  { 
  if (mRevCmap) {
    att.push_back("revcmap");
    naj++;
  }

  // ------ Attribut de marqueur
  const char* mrkn[11] = {"dot", "plus", "cross", 
			  "circle", "fcircle", 
			  "boxmarker", "fbox", 
			  "triangle", "ftriangle", 
			  "star", "fstar"};
  PIMarker mrk[11] = {PI_DotMarker, PI_PlusMarker, PI_CrossMarker, 
		      PI_CircleMarker, PI_FCircleMarker, 
		      PI_BoxMarker, PI_FBoxMarker, 
		      PI_TriangleMarker, PI_FTriangleMarker, 
		      PI_StarMarker, PI_FStarMarker};
  if (mMrk != PI_NotDefMarker) {
    astr = "marker=";
    for(int kk=0; kk<11; kk++) 
      if (mrk[kk] == mMrk)  { 
	astr += mrkn[kk];
	break;
      }
    sprintf(sbuff,",%d",mMSz);
    astr += sbuff;
    att.push_back(astr); 
    naj++;
  }
  if (mArrowMrk != PI_NotDefArrowMarker) {
    astr = "arrow=";
    if (mArrowMrk == PI_BasicArrowMarker)  astr += "basic";
    else if (mArrowMrk == PI_TriangleArrowMarker)  astr += "triangle";
    else if (mArrowMrk == PI_FTriangleArrowMarker)  astr += "ftriangle";
    else if (mArrowMrk == PI_ArrowShapedArrowMarker)  astr += "arrowshaped";
    else if (mArrowMrk == PI_FArrowShapedArrowMarker)  astr += "farrowshaped";
    else astr += "basic";
    sprintf(sbuff,",%d",mArrowMrkSz);
    astr += sbuff;
    att.push_back(astr); 
    naj++;
  }
  return naj;
}

int PIGraphicAtt::DecodeTextPosDirAtt(vector<string> & att, unsigned long& tdirpos, 
				   bool rmdecatt)
{
  if (att.size() == 0)  return(0);  
  tdirpos = PI_HorizontalLeft | PI_VerticalBottom | PI_TextDirectionHorizontal;
  int ndec = att.size();
  vector<string> udopt;
  int k;
  for( k=0; k<att.size(); k++ ) {
    string& opts = att[k];
    if (opts == "horizleft")  { 
      tdirpos &= (~PI_HorizontalPosition); 
      tdirpos |= PI_HorizontalLeft;
    }
    else if (opts == "horizcenter") {
      tdirpos &= (~PI_HorizontalPosition); 
      tdirpos |= PI_HorizontalCenter;
    }
    else if (opts == "horizright") {
      tdirpos &= (~PI_HorizontalPosition); 
      tdirpos |= PI_HorizontalRight;
    }
    else if (opts == "vertbottom") {
      tdirpos &= (~PI_VerticalPosition); 
      tdirpos |= PI_VerticalBottom;
    }
    else if (opts == "vertcenter") {
      tdirpos &= (~PI_VerticalPosition); 
      tdirpos |= PI_VerticalCenter;
    }
    else if (opts == "verttop") {
      tdirpos &= (~PI_VerticalPosition); 
      tdirpos |= PI_VerticalTop;
    }
    else if (opts == "textdirhoriz") {
      tdirpos &= (~PI_TextDirection); 
    }
    else if (opts == "textdirvertup") {
      tdirpos &= (~PI_TextDirection); 
      tdirpos |= PI_TextDirectionVerticalUp;
    }
    else if (opts == "textdirvertdown") {
      tdirpos &= (~PI_TextDirection); 
      tdirpos |= PI_TextDirectionVerticalDown;
    }
    else { 
      ndec--;
      if (rmdecatt)  udopt.push_back(opts);    
    }
  }
  if (rmdecatt)  att = udopt;
  return(ndec);
  
}
//++
// Titre	Changement des attributs graphiques
//--
//++
// void  SetColAtt(PIColors fg=PI_NotDefColor, PIColors bg=PI_NotDefColor)
//	Modifie la couleur d'avant-plan et de fond.
// void  SetLineAtt(PILineAtt lat=PI_NotDefLineAtt)
//	Modifie l'attribut type de ligne.
// void  SetLineAtt(PILineTypes ltyp=PI_NotDefLineAtt)
//	Modifie l'attribut type de ligne.
// void  SetFont(PIFont const & fnt)
//	Selection de fonte.
// void  SetFontAtt(PIFontName fn, PIFontSize fsz=PI_NotDefFontSize, PIFontAtt fat=PI_NotDefFontAtt)
//	Selection de type, taille et attribut de fonte
// void  SetFontAtt(PIFontSize fsz=PI_NotDefFontSize, PIFontAtt fat=PI_NotDefFontAtt)
//	Selection taille et attribut de fonte. 
// void  SetMarkerAtt(int sz=-1, PIMarker mrk=PI_NotDefMarker)
//	Modifie l'attribut type et taille de marker.
// void  SetMarkerAtt(PIMarker mrk=PI_NotDefMarker)
//	Modifie l'attribut type de marker.
// void  SetArrowMarkerAtt(int sz, PIArrowMarker mrk=PI_NotDefArrowMarker)
//	Modifie l'attribut type et taille de flèche.
// void  SetArrowMarkerAtt(PIArrowMarker mrk=PI_NotDefArrowMarker)
//	Modifie l'attribut type de flèche.
// void  SetColMapId(CMapId cid=CMAP_OTHER, bool rev=false)
//	L'attribut choix de la table de couleurs, et son flag d'inversion
//-- 
//++
// Titre	Accès aux attributs graphiques
//--
//++
// PIColors  GetColor() const
// PIColors  GetFgColAtt() const
//	Renvoie l'attribut de couleur d'avant-plan
// PIColors  GetBgColAtt() const
//	Renvoie l'attribut de couleur d'arrière-plan
// PILineAtt  GetLineAtt() const
// PILineAtt& GetLineAtt()
//	Renvoie l'attribut de ligne.
// PIFont  GetFont()  const
// PIFont& GetFont()
//	Renvoie l'attribut fonte.
// PIFontSize GetFontSz() const
//	Renvoie la taille de fonte
// int  GetFontSzPt() const 
// int  GetFontSize() const 
//	Renvoie la taille de fonte en points/pixels.
// PIFontAtt  GetFontAtt() const
//	Renvoie l'attribut de type de fonte (roman/bold/italique/...)
// PIFontName  GetFontName() const
//	Renvoie l'attribut nom de fonte (courier/helvetica...)
// int  GetMarkerSz() const
// int  GetMarkerSize() const
//	Renvoie la taille de marker.
// PIMarker GetMarker() const
//	Renvoie le type de marker.
// int  GetArrowMarkerSz() const
// int  GetArrowMarkerSize() const
//	Renvoie la taille de flèche.
// PIArrowMarker GetArrowMarker() const
//	Renvoie le type de flèche.
// CMapId GetColMapId()
//	Renvoie l'attribut de type de table de couleur
// CMapId GetColMapId(bool & rev)
//	Renvoie l'attribut de type de table de couleur, 
//	et le flag d'inversion de la table de couleur
//--


//++
// Titre	Utilitaires pour choix de couleur 
//--
//++
// 
// PIColors ColNameToColor(string const & colname)
//	Renvoie la couleur specifiee par le nom colname (methode static)
// PIColors ColIndexToColor(string const & colname)
//	Renvoie la couleur specifiee par le numero colidx
//	et le flag d'inversion de la table de couleur
//--

PIColors PIGraphicAtt::ColNameToColor(string const & colname)
{
  if (!gratt_init_done) InitGrAttStrings();
  GrAttColors& GrAcol = *GrAcolors;
  GrAttColors::const_iterator itc = GrAcol.find(colname);
  PIColors cdcol = PI_NotDefColor;
  if (itc != GrAcol.end())  cdcol = (*itc).second;  
  return cdcol;
}

PIColors PIGraphicAtt::ColIndexToColor(int colidx)
{
  if (!gratt_init_done) InitGrAttStrings();
  if ((colidx < 0) || (colidx >= GRA_NCOLMX))  return PI_NotDefColor;
  return GrAcolTab[colidx];
}
