// Vorosweep - Copyright (C) 2010-2014 T. Mouton
//
// See the LICENSE.txt file for license information. Please report all
// bugs and problems to <thibaud.mouton@gmail.com>.

#include "sweepobject.h"
#include "frontline.h"

#ifndef _GENERATOR_INCLUDE
#define _GENERATOR_INCLUDE

namespace vorosweep
{

class Convex_generator : public basic_type
{
  public:
    static const char *statusname[];
  public:
    enum genstatus {ACTIVE, NOACTIVE};
  protected:
    Point *apex;
    double angle;
    double v[2];
    matrix *A;
    std::vector<SweepEdge *> se;
    std::vector<SweepFacet *> sf;
    int initnf;
    int nf;
    genstatus state;
  public:
    Convex_generator ( double *pt, double t0, int nface, double a, double v1, double v2, int index );
    ~Convex_generator()
    {
      for (int i = 0; i < (int)se.size(); i++)
        delete se[i];
      for (int i = 0; i < (int)sf.size(); i++)
        delete sf[i];
    }
    inline Point *get_apex ( )
    {
      return apex;
    }
    inline double get_start_time()
    {
      return apex->p[2]; // it is the z coordinate
    }
    inline int initial_face_size()
    {
      return initnf;
    }
    inline int face_size()
    {
      return nf;
    }
    inline SweepFacet *get_prev_facet ( int i )
    {
      return sf[ ( i+initnf-1 ) %initnf];
    }
    inline SweepFacet *get_next_facet ( int i )
    {
      return sf[ ( i+1 ) %initnf];
    }
    inline SweepEdge *get_sweepedge ( int i )
    {
      if ( i >= nf )
        return NULL;
      return se[i];
    }
    inline SweepFacet *get_sweepfacet ( int i )
    {
      if ( i >= nf )
        return NULL;
      return sf[i];
    }
    inline matrix *get_matrix()
    {
      return A;
    }
    inline void add_sweepfacet ( SweepFacet *f )
    {
      sf.push_back ( f );
      nf++;
    }
    inline void compute_normal_plane(double x, double y, double *plane)
    {
        plane[2] = -1.0;
        plane[0] = 2.0*(x-apex->p[0]) *(pow(sin(A->angle),2)/(A->v[1]*A->v[1]*plane[2]*plane[2])+pow(cos(A->angle),2)/(A->v[0]*A->v[0]*plane[2]*plane[2])) +2*(y-apex->p[1])*(cos(A->angle)*sin(A->angle)/(A->v[0]*A->v[0]*plane[2]*plane[2])-cos(A->angle)*sin(A->angle)/(A->v[1]*A->v[1]*plane[2]*plane[2]));
        plane[1] = 2.0*(x-apex->p[0]) *(cos(A->angle)*sin(A->angle)/(A->v[0]*A->v[0]*plane[2]*plane[2])-cos(A->angle)*sin(A->angle)/(A->v[1]*A->v[1]*plane[2]*plane[2]))+2*(y-apex->p[1])*(pow(cos(A->angle),2)/(A->v[1]*A->v[1]*plane[2]*plane[2])+pow(sin(A->angle),2)/(A->v[0]*A->v[0]*plane[2]*plane[2]));
    }
//     inline void compute_normal_plane ( double x, double y, double *plane )
//     {      
//       double p = 4.0 ;      
//       plane[2] = -1.0;
//       x = copysign(1.0, x)*pow( fabs(x), 2.0/p);
//       y = copysign(1.0, y)*pow( fabs(y), 2.0/p);
//       double vnorm = pow(fabs(x),p)+pow(fabs(y),p);
//       printf("v norm = %lf\n", vnorm);
//       x /= vnorm;
//       y /= vnorm;
//       plane[0] = ( p*copysign(1.0, x)*pow(fabs(x)/*(x-apex->p[0])*/,( p-1.0 )) ) /pow(A->v[0],( p ));
//       plane[1] = ( p*copysign(1.0, y)*pow(fabs(y)/*(y-apex->p[1])*/,( p-1.0 )) ) /pow(A->v[1],( p ));
//       printf ( "n --> %lf %lf %lf\n", plane[0], plane[1], plane[2] );
//     }

    inline int is_active()
    {
      return ( state == ACTIVE );
    }
    inline void set_active()
    {
      state = ACTIVE;
    }
    void generate();
    void update_current ( double time );
};

};

#endif
