/*****************************************************************************
 *
 *  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 <sstream>

#include "BriquePolygone.h"
#include "ExplosionBrique.h"

#include <MOGL_GestionnaireObjet.h>
#include <MOGL_Temps.h>
#include <iostream>
#include "BibliothequeSon.h"

#ifndef M_PI
#define M_PI 3.14159265359
#endif

#define SIGN(a) (((a)<0)?-1:1)

BriquePolygone::BriquePolygone(TableauBase * p_TableauBase): ElementTableau(p_TableauBase), _Z(0), 
                                                     _VitesseZ(9), _Rotation(0), _Rayon(0), _VitesseRotation(0)
{
  _Z=2*M_PI*(rand()/(RAND_MAX+0.0))-1;
}

BriquePolygone::BriquePolygone(const BriquePolygone & p_BriquePolygone): ElementTableau(p_BriquePolygone),
                                                                         _ListPoint(p_BriquePolygone._ListPoint), _VitesseZ(9)
{
  _Z=2*M_PI*(rand()/(RAND_MAX+0.0))-1;
}

BriquePolygone::~BriquePolygone()
{
}


void BriquePolygone::Maj()
{
  _Z+=MOGL_Temps::GetVariationDistance(_VitesseZ);
  if (_Z>=2*M_PI)
  {
    _Z-=static_cast<float>(2*M_PI);
  }

  _ElementArbre->ReinitialiserPosition();
  _ElementArbre->AjouterTranslation(_Rayon, 0,0);

  MOGL_Struct_Vecteur vect;
  vect.x=0;
  vect.y=0;
  vect.z=-_VitesseRotation;

  vect = MOGL_Temps::GetVariationVecteurAngle(vect);
  vect.z += _Rotation;
  _Rotation = vect.z;
  MOGL_MatriceTransformation mat = MOGL_MatriceTransformation::FabriqueRotation(0,0,_Rotation);
  _ElementArbre->AjouteTransformation(mat);
  _ElementArbre->AjouterTranslation(_X,_Y,sin(_Z)/4);
}

void BriquePolygone::InitialiserPosition()
{
  _ElementArbre->ReinitialiserPosition();
  _ElementArbre->AjouterTranslation(_Rayon, 0,0);

  MOGL_MatriceTransformation mat = MOGL_MatriceTransformation::FabriqueRotation(0,0,_Rotation);
  _ElementArbre->AjouteTransformation(mat);
  _ElementArbre->AjouterTranslation(_X,_Y,0);
}


void BriquePolygone::SetPosition(double p_X, double p_Y)
{
  _X=p_X;
  _Y=p_Y;
  if (_ElementArbre!=NULL)
  {
    _ElementArbre->ReinitialiserPosition();
    _ElementArbre->AjouterTranslation(_X,_Y,sin(_Z)/4);
  }
}

void BriquePolygone::_AnalyserLigne()
{
  ElementCollision::_AnalyserLigne();
  It_Map_Params it;
  it = _Params.find("rspeed");
  if (it != _Params.end())
  {
    stringstream st(it->second);
    st>>_VitesseRotation;
  }
  else
  {
    _VitesseRotation = 0;
  }

  it = _Params.find("r");
  if (it != _Params.end())
  {
    stringstream st(it->second);
    st>>_Rayon;
  }
  else
  {
    _Rayon = 0;
  }

  it = _Params.find("ri");
  if (it != _Params.end())
  {
    stringstream st(it->second);
    st>>_Rotation;
  }
  else
  {
    _Rotation = 0;
  }
}

Struct_Collision BriquePolygone::TesterCollision(Balle * p_Balle)
{
  Struct_Collision collision;
  collision.TempsCollision = p_Balle->GetTempsMax();
  collision.VitesseX=p_Balle->GetVitesseTotaleX();
  collision.VitesseY=p_Balle->GetVitesseTotaleY();

  Struct_Collision col, colCircle, colSegment;

  float rot = _VitesseRotation*3.14159/180;
  float roti = -_Rotation*3.14159/180;


  ListIt_Point it = _ListPoint.begin();
  float xPrev = it->x;
  float yPrev = it->y;

  col = _CircleCollision(p_Balle->GetPositionX(), p_Balle->GetPositionY(),p_Balle->GetRayon(),
                         p_Balle->GetVitesseTotaleX(), p_Balle->GetVitesseTotaleY(),
                         _X, _Y, roti,
                         xPrev + _Rayon, yPrev, 0, 0, 0, rot, p_Balle->GetTempsMax());

  for(it++; it != _ListPoint.end(); it++)
  { 
    float x = it->x;
    float y = it->y;
    colSegment = _SegmentCollision(p_Balle->GetPositionX(), p_Balle->GetPositionY(),p_Balle->GetRayon(),
                                   p_Balle->GetVitesseTotaleX(), p_Balle->GetVitesseTotaleY(),
                                   _X, _Y, roti,
                                   xPrev + _Rayon, yPrev, x + _Rayon, y,
                                   0, 0, rot, 0, p_Balle->GetTempsMax());

    colCircle = _CircleCollision(p_Balle->GetPositionX(), p_Balle->GetPositionY(),p_Balle->GetRayon(),
                                 p_Balle->GetVitesseTotaleX(), p_Balle->GetVitesseTotaleY(),
                                 _X, _Y, roti,
                                 x + _Rayon, y, 0, 0, 0, rot, p_Balle->GetTempsMax());

    if (colSegment.TempsCollision < col.TempsCollision)
    {
      col = colSegment;
    }
    if (colCircle.TempsCollision < col.TempsCollision)
    {
      col = colCircle;
    }

    xPrev = x;
    yPrev = y;
  }

  // Pour finir on teste le segment entre le premier et le dernier point :
  // on ferme le polygone
  it = _ListPoint.begin();
  float x = it->x;
  float y = it->y;
  colSegment = _SegmentCollision(p_Balle->GetPositionX(), p_Balle->GetPositionY(),p_Balle->GetRayon(),
                                 p_Balle->GetVitesseTotaleX(), p_Balle->GetVitesseTotaleY(),
                                 _X, _Y, roti,
                                 xPrev + _Rayon, yPrev, x + _Rayon, y,
                                 0, 0, rot, 0, p_Balle->GetTempsMax());
  if (colSegment.TempsCollision < col.TempsCollision)
  {
    col = colSegment;
  }

  if (col.TempsCollision < p_Balle->GetTempsMax())
  {
    float angle = (360 - (_Modulo(_Rotation, 360)) + _Modulo(90 * SIGN(_VitesseRotation), 360)) * 3.14159/180;
    float vit = _VitesseRotation  * 3.14159/180 * _Rayon;
    float vit_x = vit * cosf(angle);
    float vit_y = vit * sinf(angle);
    
    if (fabs(col.VitesseX) < fabs(vit_x))
    {
      col.VitesseX = vit_x;
    }
    if (fabs(col.VitesseY) < fabs(vit_y))
    {
      col.VitesseY = vit_y;
    }

    float fact = sqrt(col.VitesseX*col.VitesseX + col.VitesseY*col.VitesseY) / p_Balle->GetVitesseTotale();

    col.AddFacteurCollision = fact;
    col.VitesseX /= fact;
    col.VitesseY /= fact;
  }
  return col;
}


bool BriquePolygone::Toucher(Balle * p_Balle, double p_Temps)
{
  BibliothequeSon::SonExplosion->Jouer(false);
  return true;
}

Point BriquePolygone::GetVisualCenter()
{
  MOGL_Struct_Vecteur vect={_Rayon, 0, 0};

  MOGL_MatriceTransformation mat = MOGL_MatriceTransformation::FabriqueRotation(0,0,_Rotation);
  MOGL_Struct_Vecteur vect2 = mat.MultiplierVecteur(vect);

  return Point(vect2.x + _X, vect2.y + _Y);
}

void BriquePolygone::_AjouterPoint(float p_X, float p_Y)
{
  _ListPoint.push_back(Point(p_X, p_Y));
}
