#ifndef __GRAPHICAL_OBJECT_H
#define __GRAPHICAL_OBJECT_H

#include "Vector3.h"
#include "Structures.h"

class GraphicalObject
{
protected:
  unsigned type;
  Vector3  pt;
  unsigned idMat;
  Vector3  normal;

public:
  GraphicalObject(const unsigned _t,const Vector3& _pt, const unsigned& _mat, const Vector3& _n)
   : type(_t), pt(_pt), normal(_n)
  {
    idMat = _mat;
  }

  GraphicalObject(const GraphicalObject& _obj)
  {
    type   = _obj.GetType();
    pt     = _obj.GetPoint();
    idMat  = _obj.GetMaterial();
    normal = _obj.GetNormal();
  }

  GraphicalObject()
  {
    type = 0;
    pt   = Vector3(0,0,0);
    idMat  = 0;
    normal=Vector3(0,0,0);
  }

  virtual GraphicalObject& operator=(const GraphicalObject& _obj)
  {
    type = _obj.GetType();
    pt   = _obj.GetPoint();
    idMat  = _obj.GetMaterial();
    normal=_obj.GetNormal();
  }


  inline
  Vector3 GetNormal() const
  {
    return normal;
  }

  inline
  Vector3 GetPoint() const
  {
    return pt;
  }

  inline
  unsigned GetMaterial() const
  {
    return idMat;
  }

  inline
  unsigned GetType() const
  {
    return type;
  }

  virtual int Intersect(const Ray& _ray, real& dist)
  {
    return 0;
  }
  
  virtual void affiche()
  {
    std::cout << type << " | ";
  }

  virtual ~GraphicalObject()
  {
  }

};


class GraphicalSphere : public GraphicalObject
{
public:
  real r;
public:
  GraphicalSphere(const Vector3& _centre, const unsigned _mat, const real _r)
   : GraphicalObject(SPHERE,_centre,_mat, Vector3(0,0,_r)), r(_r)
  {}
  GraphicalSphere(const Vector3& _centre, const real _r)
   : GraphicalObject(SPHERE,_centre,0, Vector3(0.0,0.0,_r)), r(_r)
  {}
  GraphicalSphere(const GraphicalSphere& _obj)
  {
    r    = _obj.r;
    type = SPHERE;
    pt   = _obj.GetPoint();
    idMat  = (_obj.GetMaterial());
    normal=_obj.GetNormal();
  }

  GraphicalSphere()
  {
    type = 0;
    pt   = Vector3(0.0,0.0,0.0);
    idMat  = 0;
    normal=Vector3(0.0,0.0,0.0);
    r     = 0.0;
  }

  GraphicalSphere& operator=(const GraphicalSphere& _obj)
  {
    r      = _obj.r;
    type   = SPHERE;
    pt     = _obj.GetPoint();
    idMat  = (_obj.GetMaterial());
    normal =_obj.GetNormal();
  }

  int Intersect(const Ray &ray, real& dist);
  
  void affiche()
  {
    std::cout<<"Sphere: pos("<<pt.x<<","<<pt.y<<","<<pt.z<<"),rayon="<<r<<",idMat="<<idMat<<std::endl;
  }

};


class GraphicalPlane : public GraphicalObject
{
public:
  GraphicalPlane(const Vector3& _normal, const Vector3& _pt, const unsigned _mat)
   : GraphicalObject(PLANE,_pt,_mat,_normal)
  {}

  GraphicalPlane()
  {
    type   = 0;
    pt     = Vector3(0.0,0.0,0.0);
    idMat  = 0;
    normal = Vector3(0.0,0.0,0.0);
  }
  
  GraphicalPlane(const GraphicalPlane& _p)
   : GraphicalObject(PLANE,_p.pt,_p.idMat,_p.normal)
  {}

  int Intersect(const Ray &ray, real& dist);
  
  void affiche()
  {
    std::cout<<"Plane: pos("<<pt.x<<","<<pt.y<<","<<pt.z<<"), n("<<normal.x<<","<<normal.y<<","<<normal.z<<") et idMat="<<idMat<<std::endl;
  }
};


class GraphicalTriangle : public GraphicalObject
{
public:
  Point py,pu;

  GraphicalTriangle(const Point& _pt, const Point& _py, const Point& _pu, const unsigned _mat)
   : GraphicalObject(TRIANGLE,_pt,_mat,Vector3(0,0,0))
  {
    py = _py;
    pu = _pu;
    normal = _pt ^ _py;
    normal.Normalize();
    normal = -normal;
  }

  GraphicalTriangle()
  {
    type   = 0;
    pt     = Vector3(0.0,0.0,0.0);
    idMat  = 0;
    normal = Vector3(0.0,0.0,0.0);
    pu     = Vector3(0.0,0.0,0.0);
    py     = Vector3(0.0,0.0,0.0);
  }
  
  GraphicalTriangle(const GraphicalTriangle& _t)
   : GraphicalObject(TRIANGLE,_t.pt,_t.idMat,_t.normal)
  {
    py = _t.py;
    pu = _t.pu;
  }

  int Intersect(const Ray &ray, real& dist);
  
  void affiche()
  {
    std::cout<<"Triangle: P1("<<pt.x<<","<<pt.y<<","<<pt.z<<"), P2("<<py.x<<","<<py.y<<","<<py.z<<"),P3("<<pu.x<<","<<pu.y<<","<<pu.z<<"), et idMat="<<idMat<<std::endl;
  }
};



/*
class GraphicalQuadric : public GraphicalObject
{
  // on représente par l'équation
  //   F(x, y, z) = Ax^2 + By^2 + Cz^2 + Dxy+ Exz + Fyz + Gx + Hy + Iz + J = 0
public:
  real a,b,c,d,e,f,g,h,i,j;
public:

  GraphicalQuadric(const real[]& _data, const Vector3& _pt, const unsigned _mat)
   : GraphicalObject(PLANE,_pt,_mat,Vector3(0,0,0))
  {
    for (unsigned iter=0;iter<9;iter++)
        *((&a)+iter) = _data[iter];
  }

  GraphicalQuadric()
  {
    type   = QUAD;
    pt     = Vector3(0.0,0.0,0.0);
    idMat  = 0;
    normal = Vector3(0.0,0.0,0.0);
  }
  
  GraphicalQuadric(const GraphicalPlane& _p)
   : GraphicalObject(PLANE,_p.pt,_p.idMat,_p.normal)
  {
    for (unsigned iter=0;iter<9;iter++)
        *((&a)+iter) = *((&_p.a)+iter)
  }


  int Intersect(const Ray &ray, real& dist);

  void affiche()
  { 

  }

};


*/













/** on fera ca apres

class GraphicalSpline : public GraphicalObject
{
protected:
  vector<Point>
}
*/

#endif
