/*****************************************************************************
 *
 *  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 "I18n.h"
#include "CasseBrique.h"
#include "MOGL_GestionnaireObjet.h"
#include "MOGL_Temps.h"
#include "MenuEditeur.h"
#include "MenuJeu.h"
#include "TableauJeu.h"
#include "Constante.h"
#include "Son.h"
#include "BibliothequeSon.h"
#include <MOGL_Bibliotheque.h>
#include <iostream>
#include "Option.h"
#include "MOGL_PoliceBitmap.h"

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

#ifndef M_PI
#define M_PI 3.14159265359
#endif


void CasseBrique::main()
{
    if (_CreateOk)
    {
        _Fenetre.LancerBoucle();
    }
}


CasseBrique::CasseBrique(): MOGL_Action(), _Fenetre(("BRIQUOLO v"+Constante::GetVersion()).c_str()), _Tableau(NULL),
                            _Pause(false), _MenuBase(NULL), _EnumAction(MENU), _CreateOk(false)
{
    string fichier(Constante::GetLocalDir());
#ifdef WIN32
    _mkdir(fichier.c_str());
#else
    mkdir(fichier.c_str(), 0775);
#endif

    fichier+=Constante::GetTableauDir();
#ifdef WIN32
    _mkdir(fichier.c_str());
#else
    mkdir(fichier.c_str(), 0775);
#endif
    Option::Charger();
    _Fenetre.SetFullscreen(Option::Fullscreen.GetValeur());
    _Fenetre.SetMode(Option::ResolutionX.GetValeur(), Option::ResolutionY.GetValeur());
    if (_Fenetre.Initialiser())
    {
        Option::ResolutionX.SetValeur(_Fenetre.GetResolutionX());
        Option::ResolutionY.SetValeur(_Fenetre.GetResolutionY());

        _Fenetre.DefinirRepetitionTouche(1,1);
        MOGL_Temps::SetMaxFPS(Option::MaxFPS.GetValeur());
        _Fenetre.SetGrabCurseur(false);
        _Fenetre.SetCacherCurseur(false);
        if (Son::Initialiser())
        {
            BibliothequeSon::Initialiser();
            Texture::ChargerTextures();
            MOGL_Bibliotheque::GetSingleton()->ReinitialiserSurChangementModeFenetre(&_Fenetre);
            _MenuPrincipal=new MenuPrincipal(&_Fenetre);
            _MenuPrincipal->SetActivation(true);
            _Fenetre.AjouterInterface(_MenuPrincipal);
            _MenuPrincipal->BoutonEditeur->Activation.Connecter(this, &CasseBrique::_OnEditer);
            _MenuPrincipal->BoutonQuitter->Activation.Connecter(this, &CasseBrique::_OnQuitter);
            _MenuPrincipal->Ok->Activation.Connecter(this, &CasseBrique::_OnCommencerJeu);

            _RectangleFond=new MOGL_Polygone();
            srand(SDL_GetTicks());
            for(int i=0; i<4; i++)
            {
                r[i]=2*M_PI*(rand()/static_cast<float>(RAND_MAX));
                g[i]=2*M_PI*(rand()/static_cast<float>(RAND_MAX));
                b[i]=2*M_PI*(rand()/static_cast<float>(RAND_MAX));
            }
            MOGL_Struct_Couleur coul;
            coul.r=0;
            coul.g=0;
            coul.b=0;
            coul.a=1;
            _RectangleFond->AjouterPoint(0,0,coul);
            _RectangleFond->AjouterPoint(0,_Fenetre.GetResolutionY(),coul);
            _RectangleFond->AjouterPoint(_Fenetre.GetResolutionX(), _Fenetre.GetResolutionY(),coul);
            _RectangleFond->AjouterPoint(_Fenetre.GetResolutionX(),0,coul);
            _Facade.AjouterElement(_RectangleFond);
            MOGL_Struct_Couleur coulTexte;
            coulTexte.r=0;
            coulTexte.g=0;
            coulTexte.b=1;
            coulTexte.a=0.5;

            MOGL_Struct_Couleur coulFond;
            coulFond.r=1;
            coulFond.g=1;
            coulFond.b=1;
            coulFond.a=0.7f;

            _TexteFPS.SetCouleurTexte(coulTexte);
            _TexteFPS.SetCouleurFond(coulFond);

            _TexteFPS.SetCacher(!Option::AfficherFPS.GetValeur());
            _Facade.AjouterElement(&_TexteFPS);

            _ImagePlateau=new MOGL_ImageFacade;
            _ImagePlateau->ChargerPNG((Constante::GetGlobalDir()+Constante::GetDataDir()+"/imageplateau.png").c_str());
            _ImagePlateau->SetPosition(0,0);
            _Facade.AjouterElement(_ImagePlateau);

            MOGL_Struct_Couleur coulTexteNombreVie;
            coulTexteNombreVie.r=0;
            coulTexteNombreVie.g=0;
            coulTexteNombreVie.b=0;
            coulTexteNombreVie.a=1;
            _TexteNombreVie.SetCouleurTexte(coulTexteNombreVie);
            _PoliceVie=new MOGL_PoliceBitmap();
            _PoliceVie->Charger((Constante::GetGlobalDir()+Constante::GetDataDir()+"/vie.ftx").c_str());
            _TexteNombreVie.SetPolice(_PoliceVie);
            _TexteNombreVie.SetPosition(100,0);
            _Facade.AjouterElement(&_TexteNombreVie);

            _ImagePlateau->SetCacher(true);
            _TexteNombreVie.SetCacher(true);

            _Fenetre.AjouterInterface(&_Facade);

            _Fenetre.Idle.Connecter(this,&CasseBrique::_Idle);
            _Fenetre.KeyDown.Connecter(this,&CasseBrique::_ClavierDown);
            _Fenetre.KeyUp.Connecter(this,&CasseBrique::_ClavierUp);
            _Fenetre.MouseMove.Connecter(this,&CasseBrique::_DeplacementSouris);
            _Fenetre.MouseButtonUp.Connecter(this,&CasseBrique::_BoutonSourisUp);
            _Fenetre.MouseButtonDown.Connecter(this,&CasseBrique::_BoutonSourisDown);
            _Fenetre.Destruction.Connecter(this,&CasseBrique::_OnDestruction);
            _Fenetre.ChangementMode.Connecter(this, &CasseBrique::_OnChangementResolution);

            _CreateOk = true;
        }
    }
}

CasseBrique::~CasseBrique()
{
  if (_Tableau!=NULL)
  {
    _Tableau->EffacerTousElementTableau();
    delete _Tableau;
  }

  if (_MenuBase!=NULL)
  {
    delete _MenuBase;
  }
  Texture::DetruireTextures();

  delete _MenuPrincipal;
  BibliothequeSon::Terminer();
}

void CasseBrique::_Idle()
{
  char ch[100];

  if (Option::AfficherFPS.GetValeur())
  {
    sprintf(ch,_("FPS : %.2f (Average : %.2f)"),MOGL_Temps::GetFPS(), MOGL_Temps::GetMoyenneFPS());
    _TexteFPS.SetTexte(ch);
    _TexteFPS.SetPosition(_Fenetre.GetResolutionX()-_TexteFPS.GetTailleX(),0);
    _TexteFPS.SetCacher(false);
  }
  else
  {
    _TexteFPS.SetCacher(true);
  }

  if (_EnumAction==JEU)
  {
    sprintf(ch,"x%i", ((TableauJeu *)_Tableau)->GetNombreVie());
    _TexteNombreVie.SetTexte(ch);
  }


  switch(_EnumAction)
  {
    case MENU:
    {
      _RectangleFond->SetPosition(0,0,0);
      _RectangleFond->SetPosition(1,0,_Fenetre.GetResolutionY());
      _RectangleFond->SetPosition(2,_Fenetre.GetResolutionX(), _Fenetre.GetResolutionY());
      _RectangleFond->SetPosition(3,_Fenetre.GetResolutionX(),0);

      float variation=0.5;
      for(int i=0; i<4; i++)
      {
        r[i]+=MOGL_Temps::GetVariationDistance(variation);
        if (r[i]>=2*M_PI)
        {
          r[i]-=static_cast<float>(2*M_PI);
        }
        g[i]+=MOGL_Temps::GetVariationDistance(variation);
        if (g[i]>=2*M_PI)
        {
          g[i]-=static_cast<float>(2*M_PI);
        }
        b[i]+=MOGL_Temps::GetVariationDistance(variation);
        if (b[i]>=2*M_PI)
        {
          b[i]-=static_cast<float>(2*M_PI);
        }
        MOGL_Struct_Couleur coul;
        coul.r=(sin(r[i])+1)/2;
        coul.g=(sin(g[i])+1)/2;
        coul.b=(sin(b[i])+1)/2;
        coul.a=1;
        _RectangleFond->SetCouleur(i, coul);
      }
      break;
    }
    case JEU:
    case EDITEUR:
    {
      if (!_Pause)
      {
        _Tableau->Maj();
      }

      if (_MenuBase->GetQuitter() || _FinJeu==true)
      {
        _EnumAction=MENU;
        _Tableau->EffacerTousElementTableau();
        _Tableau->Activer(false);
        delete _Tableau;
        _Fenetre.RetirerInterface(_MenuBase);
        delete _MenuBase;
        _Tableau=NULL;
        _MenuBase=NULL;
        _MenuPrincipal->SetActivation(true);
        _RectangleFond->SetCacher(false);
        _ImagePlateau->SetCacher(true);
        _TexteNombreVie.SetCacher(true);
        _Pause=false;
        _Fenetre.SetGrabCurseur(false);
        _Fenetre.SetCacherCurseur(false);

        MOGL_Temps::SetPause(false);
      }

      break;
    }
  }
}

void CasseBrique::_ClavierDown(SDL_keysym * key)
{
  switch (key->sym)
  {
    case SDLK_F12 :
    {
      if (MOGL_Temps::GetPause())
      {
        _Fenetre.ScreenshotPrefixBMP("briquolo");
      }
      else
      {
        MOGL_Temps::SetPause(true);
        _Fenetre.ScreenshotPrefixBMP("briquolo");
        MOGL_Temps::SetPause(false);
      }
      break;
    }
    default:
      break;
  }
  switch(_EnumAction)
  {
    case MENU:
    {
      break;
    }
    case JEU:
    {
      _Tableau->ClavierDown(key);
      break;
    }
    default:
      break;
  }
}

void CasseBrique::_ClavierUp(SDL_keysym * key)
{
  switch(_EnumAction)
  {
    case MENU:
    {
      break;
    }
    case JEU:
    {
      switch (key->sym)
      {
        case SDLK_ESCAPE :
        {
          if (!_MenuBase->GetActivation())
          {
            _Tableau->SetPause(true);
            _MenuBase->SetActivation(true);
            _Fenetre.SetGrabCurseur(false);
            _Fenetre.SetCacherCurseur(false);
            _Pause=true;
          }
          break;
        }
        default:
          break;
      }
      _Tableau->ClavierUp(key);
      break;
    }
    case EDITEUR:
    {
      switch (key->sym)
      {
        case SDLK_ESCAPE :
        {
          if (!_MenuBase->GetActivation())
          {
            _Tableau->SetPause(true);
            _MenuBase->SetActivation(true);
            _Pause=true;
          }
          break;
        }
        default:
          break;
      }
      _Tableau->ClavierUp(key);
      break;
    }
  }
}

void CasseBrique::_BoutonSourisUp(SDL_MouseButtonEvent * p_Event)
{
  switch(_EnumAction)
  {
    case MENU:
    {
      break;
    }
    case JEU:
    {
      if (!_Pause)
      {
        _Tableau->BoutonSourisUp(p_Event);
      }
      break;
    }
    case EDITEUR:
    {
      break;
    }
  }
}

void CasseBrique::_BoutonSourisDown(SDL_MouseButtonEvent * p_Event)
{
  switch(_EnumAction)
  {
    case MENU:
    {
      break;
    }
    case JEU:
    {
      if (!_Pause)
      {
        _Tableau->BoutonSourisDown(p_Event);
      }
      break;
    }
    case EDITEUR:
    {
      break;
    }
  }

}


void CasseBrique::_DeplacementSouris(SDL_MouseMotionEvent * p_Event)
{
  switch(_EnumAction)
  {
    case MENU:
    {
      break;
    }
    case JEU:
    {
      if (!_Pause)
      {
        _Tableau->DeplacementSouris(p_Event);
      }
      break;
    }
    case EDITEUR:
    {
      break;
    }
  }
}

void CasseBrique::_OnFinPause()
{
  _Pause=false;
  _Tableau->SetPause(false);
  if (_EnumAction==JEU)
  {
    _Fenetre.SetGrabCurseur(true);
    _Fenetre.SetCacherCurseur(true);
  }
}

void CasseBrique::_OnCommencerJeu()
{
  _RectangleFond->SetCacher(true);
  _Tableau=new TableauJeu(&_Fenetre);

  _ImagePlateau->SetCacher(false);
  _TexteNombreVie.SetCacher(false);

  _Fenetre.SetGrabCurseur(true);
  _Fenetre.SetCacherCurseur(true);

  _FinJeu=false;
  if (_ChargerTableau(TableauBase::GetRepGroupeFromId(_MenuPrincipal->ChoixGroupe->GetIndiceCourant()), _MenuPrincipal->ChoixTableau->GetElementChoixCourant()))
  {
    ((TableauJeu*)_Tableau)->FinTableau.Connecter(this, &CasseBrique::_OnFinTableau);
    ((TableauJeu*)_Tableau)->FinBalle.Connecter(this, &CasseBrique::_OnFinBalle);
    _Tableau->Activer(true);
    _MenuBase=new MenuJeu(&_Fenetre);
    _Fenetre.AjouterInterface(_MenuBase);
    _MenuBase->FinMenuBase.Connecter(this, & CasseBrique::_OnFinPause);
    _EnumAction=JEU;

    _MenuPrincipal->PanneauOption->SetActivation(false);
    _MenuPrincipal->SetActivation(false);
  }
  else
  {
    _MenuPrincipal->PanneauOption->SetActivation(false);
    _MenuPrincipal->SetActivation(true);
  }
}

void CasseBrique::_OnEditer()
{
  _RectangleFond->SetCacher(true);
  _Tableau = new TableauEditeur(&_Fenetre);
  _FinJeu=false;
  _Tableau->Activer(true);

  _MenuBase=new MenuEditeur(&_Fenetre);

  ((MenuEditeur*)_MenuBase)->_PanneauSauvegarder->DemanderEnregistrement.Connecter(this, &CasseBrique::_OnSauvegarder);
  ((MenuEditeur*)_MenuBase)->_PanneauCharger->DemanderChargement.Connecter(this, &CasseBrique::_OnCharger);

  _Fenetre.AjouterInterface(_MenuBase);
  _MenuBase->FinMenuBase.Connecter(this, & CasseBrique::_OnFinPause);
  _EnumAction=EDITEUR;
  _MenuPrincipal->SetActivation(false);
}

void CasseBrique::_OnQuitter()
{
  _Fenetre.Arreter();
}

void CasseBrique::_OnDestruction()
{
  Option::Sauvegarder();
}

void CasseBrique::_OnSauvegarder(const string & p_NomGroupe, const string & p_NomFichier)
{
  cout<<_("Save level -> Name : ")<<p_NomGroupe<<'/'<<p_NomFichier<<endl;
  if (!_SauverTableau(p_NomGroupe, p_NomFichier))
  {
    cerr<<_("Error while saving")<<endl;
  }
}

void CasseBrique::_OnCharger(const string & p_Groupe, const string & p_NomFichier)
{
  cout<<_("Load level -> Name : ")<<p_NomFichier<<endl;
  if (!_ChargerTableau(p_Groupe, p_NomFichier))
  {
    cerr<<_("Error while loading")<<endl;
  }
  else
  {
    ((MenuEditeur*)_MenuBase)->_PanneauSauvegarder->_NomGroupe->SetChaine(p_Groupe);
    ((MenuEditeur*)_MenuBase)->_PanneauSauvegarder->_NomTableau->SetChaine(p_NomFichier);
  }
}

bool CasseBrique::_ChargerTableau(const string & p_Groupe, const string & p_Nom)
{
  string fichier(Constante::GetLocalDir());
  fichier+=Constante::GetTableauDir();
  fichier+='/'+p_Groupe;
  fichier+='/'+p_Nom+".tab";
#ifdef WIN32
  if (_access(fichier.c_str(),04)==0)
#else
  if (access(fichier.c_str(),R_OK)==0)
#endif
  {
    _Tableau->EffacerTousElementTableau();
    if (!_Tableau->Charger(fichier.c_str()))
    {
      return false;
    }
  }
  else
  {
    fichier=Constante::GetGlobalDir();
    fichier+=Constante::GetTableauDir();
    fichier+='/'+p_Groupe;
    fichier+='/'+p_Nom+".tab";
#ifdef WIN32
    if (_access(fichier.c_str(),04)==0)
#else
    if (access(fichier.c_str(),R_OK)==0)
#endif
    {
      _Tableau->EffacerTousElementTableau();
      if (!_Tableau->Charger(fichier.c_str()))
      {
        return false;
      }
    }
    else
    {
      return false;
    }
  }
  _Tableau->SetNom(p_Nom);
  return true;
}

bool CasseBrique::_SauverTableau(const string & p_Groupe, const string & p_Nom)
{
  string fichier = Constante::GetLocalDir();
  fichier+=Constante::GetTableauDir();
  fichier+='/'+p_Groupe;
#ifdef WIN32
  _mkdir(fichier.c_str());
#else
  mkdir(fichier.c_str(), 0775);
#endif

  fichier = Constante::GetLocalDir();
  fichier+=Constante::GetTableauDir();
  fichier+='/'+p_Groupe;
  fichier+='/';
  fichier+=p_Nom+".tab";
  if (!_Tableau->Sauvegarder(fichier.c_str()))
  {
    return false;
  }
  return true;
}

void CasseBrique::_OnFinTableau()
{
  TableauJeu * tab=(TableauJeu*)_Tableau;
  tab->DepartTableau();
  set<string> liste=TableauBase::GetListeTableau(TableauBase::GetRepGroupeFromId(_MenuPrincipal->ChoixGroupe->GetIndiceCourant()));
  set<string>::iterator it=liste.find(tab->GetNom());
  if (it!=liste.end())
  {
    it++;
    if (it!=liste.end())
    {
      _ChargerTableau(TableauBase::GetRepGroupeFromId(_MenuPrincipal->ChoixGroupe->GetIndiceCourant()), *it);
    }
    else
    {
      _FinJeu=true;
    }
  }
}

void CasseBrique::_OnFinBalle()
{
  _FinJeu=true;
}

void CasseBrique::_OnChangementResolution(int p_ResolutionX, int p_ResolutionY, int p_BitParPixel)
{
  _PoliceVie->Recharger();
  _ImagePlateau->Recharger();
  Texture::RechargerTextures();
}
