/*****************************************************************************
 *
 *  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 "Balle.h"
#include "TraceBalle.h"
#include <MOGL_Temps.h>
#include <MOGL_GestionnaireObjet.h>
#include <MOGL_MatriceTransformation.h>
#include "BibliothequeSon.h"
#include "Constante.h"
#ifndef M_PI
#define M_PI 3.14159265359
#endif

#define VITESSE_DECELERATION  0.5
#define FACT_ACC_MAX          2

MOGL_Objet * Balle::_ObjetSource=NULL;

Balle::Balle(): ElementCollision(), MOGL_Action(),
                _Vitesse(0), _FacteurTaille(1), _RayonInit(0.5), _SuperPuissance(false),
                _TempoSuperPuissance(10, false, false), _CanalSonSuperPuissance(-1),
                _FacteurAcceleration(1)
{
  if (_ObjetSource==NULL)
  {
    PreCharger(Texture::GetGestionnaireTexture());
  }
  _ElementArbre=new MOGL_Objet(*_ObjetSource);
  _TraceBalle=new TraceBalle(this);
  ((MOGL_Objet *)_ElementArbre)->AjouterElement(_TraceBalle);
  _Rayon=_RayonInit;
  _TempoSuperPuissance.FinTemporisation.Connecter(this, &Balle::_OnFinSuperPuissance);
  ((MOGL_Objet *)_ElementArbre)->AjouterElement(&_TempoSuperPuissance);
}

Balle::Balle(const Balle & p_Balle): ElementCollision(p_Balle), _RayonInit(p_Balle._RayonInit), _CanalSonSuperPuissance(-1)
{
  _ElementArbre=new MOGL_Objet(*_ObjetSource);

  _TraceBalle=new TraceBalle(this);
  _SuperPuissance=p_Balle._SuperPuissance;
  _TraceBalle->SetSuperPuissance(_SuperPuissance);
  ((MOGL_Objet *)_ElementArbre)->AjouterElement(_TraceBalle);
  _Vitesse = p_Balle._Vitesse;
  _DirectionX = p_Balle._DirectionX;
  _DirectionY = p_Balle._DirectionY;
  _FacteurAcceleration = p_Balle._FacteurAcceleration;

  _Rayon=p_Balle._Rayon;
  _FacteurTaille=p_Balle._FacteurTaille;
  _TempoSuperPuissance=p_Balle._TempoSuperPuissance;
  _TempoSuperPuissance.FinTemporisation.Connecter(this, &Balle::_OnFinSuperPuissance);
  ((MOGL_Objet *)_ElementArbre)->AjouterElement(&_TempoSuperPuissance);
  _MatriceRotation=p_Balle._MatriceRotation;

  val=12;
}

Balle::~Balle()
{
  if (_CanalSonSuperPuissance!=-1)
  {
    Son::ArreterCanal(_CanalSonSuperPuissance);
  }
  delete _TraceBalle;
  delete _ElementArbre;
}

void Balle::PreCharger(MOGL_GestionnaireTexture * p_GestionnaireTexture)
{
  _ObjetSource=new MOGL_Objet;
  MOGL_GestionnaireObjet::ChargerObjetASCTriangle((Constante::GetGlobalDir()+Constante::GetDataDir()+"/balle.tri").c_str(), *p_GestionnaireTexture, *_ObjetSource);
}

void Balle::Deplacer(double p_Temps)
{
  SetPosition(_X + p_Temps*_Vitesse*_DirectionX*_FacteurAcceleration, _Y + p_Temps*_Vitesse*_DirectionY*_FacteurAcceleration);

  double ang = atan2(_DirectionY, _DirectionX);
  if (GetVitesseTotale() != 0 && (fabs(ang)<0.34))
  {
    _DirectionX = cos(ang*1.5);
    _DirectionY = sin(ang*1.5);
  }

  if (_SuperPuissance && _CanalSonSuperPuissance==-1)
  {
    _CanalSonSuperPuissance=BibliothequeSon::SonSuperPuissance->Jouer(true);
  }
}

double Balle::GetRayon() const
{
  return _Rayon;
}

void Balle::SetPosition(double p_X, double p_Y)
{
  _X=p_X;
  _Y=p_Y;
  if (_ElementArbre!=NULL)
  {
    if (_Vitesse!=0)
    {
      double distance=MOGL_Temps::GetVariationTemps()*_Vitesse;
      double angleRot=distance/_Rayon;
    
      MOGL_Struct_Vecteur vec;
      vec.x=-_DirectionY;
      vec.y=_DirectionX;
      vec.z=0;

      MOGL_MatriceTransformation matRot=MOGL_MatriceTransformation::FabriqueRotation(vec, angleRot*180.0/M_PI);
      _MatriceRotation.Multiplier(matRot);
    }

    MOGL_MatriceTransformation mat=MOGL_MatriceTransformation::FabriqueEchelle(_FacteurTaille, _FacteurTaille, _FacteurTaille);
    mat.Multiplier(_MatriceRotation);
    

    _ElementArbre->ReinitialiserPosition();
    _ElementArbre->AjouteTransformation(mat);

    _ElementArbre->AjouterTranslation(_X,_Y,0);
  }
}

void Balle::SetTaille(double p_Facteur)
{
  _Rayon*=p_Facteur;
  _FacteurTaille*=p_Facteur;
  
  MOGL_MatriceTransformation mat=MOGL_MatriceTransformation::FabriqueEchelle(_FacteurTaille, _FacteurTaille, _FacteurTaille);
  mat.Multiplier(_MatriceRotation);

  _ElementArbre->ReinitialiserPosition();
  _ElementArbre->AjouteTransformation(mat);

  _ElementArbre->AjouterTranslation(_X,_Y,0);
}

bool Balle::GetSuperPuissance() const
{
  return _SuperPuissance;
}

void Balle::SetSuperPuissance(bool p_Actif)
{
  if (!_SuperPuissance && p_Actif && _CanalSonSuperPuissance==-1)
  {
    _CanalSonSuperPuissance=BibliothequeSon::SonSuperPuissance->Jouer(true);
  }

  if (_SuperPuissance && !p_Actif && _CanalSonSuperPuissance!=-1)
  {
    Son::ArreterCanal(_CanalSonSuperPuissance);
    _CanalSonSuperPuissance=-1;
  }

  _SuperPuissance=p_Actif;
  _TraceBalle->SetSuperPuissance(p_Actif);
  if (p_Actif)
  {
    _TempoSuperPuissance.Arreter();
    _TempoSuperPuissance.Demarrer();
  }
  else
  {
    _TempoSuperPuissance.Arreter();
  }
}

void Balle::_OnFinSuperPuissance()
{
  SetSuperPuissance(false);
}

double Balle::GetTempsMax() const
{
  return _TempsMax;
}

void Balle::SetTempsMax(double p_TempsMax)
{
  _TempsMax = p_TempsMax;
}

Struct_Collision Balle::TesterCollision(Balle * p_Balle)
{
  Struct_Collision collision;
  collision.TempsCollision = p_Balle->GetTempsMax();
  return collision;
}

void Balle::SetFacteurAcceleration(double p_Facteur)
{
  _FacteurAcceleration = p_Facteur;
  if (_FacteurAcceleration > FACT_ACC_MAX)
  {
    _FacteurAcceleration = FACT_ACC_MAX;
  }
}

double Balle::GetFacteurAcceleration() const
{
  return _FacteurAcceleration;
}

void Balle::SetDirection(double p_DirectionX, double p_DirectionY)
{
  _DirectionX = p_DirectionX;
  _DirectionY = p_DirectionY;
}

double Balle::GetDirectionX() const
{
  return _DirectionX;
}

double Balle::GetDirectionY() const
{
  return _DirectionY;
}

void Balle::SetVitesseTotale(double p_Vitesse)
{
  _Vitesse = p_Vitesse / _FacteurAcceleration;
}

double Balle::GetVitesseTotale() const
{
  return _Vitesse * _FacteurAcceleration;
}


void Balle::SetVitesseBase(double p_Vitesse)
{
  _Vitesse = p_Vitesse;
}

double Balle::GetVitesseBase() const
{
  return _Vitesse;
}

double Balle::GetVitesseTotaleX() const
{
  return (_Vitesse * _FacteurAcceleration) * _DirectionX;
}

double Balle::GetVitesseTotaleY() const
{
  return (_Vitesse * _FacteurAcceleration) * _DirectionY;
}

void Balle::SetVitesseTotale(double p_VitesseX, double p_VitesseY)
{
  double vit = sqrt(p_VitesseX * p_VitesseX + p_VitesseY * p_VitesseY);
  _DirectionX = p_VitesseX / vit;
  _DirectionY = p_VitesseY / vit;
  
  _Vitesse = vit / _FacteurAcceleration;
}

void Balle::MajVitesse()
{
  double val = VITESSE_DECELERATION * MOGL_Temps::GetVariationTemps();

  if (_FacteurAcceleration > 1)
  {
    _FacteurAcceleration -= val;
    if (_FacteurAcceleration < 1)
    {
      _FacteurAcceleration = 1;
    }
  }
  else if (_FacteurAcceleration < 1)
  {
    _FacteurAcceleration += val;
    if (_FacteurAcceleration > 1)
    {
      _FacteurAcceleration = 1;
    }
  }
}

void Balle::AddAcceleration(double p_Facteur)
{
  _FacteurAcceleration *= p_Facteur;

  if (_FacteurAcceleration > FACT_ACC_MAX)
  {
    _FacteurAcceleration = FACT_ACC_MAX;
  }
}
