/*****************************************************************************
 *
 *  Copyright (C) 2003 Cédric Brégardis <cedric.bregardis@free.fr>
 *
 *  This file is part of BRIQUOLO
 *
 *  BRIQUOLO is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  BRIQUOLO is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with BRIQUOLO; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *****************************************************************************/
#include "TableauBase.h"
#include "Gestionnaire.h"
#include <MOGL_Temps.h>
#include <MOGL_GestionnaireObjet.h>
#include <fstream>
#include <sstream>
#include "Constante.h"
#include "I18n.h"

#ifdef WIN32
  #include <sys/types.h>
  #include <sys/stat.h>
  #include <io.h>
#else
  #include <dirent.h>
  #include <sys/stat.h>
  #include <sys/types.h>
  #include <unistd.h>
#endif

TableauBase::Vect_NomGroupe TableauBase::_VectNomGroupe;

TableauBase::TableauBase(MOGL_Fenetre * p_Fenetre)
  : MOGL_Action(), _Fenetre(p_Fenetre), _XMin(0), _XMax(40), _YMin(-3), _YMax(50),
    _Activation(false), _NomTableau("")
{
  _Univers=new MOGL_Univers;
//  _Univers->DessinerBord(true);
  MOGL_Struct_Vecteur Vec;
  Vec.x=-0.2f;
  Vec.y=0.2f;
  Vec.z=-1;

  _TableauMOGL=new MOGL_Objet();
  MOGL_GestionnaireObjet::ChargerObjetASCTriangle((Constante::GetGlobalDir()+Constante::GetDataDir()+"/tableau.tri").c_str(),
                                                  *Texture::GetGestionnaireTexture(), *_TableauMOGL);
  _Univers->AjouterElement(_TableauMOGL);

  _Lumiere.SetDirection(Vec);
  //_Lumiere.ProjeterOmbre(true);
  _Univers->AjouterElement (&_Lumiere);

  _Fond=new MOGL_Objet;
  MOGL_GestionnaireObjet::ChargerObjetASCTriangle((Constante::GetGlobalDir()+Constante::GetDataDir()+"/env.tri").c_str(),
                                                  *Texture::GetGestionnaireTexture(), *_Fond);

  _Univers->AjouterElementFond(_Fond);
  SetPause(false);
}

TableauBase::~TableauBase()
{
  delete _Fond;
  delete _TableauMOGL;
  delete _Univers;
}

void TableauBase::ClavierUp(SDL_keysym * key)
{
}

void TableauBase::ClavierDown(SDL_keysym * key)
{
}

void TableauBase::DeplacementSouris(SDL_MouseMotionEvent * p_Event)
{
}

void TableauBase::BoutonSourisUp(SDL_MouseButtonEvent * p_Event)
{
}

void TableauBase::BoutonSourisDown(SDL_MouseButtonEvent * p_Event)
{
}


float TableauBase::GetXMin() const
{
  return _XMin;
}

float TableauBase::GetXMax() const
{
  return _XMax;
}

float TableauBase::GetYMin() const
{
  return _YMin;
}

float TableauBase::GetYMax() const
{
  return _YMax;
}

void TableauBase::Activer(bool p_Activation)
{
  if (p_Activation!=_Activation)
  {
    _Activation=p_Activation;
    if (_Activation)
    {
      _Fenetre->AjouterInterface(_Univers);
    }
    else
    {
      _Fenetre->RetirerInterface(_Univers);
    }
  }
}

void TableauBase::AjouterElementTableau(ElementTableau * p_ElementTableau)
{
  _SetElementTableau.insert(p_ElementTableau);
  if (p_ElementTableau->GetElementArbreMOGL()!=NULL)
  {
    _Univers->AjouterElement(p_ElementTableau->GetElementArbreMOGL());
  }
}

bool TableauBase::RetirerElementTableau(ElementTableau * p_ElementTableau)
{
  Set_ElementTableau::iterator it=_SetElementTableau.find(p_ElementTableau);
  if (it!=_SetElementTableau.end())
  {
    if (p_ElementTableau->GetElementArbreMOGL()!=NULL)
    {
      _Univers->RetirerElement(p_ElementTableau->GetElementArbreMOGL());
    }
    _SetElementTableau.erase(it);
    return true;
  }
  else
  {
    return false;
  }
}

void TableauBase::EffacerTousElementTableau()
{
  for(Set_ElementTableau::iterator it=_SetElementTableau.begin(); it!=_SetElementTableau.end(); it++)
  {
    if ((*it)->GetElementArbreMOGL()!=NULL)
    {
      _Univers->RetirerElement((*it)->GetElementArbreMOGL());
    }
    delete (*it);
  }
  _SetElementTableau.clear();
}

void TableauBase::SetPause(bool p_Pause)
{
  _Pause=p_Pause;
  MOGL_Temps::SetPause(_Pause);
}

bool TableauBase::GetPause() const
{
  return _Pause;
}

void TableauBase::Maj()
{
}

bool TableauBase::Sauvegarder(const char * p_NomFichier)
{
  ofstream fichier(p_NomFichier);
  if (!fichier.good())
  {
    return false;
  }
  fichier<<_SetElementTableau.size()<<endl;
  if (!fichier.good())
  {
    return false;
  }
  for(Set_ElementTableau::iterator it=_SetElementTableau.begin(); it!=_SetElementTableau.end(); it++)
  {
    fichier<<(*it)->GetId()<<' '<<(*it)->GetPositionX()<<' '<<(*it)->GetPositionY();
    if ((*it)->GetLigneOption() != "")
    {
      fichier<<' '<<(*it)->GetLigneOption();
    }

    fichier<<endl;
    if (!fichier.good())
    {
      return false;
    }
  }
  return true;
}

bool TableauBase::Charger(const char * p_NomFichier)
{
  ifstream fichier(p_NomFichier);
  if (!fichier.good())
  {
    return false;
  }

  string myString;
  stringstream mySSt;

  getline(fichier, myString);
  mySSt.str(myString);

  unsigned int nb;
  mySSt>>nb;

  unsigned int id;
  float x,y;
  for(unsigned int i=0; i< nb; i++)
  {
    getline(fichier, myString);
    istringstream myStringStream(myString);
    myStringStream>>id>>x>>y;
    stringstream reste;
    myStringStream.get(*reste.rdbuf());

    ElementTableau * elem=Gestionnaire::GetElementTableau(id, this);
    elem->SetPosition(x, y);
    if (reste.str() != "")
    {
      string st = reste.str().substr(1, reste.str().size()-1);
      elem->SetLigneOption(st);
    }
    MOGL_Objet * objelem = dynamic_cast<MOGL_Objet *>(elem->GetElementArbreMOGL());
    if (objelem != NULL)
    {
      objelem->SetTailleBord(5);
      MOGL_Struct_Couleur coul = {1,0,0,1};
      objelem->SetCouleurBord(coul);
    }
    elem->InitialiserPosition();
    AjouterElementTableau(elem);
  }
  return true;
}

string TableauBase::GetGroupeTableauDesc(const string & base, const string & dir)
{
  string fichier=base;
  fichier+=dir;
  fichier+="/description";

  std::ifstream file(fichier.c_str());
  if (file.good())
  {
    string desc;
    string defaultDesc = dir;
    while (!file.eof())
    {
      string line, idPays;
      idPays = "Desc[" + GetIdCountry() + ']';
      getline(file, line);
      if (line.substr(0,8) == idPays)
      {
        desc = line.substr(9, line.size() - 9);
        break;        
      }
      else if (line.substr(0,5) == "Desc=")
      {
        defaultDesc = line.substr(5, line.size() - 5);
      }
    }
    if (desc != "")
    {
      return desc;
    }
    else
    {
      return defaultDesc;
    }
  }
  else
  {
    return dir;
  }
}

list<string> TableauBase::GetListeGroupeTableau()
{
    set<string> preprocList;
    list<string> liste;
    _VectNomGroupe.clear();
#ifdef WIN32
    // Fichiers locaux
    string rep(Constante::GetLocalDir());
    rep+=Constante::GetTableauDir();
    rep+='/';


    WIN32_FIND_DATA wData;
    HANDLE listing;
    listing = FindFirstFile((rep+"*").c_str(),    &wData);
    do
    {
        string fichier=rep+wData.cFileName;
        struct _stat stat_fic;
        _stat(fichier.c_str(), &stat_fic);
        if ((stat_fic.st_mode&_S_IFDIR)!=0 && _access(fichier.c_str(), 04)==0)
        {
            string le_fic(wData.cFileName);
            if (le_fic!="" && le_fic != "." && le_fic != "..")
            {
                if (GetListeTableau(le_fic).size() != 0)
                {
                    liste.push_back(GetGroupeTableauDesc(rep, le_fic));
                    _VectNomGroupe.push_back(le_fic);
                }
            }
        }
    } while((FindNextFile(listing, &wData)));

    // Fichiers globals
    rep=Constante::GetGlobalDir();
    rep+=Constante::GetTableauDir();
    rep+='/';
    listing = FindFirstFile((rep+"*").c_str(), &wData);
    do
    {
        string fichier=rep+wData.cFileName;
        struct _stat stat_fic;
        _stat(fichier.c_str(), &stat_fic);
        if ((stat_fic.st_mode&_S_IFDIR)!=0 && _access(fichier.c_str(), 04)==0)
        {
            string le_fic(wData.cFileName);
            if (le_fic!="" && le_fic != "." && le_fic != "..")
            {
                if (GetListeTableau(le_fic).size() != 0)
                {
                    liste.push_back(GetGroupeTableauDesc(rep, le_fic));
                    _VectNomGroupe.push_back(le_fic);
                }
            }
        }
    } while((FindNextFile(listing, &wData)));

#else
    // Fichiers locaux
    string rep(Constante::GetLocalDir());
    rep+=Constante::GetTableauDir();
    rep+='/';
  
    dirent * mon_dirent;
    DIR * dir=opendir(rep.c_str());
    if (dir!=NULL)
    {
        mon_dirent=readdir(dir);
        while ( mon_dirent!=NULL )
        {
            string fichier=rep+mon_dirent->d_name;
            struct stat stat_fic;
            stat(fichier.c_str(), &stat_fic);
            if (S_ISDIR(stat_fic.st_mode) && access(fichier.c_str(),R_OK)==0 && access(fichier.c_str(),X_OK)==0)
            {
                string le_rep(mon_dirent->d_name);
                if (le_rep != ".." && le_rep != ".")
                {
                    // C'est un répertoire, et on peut y accéder
                    if (GetListeTableau(le_rep).size() != 0)
                    {
                        preprocList.insert(le_rep);
                    }
                }
            }
            mon_dirent=readdir(dir);
        }
        for(set<string>::iterator it = preprocList.begin(); it != preprocList.end(); it++)
        {
            liste.push_back(GetGroupeTableauDesc(rep, *it));
            _VectNomGroupe.push_back(*it);      
        }
    }

    // Fichiers globals
    preprocList.clear();
    rep=Constante::GetGlobalDir();
    rep+=Constante::GetTableauDir();
    rep+='/';

    dir=opendir(rep.c_str());
    if (dir!=NULL)
    {
        mon_dirent=readdir(dir);
        while (mon_dirent!=NULL)
        {
            string fichier=rep+mon_dirent->d_name;
            struct stat stat_fic;
            stat(fichier.c_str(), &stat_fic);
            if (S_ISDIR(stat_fic.st_mode) && access(fichier.c_str(),R_OK)==0 && access(fichier.c_str(),X_OK)==0)
            {
                string le_rep(mon_dirent->d_name);
                if (le_rep != ".." && le_rep != ".")
                {
                    // C'est un répertoire, et on peut y accéder
                    if (GetListeTableau(le_rep).size() != 0)
                    {
                        preprocList.insert(le_rep);
                    }
                }
            }
            mon_dirent=readdir(dir);
        }
        for(set<string>::iterator it = preprocList.begin(); it != preprocList.end(); it++)
        {
            liste.push_back(GetGroupeTableauDesc(rep, *it));
            _VectNomGroupe.push_back(*it);      
        }

    }
#endif

    return liste;
}

set<string> TableauBase::GetListeTableau(const string & p_NomGroupe)
{
  set<string> liste;
#ifdef WIN32
  // Fichiers locaux
  string rep(Constante::GetLocalDir());
  rep+=Constante::GetTableauDir();
  rep+='/'+p_NomGroupe+'/';


  WIN32_FIND_DATA wData;
  HANDLE listing;
  listing = FindFirstFile((rep+"*.tab").c_str(),    &wData);
  do
  {
    string fichier=rep+wData.cFileName;
    struct _stat stat_fic;
    _stat(fichier.c_str(), &stat_fic);
    if ((stat_fic.st_mode&_S_IFDIR)==0 && _access(fichier.c_str(), 04)==0)
    {
      string le_fic(wData.cFileName);
      if (le_fic!="")
      {
        le_fic= le_fic.substr(0, le_fic.length()-4);
        liste.insert(le_fic);
      }
    }
  } while((FindNextFile(listing, &wData)));

  // Fichiers globals
  rep=Constante::GetGlobalDir();
  rep+=Constante::GetTableauDir();
  rep+='/'+p_NomGroupe+'/';
  listing = FindFirstFile((rep+"*.tab").c_str(),    &wData);
  do
  {
    string fichier=rep+wData.cFileName;
    struct _stat stat_fic;
    _stat(fichier.c_str(), &stat_fic);
    if ((stat_fic.st_mode&_S_IFDIR)==0 && _access(fichier.c_str(), 04)==0)
    {
      string le_fic(wData.cFileName);
      if (le_fic!="")
      {
        le_fic= le_fic.substr(0, le_fic.length()-4);
        liste.insert(le_fic);
      }
    }
  } while((FindNextFile(listing, &wData)));

#else
  // Fichiers locaux
  string rep(Constante::GetLocalDir());
  rep+=Constante::GetTableauDir();
  rep+='/';
  rep+=p_NomGroupe;
  rep+='/';
  
  dirent * mon_dirent;
  DIR * dir=opendir(rep.c_str());
  if (dir!=NULL)
  {
    mon_dirent=readdir(dir);
    while ( mon_dirent!=NULL )
    {
      string fichier=rep+mon_dirent->d_name;
      struct stat stat_fic;
      stat(fichier.c_str(), &stat_fic);
      if (!S_ISDIR(stat_fic.st_mode) && access(fichier.c_str(),R_OK)==0)
      {
        string le_fic(mon_dirent->d_name);
        int pos=le_fic.rfind(".tab");
        if (pos>0 && pos==static_cast<int>(le_fic.length()-4))
        {
          le_fic= le_fic.substr(0, le_fic.length()-4);
          liste.insert(le_fic);
        }
      }
      mon_dirent=readdir(dir);
    }
  }

  // Fichiers globals
  rep=Constante::GetGlobalDir();
  rep+=Constante::GetTableauDir();
  rep+='/';
  rep+=p_NomGroupe;
  rep+='/';

  dir=opendir(rep.c_str());
  if (dir!=NULL)
  {
    mon_dirent=readdir(dir);
    while (  mon_dirent!=NULL )
    {
      string fichier=rep+mon_dirent->d_name;
      struct stat stat_fic;
      stat(fichier.c_str(), &stat_fic);
      if (!S_ISDIR(stat_fic.st_mode) && access(fichier.c_str(),R_OK)==0)
      {
        string le_fic(mon_dirent->d_name);
        int pos=le_fic.rfind(".tab");
        if (pos>0 && pos==static_cast<int>(le_fic.length()-4))
        {
          le_fic= le_fic.substr(0, le_fic.length()-4);
          liste.insert(le_fic);
        }
        //liste.insert(mon_dirent->d_name);
      }
      mon_dirent=readdir(dir);
    }
  }
#endif

  return liste;
}

string TableauBase::GetRepGroupeFromId(unsigned int p_Id)
{
  if (p_Id < _VectNomGroupe.size())
  {
    return _VectNomGroupe[p_Id];
  }
  else
  {
    if (!_VectNomGroupe.empty())
    {
      return *_VectNomGroupe.rbegin();
    }
    else
    {
      return "";
    }
  }
}

string TableauBase::GetNom() const
{
  return _NomTableau;
}

void TableauBase::SetNom(const string & p_Nom)
{
  _NomTableau=p_Nom;
}

