/* 
   Project: coevolutionary GP moto driving
   Dana Vrajitoru
   road_manager.h
   
   The class that handles the road and some basic functionality
   related to it.
  
**/

#ifndef ROAD_MANAGER_H
#define ROAD_MANAGER_H

#include "point3f.h"

typedef vector<int> vectori;

class Road_manager {
 protected:
  GLuint road_id, centerline_id;
  bool centerline, dotted;
  GLfloat scale, angle;
  Point3f position;
  Point3f min, max; // bounding box
  matrix3f coords;
  vector3f normals;
  vector3f center_coords;
  vector<float> d_pars;
  vector<vectori> neighbors, edges; // the neighbor of each triangle
                                    // and the common edge
  vectori is_border; // if a triangle is on the border of the road or not
  int nr_trigs, nr_points;
  float epsilon;

 public:
  // default constructor
  Road_manager();
  // Constructor with a file name - read the road from a file.
  Road_manager(const char *filename);
  // destructor
  ~Road_manager();

  // Set and get these values;
  void set_scale(float val = 1.0);
  void set_angle(float val=0.0);
  void set_position(const Point3f &data);
  void set_position(float x=0, float y=0, float z=0);

  GLfloat get_scale();
  GLfloat get_angle();
  Point3f &get_position();

  // Perform some operations on the data itself to accelerate the
  // computations.
  void zoom(float val = 1.0);
  void translate(float x=0, float y=0, float z=0);
  void rotate_x(float angle);
  void rotate_y(float angle);
  void rotate_z(float angle);

  // Function to return the center_coord[size]
  int coord_size();

  // Tells us if the road has a visible centerline.
  bool has_centerline();

  // Tells us if the centerline is dotted.
  bool is_dotted();

  // Function to be called to generate the display lists.
  void draw();
  // Function to be called to generate the display lists for the small
  // overview window.
  void draw_sml();
  // Function to be called to display the lists.
  void display();
  // Read the triangles from a file.
  bool read(const char *filename);
  // Read the centerline from a file.
  bool read_center(const char *filename);

  //to find the number of points in the line
  int center_size();

  //to find the distance between two points
  float distance_center(const Point3f &position,int prev);

  // to find the position of the motorcycle with respect to the line
  int locate_center(const Point3f &position,int prev);

  // Locate a position inside the mesh. If the point intersects more
  // than one triangle, choose the one closest to it.
  int locate(const Point3f &position);

  // Check if the position is inside a given triangle.
  bool is_inside(const Point3f &position, const int trig);

  // Locate a position inside the triangles that are direct neighbors
  // of the old triangle. When the moto moves out of a given triangle,
  // we might want to start looking for its current location in the
  // neighborhood first.
  int locate_neighborhood(const Point3f &position, int trig);

  // Find the intersection between a vertical in the given position
  // and the plane of the specified triangle.
  float project_y_diff(const Point3f &position, int trig);

  // Some function for the interaction with the motorcycle or any
  // other object on it.
  float get_slope(const Point3f &position, float angle);

  // Some function for the interaction with the motorcycle or any
  // other object on it. The triangle is given.
  float get_slope(const Point3f &position, float angle, int trig);
  
  // Compute all the normals to the triangles - these will be used
  // over and over, want to speed up the computations.
  void compute_normals();
  // Compute the d parameter in the equation of the plane for each
  // triangle. This is used to compute the projection of an object
  // onto the road and can speed up computations too.
  void compute_d_pars();
  // Compute the bounding box, the min and max pointers.
  void compute_bbox();
  // For each triangle, find the neighbors
  void compute_neighbors();
  // Displays the neighbors structure
  void print_neighbors();
  // Displays the coordinates
  void print_coordinates();

  // Some methods for tracing rays inside triangles and get some
  // information about the surrounding of the motorcycle on the road.

  // Trace a ray inside a triangle. The ray is given by a point
  // supossedly inside the triangle and a direction. We must find the
  // position where the ray gets out of the triangle and the triangle
  // into which it goes. If the exit edge is a border, return -1 for
  // the neighbor triangle.
  int trace(int trig, const Point3f &pos, const Point3f &dir, 
	    Point3f &out_pos);
  // Find out if the ray coming in intersect the triangle again in any
  // points that is different from the starting one. Returns -2 if
  // there's no new intersection, meaning that the ray doesn't go into
  // the triangle. The new intersection point if stored in the
  // parameter out_pos. The returned value is 0-2 if the intersection
  // is on an edge, and 3-5 if it's a vertex, in which case the vertex
  // in question is the returned value -3.
  int intersect_trig(int trig, const Point3f &pos, 
		     const Point3f &dir, Point3f &out_pos);
  // Find a neighbor sharing the same edge. Return -1 if that edge is
  // a border.
  int trace_edge(int trig, int edge);
  // Find a neighbor sharing the same vertex. It has to check both the
  // triangles having in common an edge containing this vertex and
  // those having this vertex in common. Returns -1 if it doesn't find
  // anything, meaning that we found a border.
  int trace_vertex(int trig, int vertex, const Point3f &pos, 
		   const Point3f &dir);
  // Trace a ray inside the triangle mesh until it gets out of the
  // mesh or until it cannot find a new intersection anymore.
  int trace_out(int trig, const Point3f &pos, const Point3f &dir, 
		Point3f &out_pos);
  
  friend class Manager;
};

#endif
