///
/// \file TextField.cpp
/// Classe mere du composant TextField.
/// 
/// @author Nicolas Janey
/// @author nicolas.janey@univ-fcomte.fr
/// @version 1.0, 01/01/10
///

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>

#include "Controle.h"
#include "TextField.h"
#include "Couleur.h"
#include "ModuleFont.h"

///
/// Anti-warning.
///
/// @author Nicolas Janey
/// @author nicolas.janey@univ-fcomte.fr
/// @version 1.0, 25/02/10
///
#define UNREFERENCED_PARAMETER(P) (P)

///
/// Constructeur basique.
///
/// @author Nicolas Janey
/// @author nicolas.janey@univ-fcomte.fr
/// @version 1.0, 25/02/10
///
TextField::TextField(void):Controle() {
  pos = 0;
  ins = 1;
  coulBox = new Couleur();
  coulTexte = new Couleur();
  coulBackGround = new Couleur();
  coulForeGround = new Couleur();
  taille = 0;
  dx = 0;
  strcpy(str,"");
  strcpy(titre,"");
  save = NULL;
}

static void ajustement(char *s,int taille) {
  int t = taille/8;
  int n =(int) strlen(s);
  for ( int i = n ; i < t ; i++ ) {
    s[i] = ' '; }
  s[t] = 0x00;
}

///
/// Constructeur avec parametres d'initialisation.
///
/// @param px La position en x du TextField.
/// @param py La position en y du TextField.
/// @param dx La position en x de la zone de daisie par rapport à la position globale du TextField.
/// @param taille La taille de la zone de saisie.
/// @param coul La couleur de base du TextField.
/// @param coulB La couleur de dessin de l'encadrement.
/// @param titre La chaine de caracteres titre du TextField.
/// @param coulT La couleur de dessin du texte.
/// @param coulBG La couleur de dessin d'avant-plan.
/// @param coulFG La couleur de dessin d'arriere-plan.
/// @param s La chaine de carateres d'initialisation de la zone de saisie.
/// @author Nicolas Janey
/// @author nicolas.janey@univ-fcomte.fr
/// @version 1.0, 25/02/10
///
TextField::TextField(int px,int py,int dx,int taille,Couleur *coul,Couleur *coulB,const char *titre,Couleur *coulT,Couleur *coulBG,Couleur *coulFG,char *s):Controle(px,py,coul) {
  this->coulBox = new Couleur(coulB);
  this->coulTexte = new Couleur(coulT);
  this->coulBackGround = new Couleur(coulBG);
  this->coulForeGround = new Couleur(coulFG);
  this->taille = taille;
  this->dx = dx;
  strcpy(this->str,s);
  this->ins = 1;
  ajustement(s,taille);
  this->pos = 0;
  strcpy(this->titre,titre);
  save = NULL;
}

///
/// Constructeur avec parametres d'initialisation.
///
/// @param px La position en x du TextField.
/// @param py La position en y du TextField.
/// @param dx La position en x de la zone de daisie par rapport à la position globale du TextField.
/// @param taille La taille de la zone de saisie.
/// @param coul La couleur de base du TextField.
/// @param coulB La couleur de dessin de l'encadrement.
/// @param titre La chaine de caracteres titre du TextField.
/// @param coulT La couleur de dessin du texte.
/// @param coulBG La couleur de dessin d'avant-plan.
/// @param coulFG La couleur de dessin d'arriere-plan.
/// @author Nicolas Janey
/// @author nicolas.janey@univ-fcomte.fr
/// @version 1.0, 25/02/10
///
TextField::TextField(int px,int py,int dx,int taille,Couleur *coul,Couleur *coulB,const char *titre,Couleur *coulT,Couleur *coulBG,Couleur *coulFG):Controle(px,py,coul) {
  this->coulBox = new Couleur(coulB);
  this->coulTexte = new Couleur(coulT);
  this->coulBackGround = new Couleur(coulBG);
  this->coulForeGround = new Couleur(coulFG);
  this->taille = taille;
  this->dx = dx;
  strcpy(this->str,"");
  this->ins = 1;
  ajustement(str,taille);
  this->pos = 0;
  strcpy(this->titre,titre);
  save = NULL;
}

///
/// Destructeur.
///
/// @author Nicolas Janey
/// @author nicolas.janey@univ-fcomte.fr
/// @version 1.0, 25/02/10
///
TextField::~TextField(void) {
  delete(this->coulTexte);
  delete(this->coulBox);
  delete(this->coulBackGround);
  delete(this->coulForeGround);
  if ( save )
    free(save);
}

static void clipString(int x,int y,int z,char *s,int taille) {
  char st[200];
  strcpy(st,s);
  if ( strlen(st)*8 > (unsigned) taille-8 )
    st[taille/8] = 0x00;
  bitmapStringOutput(x,y,z,st);
}

void TextField::initialise(void) {
  this->ins = 1;
  ajustement(str,taille);
  this->pos = 0;
}

///
/// Dessin du TextField.
///
/// @author Nicolas Janey
/// @author nicolas.janey@univ-fcomte.fr
/// @version 1.0, 25/02/10
///
void TextField::dessiner(void) {
  if ( !enabled )
    actif = 0;
  glDisable(GL_LIGHTING);
  glPushMatrix();
  glTranslatef(px,py,0.0F);
  { setGLColor((float *) coulBox);
    glPushMatrix();
    glTranslatef(dx,0.0F,0.0F);
    glBegin(GL_LINE_LOOP);
    glVertex2i(0,5);
    glVertex2i(0,-13);
    glVertex2i(taille,-13);
    glVertex2i(taille,5);
    glEnd();
    glPopMatrix(); }
  if ( actif ) {
    glPushMatrix();
    glTranslatef(dx-1,0.0F,0.0F);
    glBegin(GL_QUADS);
    setGLColor((float *) coulBackGround);
    glVertex2i(2,4);
    glVertex2i(2,-11);
    glVertex2i(taille-1,-11);
    glVertex2i(taille-1,4);
    setGLColor((float *) coulForeGround);
    glVertex3i(2+pos*8,4,1);
    glVertex3i(2+pos*8,-11,1);
    glVertex3i(pos*8+10,-11,1);
    glVertex3i(pos*8+10,4,1);
    glEnd();
    glPopMatrix(); }
  { setGLColor((float *) coulTexte);
    setFont(GLUT_BITMAP_8_BY_13,LEFT);
    glPushMatrix();
    bitmapStringOutput(0.0F,0.0F,1.0F,titre);
    glPopMatrix(); }
  { setFont(GLUT_BITMAP_8_BY_13,LEFT);
    glPushMatrix();
    glTranslatef(dx,0.0F,0.0F);
    setGLColor((float *) ((actif) ? coulForeGround : coul));
    clipString(1,0,1,str,(int) taille);
    setGLColor((float *) ((actif) ? coulBackGround : coul));
    bitmapStringOutput(2+8*pos-1,0,2,"%c",str[pos]);
    glPopMatrix(); }
  glPopMatrix();
}

///
/// Sauvegarde des valeurs actuelles liees au TextField.
///
/// @author Nicolas Janey
/// @author nicolas.janey@univ-fcomte.fr
/// @version 1.0, 25/02/10
///
void TextField::sauve(void) {
  if ( str ) {
    if ( save )
      free(save);
    save =(char *) calloc(strlen(str)+1,sizeof(char));
    if ( save )
      strcpy(save,str); } 
}

///
/// Restoration des valeurs sauvegardees liees au TextField.
///
/// @author Nicolas Janey
/// @author nicolas.janey@univ-fcomte.fr
/// @version 1.0, 25/02/10
///
void TextField::annule(void) {
  if ( str )
    strcpy(str,save);
}

///
/// Selection du TextField lie a la position (x,y).
///
/// @param x La coordonnee x.
/// @param y La coordonnee y.
/// @return Le booleen indiquant que la selection a bien ete geree.
/// @author Nicolas Janey
/// @author nicolas.janey@univ-fcomte.fr
/// @version 1.0, 25/02/10
///
int TextField::selection(int x,int y) {
  if ( enabled ) {
    int xi = px+dx;
    int xf = px+dx+taille;
    int yi = py-10;
    int yf = py+2;
    if ( ( x >= xi ) && ( x <= xf ) && ( y >= yi ) && ( y <= yf ) ) {
      actif = !actif;
      pos = 0;
      return(1); } }
  return(-1);
}

///
/// Modification du TextField lie a la position (x,y) et a un vecteur (dx,dy).
///
/// @param x La coordonnee x.
/// @param y La coordonnee y.
/// @param dx La valeur dx.
/// @param dy La valeur dy.
/// @return Le booleen indiquant que la selection a bien ete geree.
/// @author Nicolas Janey
/// @author nicolas.janey@univ-fcomte.fr
/// @version 1.0, 25/02/10
///
int TextField::gereModification(int,int,int,int) {
  return(0);
}

static int mymin(int a,int b) {
  return(( a < b ) ? a : b);
}

///
/// Gestion clavier du TextField lie a la position (x,y).
///
/// @param c Le caractere frappe au clavier.
/// @param x La coordonnee x.
/// @param y La coordonnee y.
/// @return Le booleen indiquant que la clavier a bien ete gere.
/// @author Nicolas Janey
/// @author nicolas.janey@univ-fcomte.fr
/// @version 1.0, 25/02/10
///
int TextField::gereKeyboard(unsigned char c,int x,int y) {
  UNREFERENCED_PARAMETER(x);
  UNREFERENCED_PARAMETER(y);
  switch ( (int) c ) {
    case 0x08 : if ( pos != 0 ) {
                  pos--; }
                  else
                  break;
    case 0x7F : { for ( int i = pos ; i < (int) strlen(str)-1 ; i++ )
                    str[i] = str[i+1];
                  str[strlen(str)-1] = ' ';
                  return(2); }
                break;
    case 0x0D : actif = !actif; 
                return(1);
                break;
    case 'A'  :
    case 'B'  :
    case 'C'  :
    case 'D'  :
    case 'E'  :
    case 'F'  :
    case 'G'  :
    case 'H'  :
    case 'I'  :
    case 'J'  :
    case 'K'  :
    case 'L'  :
    case 'M'  :
    case 'N'  :
    case 'O'  :
    case 'P'  :
    case 'Q'  :
    case 'R'  :
    case 'S'  :
    case 'T'  :
    case 'U'  :
    case 'V'  :
    case 'W'  :
    case 'X'  :
    case 'Y'  :
    case 'Z'  : 
    case 'a'  :
    case 'b'  :
    case 'c'  :
    case 'd'  :
    case 'e'  :
    case 'f'  :
    case 'g'  :
    case 'h'  :
    case 'i'  :
    case 'j'  :
    case 'k'  :
    case 'l'  :
    case 'm'  :
    case 'n'  :
    case 'o'  :
    case 'p'  :
    case 'q'  :
    case 'r'  :
    case 's'  :
    case 't'  :
    case 'u'  :
    case 'v'  :
    case 'w'  :
    case 'x'  :
    case 'y'  :
    case 'z'  :
    case '0'  :
    case '1'  :
    case '2'  :
    case '3'  :
    case '4'  :
    case '5'  :
    case '6'  :
    case '7'  :
    case '8'  :
    case '9'  :
    case '-'  :
    case '/'  :
    case '\\' :
    case ' '  :
    case '_'  :
    case '#'  :
    case '*'  :
    case '+'  :
    case '.'  : if ( ins ) {
                  for ( int i = mymin(taille/8-1,(int) strlen(str)-1) ; i > pos ; i-- )
                    str[i] = str[i-1]; }
                str[pos] = c;
                pos++ ;
                if ( pos > mymin(taille/8-1,(int) strlen(str)-1) )
                  pos = mymin(taille/8-1,(int) strlen(str)-1);
                return(2);
                break; }
  return(0);
}

///
/// Gestion du clavier special du TextField lie a la position (x,y).
///
/// @param c Le code du caractere frappe au clavier.
/// @param x La coordonnee x.
/// @param y La coordonnee y.
/// @return Le booleen indiquant que la clavier a bien ete gere.
/// @author Nicolas Janey
/// @author nicolas.janey@univ-fcomte.fr
/// @version 1.0, 25/02/10
///
int TextField::gereSpecial(int c,int x,int y) {
  UNREFERENCED_PARAMETER(x);
  UNREFERENCED_PARAMETER(y);
  switch(c) {
    case GLUT_KEY_INSERT : ins = !ins;
                           return(0);
                           break;
    case GLUT_KEY_LEFT   : pos-- ;
                           if ( pos < 0 )
                             pos = 0;
                           return(2);
                           break;
    case GLUT_KEY_RIGHT  : pos++ ;
                           if ( pos > mymin(taille/8-1,(int) strlen(str)-1) )
                             pos = mymin(taille/8-1,(int) strlen(str)-1);
                           return(2);
                           break; }
  return(0);
}

///
/// Configuration du texte du TextField.
///
/// @param text La chaine de carateres a affecter.
/// @author Nicolas Janey
/// @author nicolas.janey@univ-fcomte.fr
/// @version 1.0, 25/02/10
///
void TextField::setText(char *text) {
  strcpy(str,text);
  ajustement(str,taille);
  this->pos = 0;
}

///
/// Lecture du texte du TextField.
///
/// @param text La chaine de carateres ou sauvegarder le texte lu.
/// @author Nicolas Janey
/// @author nicolas.janey@univ-fcomte.fr
/// @version 1.0, 25/02/10
///
void TextField::getText(char *text) {
  strcpy(text,str);
  int j =(int) strlen(text)-1;
  while ( text[j] == ' ' ) {
    text[j] = 0x00;
    j--; }
}

///
/// Sauvegarde du TextField dans un fichier.
///
/// @param f Le fichier de sauvegarde.
/// @author Nicolas Janey
/// @author nicolas.janey@univ-fcomte.fr
/// @version 1.0, 25/02/10
///
void TextField::sauve(FILE *f) {
  if ( strcmp(name,"") ) {
    char texte[512];
    getText(texte);
    fprintf(f,"  <%s valeur=\"%s\"></%s>\n",name,texte,name); }
}
