#include <vamos/geometry/Gl_Texture_Image.h>
#include <vamos/geometry/Three_Vector.h>
#include <vamos/geometry/Two_Point.h>

#include <GL/gl.h>

#include <vector>

namespace Vamos_Body
{
  class Facade : public Vamos_Geometry::Gl_Texture_Image
  {
	double m_x;
	double m_y;
	double m_above;
	double m_width;
	double m_height;
	GLuint m_list_index;	

	void build_facade ();
	void build_image ();

  public:
	Facade (double x, double y, double above, double width, double height, 
			std::string image);

	Facade (double center_x, double center_y, double above, double radius,
			std::string image);

	void rotate (double degrees) const;
	virtual void draw () const;
  };

  class Scaler
  {
	double m_minimum_input;
	double m_maximum_input;
	double m_offset;
	double m_factor;
	
  public:
	Scaler (double min_in, double min_out, double max_in, double max_out);
	double scale (double value_in);
  };

  class Steering_Wheel : public Facade
  {
	double m_center_x;
	double m_center_y;
	double m_angle;
	Scaler m_scaler;

  public:
	Steering_Wheel (double center_x, double center_y, double above, 
					double radius, double min, double min_angle, 
					double max, double max_angle,
					std::string image);

	void set (double value);
	void draw () const;
  };

  class Gauge
  {
  protected:
	bool m_on_steering_wheel;

  public:
	Gauge () : m_on_steering_wheel (false) {};
	virtual ~Gauge () {};
	virtual void set (double value) = 0;
	virtual void draw () const = 0;
	bool on_steering_wheel () const { return m_on_steering_wheel; }
  };

  class Dial : public Gauge
  {
	double m_above;
	Scaler m_scaler;
	
	Facade* mp_face;
	Facade* mp_needle;

  protected:
	double m_center_x;
	double m_center_y;
	double m_angle;

  public:
	Dial (double center_x, double center_y, double above, double radius, 
		  double min, double min_angle, double max, double max_angle,
		  std::string face_image, std::string needle_image);
	
	~Dial ();
	
	void set (double value);
	void draw () const;

	//	double angle () const { return m_angle; }
  };

  class LED_Gauge : public Gauge
  {
	double m_x;
	double m_y;
	double m_above;
	double m_width;
	double m_height;
	int m_elements;
	double m_min;
	double m_range;

	int m_leds_on;

	Vamos_Geometry::Gl_Texture_Image* mp_leds;

	GLuint m_list_index;

  public:
	LED_Gauge (double x, double y, double above, double width, int elements,
			   double min, double redline, std::string image, bool on_wheel);
	~LED_Gauge ();

	void set (double value);
	void draw () const;
  };

  class Digital_Gauge : public Gauge
  {
	double m_x;
	double m_y;
	double m_above;
	double m_width;
	double m_height;
	size_t m_places;

	std::vector <int> m_digits;

	Vamos_Geometry::Gl_Texture_Image* mp_digits;

  public:
	Digital_Gauge (double x, double y, double above, 
				   double width, double height, size_t places,
				   std::string digits, bool on_wheel);
	~Digital_Gauge ();

	void set (double value);
	void draw () const;
  };


  class Gear_Indicator
  {
	bool m_on_steering_wheel;

	double m_number_width;

	Vamos_Geometry::Gl_Texture_Image* mp_numbers;

  protected:
	double m_x;
	double m_y;
	double m_above;
	double m_width;
	double m_height;
	int m_gear;

  public:
	Gear_Indicator (double x, double y, double above, 
					double width, double height,
					int numbers, std::string image, bool on_wheel);
	~Gear_Indicator ();

	virtual void set (int gear) { m_gear = gear; }
	virtual void draw () const;
	bool on_steering_wheel () const { return m_on_steering_wheel; }
  };


  class Gear_Shift : public Gear_Indicator
  {
	double m_stick_width;
	double m_stick_height;

	Vamos_Geometry::Three_Vector m_rotation;
	std::vector <Vamos_Geometry::Two_Point> m_positions;
	int m_top_gear;

	Vamos_Geometry::Gl_Texture_Image* mp_gate;
	Vamos_Geometry::Gl_Texture_Image* mp_stick;

	GLuint m_list_index;

  public:
	Gear_Shift (double x, double y, double z, double width, double height,
				const Vamos_Geometry::Three_Vector& rotation,
				const std::vector <Vamos_Geometry::Two_Point>& positions,
				std::string gate_image, std::string stick_image);
	~Gear_Shift ();

	void set (int gear);
	void draw () const;
  };


  class Dashboard
  {
	double m_x;
	double m_y;
	double m_z;
	double m_tilt;

	Gauge* mp_tachometer;
	Gauge* mp_speedometer;
	Gauge* mp_fuel_gauge;
	Gear_Indicator* mp_gear_indicator;
	Steering_Wheel* mp_steering_wheel;
	std::vector <Facade*> ma_facades;

  public:
	Dashboard (double x, double y, double z, double tilt);
	~Dashboard ();

	void add_tachometer (Gauge* tachometer);
	void add_speedometer (Gauge* speedometer);
	void add_fuel_gauge (Gauge* fuel_gauge);
	void add_gear_indicator (Gear_Indicator* gear_indicator);
	void add_steering_wheel (Steering_Wheel* steering_wheel);
	void add_facade (Facade* facade);

	void set_tachometer (double rpm);
	void set_speedometer (double speed);
	void set_fuel_gauge (double fuel);
	void set_gear_indicator (int gear);
	void set_steering_wheel (double angle);

	void draw () const;
  };
}
