#pragma once
#include "../stdafx.h"
#include "glLibLocals.h"
#include "glLibMath/glLibMathMatrix.h"

namespace glLib {

namespace Math {
	template <typename type_element, typename type_int> class matrix;
}

namespace View {

class glLibInternal_glLibView {
	//Update glLibInternal_copy_from!
	//TODO: make sure you can't .set_view() if you've only used the default constructor
	public:
		int x, y, width, height, size[2], rect[4];
		//TODO: clip_near, clip_far
		float fov_angle, near_clip, far_clip;
		float aspect_ratio;

	public:
		glLibInternal_glLibView(void);
		glLibInternal_glLibView(const int r[4], float near_value, float far_value);
		glLibInternal_glLibView(const glLibInternal_glLibView& copy);
		glLibInternal_glLibView& operator=(const glLibInternal_glLibView& other);
		~glLibInternal_glLibView(void);
	private:
		void glLibInternal_copy_from( const glLibInternal_glLibView* copy);
	protected:
		virtual void glLibInternal_set_proj(void) const {}
	public:
		void set_view(void) const;
		//TODO: add overload for mat[4][4]
		void get_matrix_projection(GLfloat matrix[16]) const;
		void get_matrix_projection(GLdouble matrix[16]) const;
		template <typename type_float, typename type_int> void get_matrix_projection(Math::matrix<type_float,type_int>* matrix) const {
			#ifdef GLLIB_ERROR_MODE_REPORT_ERRORS
			if ((matrix->_rows!=4)||(matrix->_columns!=4)) throw GLLIB_ERROR_TYPE_ERROR("Matrix dimensions are incorrect!  Must be 4x4.");
			#endif

			type_float data[16];
			get_matrix_projection(data);

			for (char x=0;x<4;++x) {
				for (char y=0;y<4;++y) {
					matrix->values[y][x] = data[x*4+y];
					//TODO: check whether this is transposed!
					//Matrix class should mimic OpenGL
				}
			}
		}
};

class view_2D : public glLibInternal_glLibView {
	public:
		view_2D(void);
		view_2D(const int rect[4]);
	private:
		void glLibInternal_set_proj(void) const;
};
class view_isometric : public glLibInternal_glLibView {
	public:
		float zoom;
		view_isometric(void);
		view_isometric(const int rect[4], float near_value=0.1f, float far_value=1000.0f);
		
		void set_near(float value);
		void set_far(float value);
		void set_zoom(float value);
	private:
		void glLibInternal_set_proj(void) const;
};
class view_3D : public glLibInternal_glLibView {
	public:
		view_3D(void);
		view_3D(const int rect[4], float angle, float near_value=0.1f, float far_value=1000.0f);
		
		void set_angle(float angle);
		void set_near(float value);
		void set_far(float value);
	private:
		void glLibInternal_set_proj(void) const;
};

void push_view(void);
void pop_view(void);

};};