

#include <map>
#include <list>
#include <string>

#include <cstdio>
#include <cstring>

#include <Gl/gl.h>
#include <GL/glu.h>

#include "CConsole.hpp"
#include "CTextures.hpp"

using namespace std;


extern int hc,wc;


//---------------------------------------
// Récupère la liste des smileys depuis
// le fichier de configuration
// smiley.conf
//---------------------------------------
bool CConsole::RecupererSmiley()
{
  FILE *fp = NULL;
  c_log << "<b>CConsole::RecupererSmiley()</b>";
  if (!(fp = fopen("./textures/smiley/smiley.conf","rb")))
     return false;

  char ligne[256]="";
  int  nombre = 0;
  bool smi = false;  // init..
  int  i=0;

  // On va récupérer le nombre de smiley
  for  (;fgets(ligne,256,fp);) {
    //c_log.printf("ligne_courante: %s",ligne);

    if (*ligne != '/' && *(ligne+1) != '/') // ce n'est pas un commentaire
    {
      if (!smi) {
        // On doit avoir le nombre
        char buf[256];
        int  nombre=0;
        strcpy(buf,ligne);
        nombre = atoi(buf);
        c_log.printf("nombre: %i",nombre,buf);
        if (nombre > 99 || nombre < 1)
        { // ben c une erreur ineplicable ;)
           c_log << "Erreur de dimensionnement, la fonction retournera <b>false</b>";
           return false;
        }
        else {
          smi = true;
          nb = nombre;
          // On va aussi allouer notre structure !
          smile = new SMILEY [nombre];
          if (!smile) {
             c_log << "Erreur d'allocation de smile dans CConsole::RecupererSmiley();";
             return false;
          }
        }
      }
      else // alors on récupère les smileys
      {
        char val[50], image[50];
        int  l=0,h=0;

        // J'admet à partir d'aujourd'hui que *scanf ca peut servir ... :D
        sscanf(ligne,"%s %s %i,%i",val,image,&l,&h);
        //c_log.printf ("val=%s | image=%s | dim=(%i,%i)",val,image,l,h);
        char llllllll[256]="./textures/smiley/";
        strcat(llllllll,image);
        strcat(llllllll,".tga");

        // on remplit notre structure
        strcpy (smile[i].rec,val);
        strcpy (smile[i].str,llllllll);
        smile[i].width = l;
        smile[i].height= h;
        //c_log.printf ("%d == <b>pattern</b>=[<b>%s</b>] | <b>texture</b>=%s | <b>dimensions</b>=(%i,%i)",i,smile[i].rec,smile[i].str,smile[i].width,smile[i].height);
        ++i;
      }
    }
    memset(ligne,0,256*sizeof(char));
  }
  fclose(fp);



  //delete [] smile;

  return true;
}


bool CConsole::g_LoadSmiley()
{
  if (!RecupererSmiley ())
     return false;

  bool etat;
  STOCKAGE stock;

  // Charger les textures ...
  for (int i=0;i<nb;i++)
  {
    etat = false;
    etat = gl_GenTexture(stock.id,
                         smile[i].str,
                         GL_LINEAR_MIPMAP_LINEAR,
                         GL_LINEAR_MIPMAP_LINEAR,
                         GL_REPEAT,
                         GL_REPEAT,
                         1);
                         
    c_log.printf ("<b>(CConsole::g_LoadSmiley)</b> %s =)> %i",smile[i].str,etat);

    if (!etat)
        return false;
    else
        {
        	// on ajoute dans le map
        	 string tmp = smile[i].rec;
           stock.w    = smile[i].width;
           stock.h    = smile[i].height;
           atos[tmp]  = stock;
        }
  }

  // log : affichage des map;
  c_log << "Affichage du map des smileys rempli !";
  c_log << "tableau = {";
  for (int i=0;i<nb;i++) {
      stock = atos[smile[i].rec];
      c_log.printf ("[%i,%i,%i] <-> (%s)",stock.id,stock.w,stock.h,smile[i].rec) ;
  }
  c_log << "};";

  delete [] smile;

  return true;
}



bool CConsole::Init()
{
  l_cons.clear();
  l_cons.push_front(ver_string);
  c_i = 1;
  c_nb_lines = 1;
  s_cons = "$";

  pos_x = 0;
  pos_y = 16;

  // Charger la texture de la console
  if (!(gl_GenTexture(text_id,"./textures/Console.tga",
                      GL_LINEAR_MIPMAP_LINEAR, 
                      GL_LINEAR_MIPMAP_LINEAR,
                      GL_REPEAT, GL_REPEAT, 1)))
      return false;

  // Charger les smileys et l'acces
  // par clé dans le map
  if (!g_LoadSmiley())
     return false;

  return true;
};


void CConsole::ALaLigne()
{
   // On est deja a la ligne
   if (s_cons == "$")
      return;
   l_cons.push_back(s_cons);
   s_cons = "$";
   c_i = 1;
   pos_y += 16;
   pos_x  = 16;
}


// Ajouter le string c ds le s_cons courant !
template <typename T>
void CConsole::PushString(T c)
{
   const unsigned int t=strlen((char *)c);
   for (int i=0;i<t;i++)
       s_cons[c_i+i] = c[i];
   c_i += t;
}

// Ajouter un caractère c
void CConsole::PushChar(unsigned char c)
{
  if (c_i == 0) {
    s_cons += "$";
    ++c_i;
  }
  s_cons[c_i++] = c;
}

// Effacer un caractère
void CConsole::PopChar()
{
  if (c_i<2) { // Si l'indice est zéro alors
    c_i = 1;   //    on bouge pas ...
    return;
  }
  s_cons[--c_i] = '\0';
}

void CConsole::PushKey(unsigned char key)
{
  switch (key)
  {
  	case 13:  // KEY_ENTER
    {
         int k = Action();
         PushString (s_cons.c_str());
         ALaLigne   ();
    }
    break;

    case 8: // KEY_DEL
         PopChar();
    break;

    default:
         if (key >= 32 && key <= 126)
             PushChar(key);
    break;
  }
}

int CConsole::Sortie(int erreur, int pos)
{
  return -2;
}

int CConsole::Action()
{
  // On va valider s_cons !


  return 0;
}


void CConsole::DrawSmiley(int loc_x, int loc_y, unsigned int id, float color_3f[3], int tailles[2])
{
  // c_log.printf ("<b>(CConsole::DrawSmiley)</b> @[%i,%i] , id=%i, dim=(%i,%i)",loc_x,loc_y,id,tailles[0],tailles[1]);


  glColor4f (1.0,1.0,1.0,1.0);   // On remet la couleur a
                                 // sa puissance maximale
  glEnable      (GL_BLEND);
  glBlendFunc   (GL_ONE,GL_SRC_ALPHA);

	glBindTexture(GL_TEXTURE_2D, id);
	glDisable(GL_DEPTH_TEST);
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
		glLoadIdentity();
		glOrtho(0,wc,0,hc,-1,1);
		glMatrixMode(GL_MODELVIEW);

		glPushMatrix();                      // sauvegarde de la matrice !!!!
			glLoadIdentity();
			glTranslated(loc_x,hc - loc_y,0);  // la position est bien TAILLE_Y - y !!!!
			                                   // ( ct mon erreur :'( )
              glBegin (GL_QUADS);
            		glTexCoord2i(0, 0);  glVertex2i(0,  0);
            		glTexCoord2i(1, 0);  glVertex2i(tailles[0], 0);
            		glTexCoord2i(1, 1);  glVertex2i(tailles[0],tailles[1]);
            		glTexCoord2i(0, 1);  glVertex2i(0, tailles[1]);
              glEnd ();

			glMatrixMode(GL_PROJECTION);
		glPopMatrix();
		glMatrixMode(GL_MODELVIEW);

	glPopMatrix(); 
  
  // On recharge la matrice sauvegardée prédédement
	glEnable (GL_DEPTH_TEST);
  glDisable(GL_BLEND);

  
  glColor3f (color_3f[0],color_3f[1],color_3f[2]);
}

void CConsole::DrawChar(unsigned char c, int set)
{
  // positionner à (pos_x,pos_y) le smiley ID
  float scale[2] = {1.0f,1.0f};
  fonte.DrawChar(pos_x,pos_y,set,scale,c);
}

string trim(const string& s) {
  if(s.length() == 0)
    return s;
  int b = s.find_first_not_of(" \t");
  int e = s.find_last_not_of(" \t");
  if(b == -1) // No non-spaces
    return "";
  return string(s, b, e - b + 1);
}

void CConsole::c_DrawStr(const char *str, float color_rgb[], int set)
{
  float scale[2] = {1,1};
  map<string,STOCKAGE>::iterator place = 0;
  string  tmp;

  glColor4f (color_rgb[0],color_rgb[1],color_rgb[2],1.0f);
  int    loc_x = 0;
  char    *ptr = (char *)str;
  int   dim[2] = {0,0};
  unsigned int index;

  while (*str) {
     
     char mot[50]={0};

     if (*str == '$') {
       fonte.DrawChar(loc_x,pos_y,0,scale,*str);
       str++;
       loc_x += 16;
     }
     // On va récupérer le nom
     mot[index=0] = *str;
     ++str;
     while (*str && *str != ' ' && index<50)
           mot[++index] = *str++;

     // mot est notre mot !
     //tmp = mot;
     tmp = trim(string(mot));  // les espaces faisaient chier ... maintenant, ca va mieux !
     // On affiche le smiley
     place = atos.find(tmp);
     if (place != atos.end()) {
        STOCKAGE st = atos[tmp];
        dim[0] = st.w;
        dim[1] = st.h;
        DrawSmiley (loc_x+10, pos_y+1, st.id,color_rgb,dim);
        loc_x += st.w;
      }
     else
      {
        // on affiche simplement le mot
        o_DrawStr (loc_x,mot,color_rgb,set);
      }
  }
}


void CConsole::o_DrawStr(int &loc_x, const char *str, float color_rgb[], int set)
{
  float scale[2] = {1,1};
  glColor4f (color_rgb[0],color_rgb[1],color_rgb[2],1.0f);
  //fonte.Print (16,pos_y,1,scale,(char *)str);
  while (*str){
    fonte.DrawChar(loc_x,pos_y,set,scale,*str);
    ++str;
    loc_x += 10;
  }
}

void CConsole::show(int w, string str)
{
  STOCKAGE l = atos[str];
  float color_reponse[3] = {1,1,1};
  int dim[2];
  dim[0]=l.w;
  dim[1]=l.h;
  DrawSmiley (w,200,l.id,color_reponse,dim);
};


void CConsole::Render ()
{

  glDisable (GL_LIGHTING);			//positionnement de la lumière avec
  glDisable (GL_LIGHT0  );			//ca y est.

  glColor4f (1.0f,1.0f,1.0f,1.0f);
  glEnable(GL_TEXTURE_2D);

  float         scale[2] = {1,1};
  float color_titre  [3] = {0.4,1,0.4};
  float color_reponse[3] = {1,1,1};

  Transition (480); // c'est etabli !

  // principe:
  //    - Afficher le titre
  //    - Afficher tout le l_cons avec l'iterator
  //    - Afficher alors s_cons !
  //
  it_cons=l_cons.begin();
  ++it_cons;
 
  pos_y=16;
  c_DrawStr (ver_string.c_str(),color_titre,0);
    for (pos_y=32;it_cons!=l_cons.end();++it_cons,pos_y+=16)
      c_DrawStr ((*it_cons).c_str(),(pos_y==16?color_titre:color_reponse),1);
  int i=0;
  o_DrawStr (i,s_cons.c_str(),color_reponse,1);


  glEnable(GL_LIGHT0  );			 //ca y est.
  glEnable(GL_LIGHTING);
}


void CConsole::Transition(int valeur)
{
  glEnable      (GL_BLEND);
  glBlendFunc   (GL_SRC_ALPHA,GL_ONE_MINUS_SRC_COLOR);
	
  glBindTexture(GL_TEXTURE_2D, text_id);
	glDisable(GL_DEPTH_TEST);
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
		glLoadIdentity();
		glOrtho(0,wc,0,hc,-1,1);
		glMatrixMode(GL_MODELVIEW);

		glPushMatrix();                      // sauvegarde de la matrice !!!!
			glLoadIdentity();
			glTranslated(0,hc-valeur,0);  // la position est bien TAILLE_Y - y !!!!
			                       // ( ct mon erreur :'( )
              glBegin (GL_QUADS);
            		glTexCoord2i(0,0);   glVertex2i(0,    0);
            		glTexCoord2i(1,0);   glVertex2i(640,  0);
            		glTexCoord2i(1,1);   glVertex2i(640,480);
            		glTexCoord2i(0,1);   glVertex2i(0,  480);
              glEnd ();

			glMatrixMode(GL_PROJECTION);
		glPopMatrix();
		glMatrixMode(GL_MODELVIEW);

	glPopMatrix(); 
  
  // On recharge la matrice sauvegardée prédédement
	glEnable (GL_DEPTH_TEST);
  glDisable(GL_BLEND);
}


