#include "CameraController.h"


CameraController::CameraController(GLFWwindow* window)
	: mp_window(window)
{
	//mp_window = window;
	m_camera_position = glm::vec3(0, 0, 20);
	m_horizontal_angle = 3.14f;
	m_vertical_angle = 0.0f;
	m_initialFOV = 45.0f;

	m_keyboard_speed = 30.0f;
	m_mouse_speed = 0.003f;
	//glfwGetWindowSize(mp_window, &m_window_size_width, &m_window_size_height);
	//m_last_xpos = m_window_size_width / 2;
	//m_last_ypos = m_window_size_height / 2;

	//m_arc_rotation = glm::mat4(1.0);
	//tempRotate = glm::mat4(1.0);
	//mouse_status = 0;
	//arcBallRadius = 100;
}


CameraController::~CameraController()
{

}


glm::mat4 CameraController::GetViewMatrix()
{
	return m_view_space; // * tempRotate * m_arc_rotation;
}


glm::mat4 CameraController::GetProjectionMatrix()
{
	return m_projection_space;
}

//void CameraController::setWindowWidthHeight(int w, int h)
//{
//	m_window_height = h;
//	m_window_width = w;
//}

void CameraController::ComputeMatricesFromInputs()
{
	// glfwGetTime is called only once, the first time this function is called
	static double lastTime = glfwGetTime();

	// Compute time difference between current and last frame
	double currentTime = glfwGetTime();
	float deltaTime = float(currentTime - lastTime);

	// Get mouse position
	static double current_xpos, current_ypos;
	glfwGetCursorPos(mp_window, &current_xpos, &current_ypos);

	// Reset mouse position for next frame
	glfwGetWindowSize(mp_window, &m_window_width, &m_window_height);
	//glfwSetCursorPos(window, m_window_size_width / 2, m_window_size_height / 2);

	// Compute new orientation
	if (glfwGetMouseButton(mp_window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS)
	{
		m_horizontal_angle += m_mouse_speed * float(m_last_xpos - current_xpos);
		m_vertical_angle += m_mouse_speed * float(m_last_ypos - current_ypos);
	}
	m_last_xpos = current_xpos;
	m_last_ypos = current_ypos;

	// Direction : Spherical coordinates to Cartesian coordinates conversion
	glm::vec3 direction(
		cos(m_vertical_angle) * sin(m_horizontal_angle),
		sin(m_vertical_angle),
		cos(m_vertical_angle) * cos(m_horizontal_angle)
	);

	// Right vector
	glm::vec3 right = glm::vec3(
		sin(m_horizontal_angle - 3.14f / 2.0f),
		0,
		cos(m_horizontal_angle - 3.14f / 2.0f)
	);

	// Up vector
	glm::vec3 up = glm::cross(right, direction);

	// Move forward
	if (glfwGetKey(mp_window, GLFW_KEY_W) == GLFW_PRESS)
	{
		m_camera_position += direction * deltaTime * m_keyboard_speed;
	}
	// Move backward
	if (glfwGetKey(mp_window, GLFW_KEY_S) == GLFW_PRESS)
	{
		m_camera_position -= direction * deltaTime * m_keyboard_speed;
	}
	// Move right
	if (glfwGetKey(mp_window, GLFW_KEY_D) == GLFW_PRESS)
	{
		m_camera_position += right * deltaTime * m_keyboard_speed;
	}
	// Move left
	if (glfwGetKey(mp_window, GLFW_KEY_A) == GLFW_PRESS)
	{
		m_camera_position -= right * deltaTime * m_keyboard_speed;
	}
	// Move up
	if (glfwGetKey(mp_window, GLFW_KEY_R) == GLFW_PRESS)
	{
		m_camera_position += up * deltaTime * m_keyboard_speed;
	}
	// Move down
	if (glfwGetKey(mp_window, GLFW_KEY_F) == GLFW_PRESS)
	{
		m_camera_position -= up * deltaTime * m_keyboard_speed;
	}

	// Projection matrix : 45 Field of View, 4:3 ratio, display range : 0.1 unit <-> 100 units
	if (m_window_height > 0)
	{
		m_projection_space = glm::perspective(
			glm::radians(m_initialFOV),
			(float)m_window_width / (float)m_window_height, // 화면 최소화시 0 으로 나누어서 오류 발생 (오류 해결 : 2019-02-22)
			0.1f,
			1000.0f // Draw distance
		);
	}

	// Camera matrix
	m_view_space = glm::lookAt(
		m_camera_position,				// Camera is here
		m_camera_position + direction,	// And looks here : at the same position, plus "direction"
		up								// Head is up (set to 0,-1,0 to look upside-down)
	);

	// For the next frame, the "last time" will be "now"
	lastTime = currentTime;

}


//void CameraController::MouseCallBackFunction(GLFWwindow* window, double xpos, double ypos)
//{
//	if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS)
//	{
//		if (mouse_status == 0)
//		{
//			start_cursor[0] = xpos;
//			start_cursor[1] = ypos;
//			start_cursor[2] = 0;
//			mouse_status = 1;
//		}
//		else
//		{
//			glm::vec3 end_cursor;
//			end_cursor[0] = xpos;
//			end_cursor[1] = ypos;
//			end_cursor[2] = 0;
//			setArcAngle(start_cursor, end_cursor);
//		}
//	}
//	else
//	{
//		if (mouse_status == 1)
//		{
//			mouse_status = 0;
//			m_arc_rotation = tempRotate*m_arc_rotation;
//			tempRotate = identity;
//		}
//	}
//}
//
//
//void CameraController::setArcAngle(glm::vec3 start, glm::vec3 end)
//{
//	glm::vec3 intersection_start = rayCast(start);
//	glm::vec3 intersection_end = rayCast(end);
//	double cosine_angle = glm::dot(intersection_start, intersection_end);
//	cosine_angle = cosine_angle / (glm::length(intersection_start)*glm::length(intersection_end));
//	float angle = (acos(cosine_angle) / (3.14f))*180.0f;
//	glm::mat4 identity = glm::mat4(1.0f);
//	tempRotate=glm::rotate(identity,angle, -glm::normalize(glm::cross(intersection_start,intersection_end)));
//	//m_arc_rotation = glm::rotate(m_arc_rotation,angle, intersection_start);
//
//}
//
//
//glm::vec3 CameraController::rayCast(glm::vec3 emit)
//{
//	//First compute Xwi
//	glm::mat4 inverse_view_space = glm::transpose(m_view_space);
//	inverse_view_space[0][3] = m_camera_position[0];
//	inverse_view_space[1][3] = m_camera_position[1];
//	inverse_view_space[2][3] = m_camera_position[2];
//
//	double width = 
//
//	//uniform emit to -1~1
//	emit[0] = (emit[0] - m_window_width / 2) / (m_window_width / 2);
//	emit[1] = ((m_window_height / 2)-emit[1]) / (m_window_height / 2);
//
//	glm::vec4 emit_ext = glm::vec4(emit, 1);
//	glm::vec3 world_space = glm::vec3(inverse_view_space * emit_ext);
//	glm::vec3 ray_direction = glm::normalize(world_space - m_camera_position);
//
//	//get the distance from the center to the ray
//	double cos_theta =glm::dot( glm::normalize(-m_camera_position) ,ray_direction);
//	double distance = glm::length(m_camera_position)*sin(acos(cos_theta));
//	if (distance > arcBallRadius)
//	{
//		double len = glm::length(m_camera_position)*cos_theta;
//		glm::vec3 intersection = float(len) * ray_direction + m_camera_position;
//		return intersection;
//	}
//	else
//	{
//		double len1 = sqrt(arcBallRadius*arcBallRadius - distance*distance);
//		double len2 = glm::length(m_camera_position)*cos_theta-len1;
//		glm::vec3 intersection = float(len2) * ray_direction + m_camera_position;
//		return intersection;
//	}
//
//}
//
//
//void CameraController::mousecb(GLFWwindow* window, double xpos, double ypos)
//{
//	getInstance().MouseCallBackFunction(window, xpos, ypos);
//}