#include "MyCamera.h"
#include "MatrixStack.h"
#include <iostream>
#include <glm/gtc/matrix_transform.hpp>

Camera::Camera() :
	aspect(1.0f),
	fovy(45.0f),
	znear(0.1f),
	zfar(1000.0f),
	rotations(0.0, 0.0),
	translations(0.0f, 0.0f, -5.0f),
	rfactor(0.01f),
	tfactor(0.001f),
	sfactor(0.005f),
  pos(0.0f, 0.0f, 1.0f),
  pitch(0.0f),
  yaw(0.0f)
{
}

Camera::~Camera()
{
}

void Camera::mouseClicked(float x, float y, bool shift, bool ctrl, bool alt)
{
	mousePrev.x = x;
	mousePrev.y = y;
	if(shift) {
		state = Camera::TRANSLATE;
	} else if(ctrl) {
		state = Camera::SCALE;
	} else {
		state = Camera::ROTATE;
	}
}

void Camera::mouseMoved(float x, float y)
{
	glm::vec2 mouseCurr(x, y);
	glm::vec2 dv = mouseCurr - mousePrev;
	switch(state) {
		case Camera::ROTATE:
			rotations += rfactor * dv;
      if(rotations.y > 0.6)
      {
              rotations.y = 0.6;
      }
      else if(rotations.y < -0.6)
      {
              rotations.y = -0.6;
      }
			break;
		case Camera::TRANSLATE:
			translations.x -= translations.z * tfactor * dv.x;
			translations.y += translations.z * tfactor * dv.y;
			break;
		case Camera::SCALE:
			translations.z *= (1.0f - sfactor * dv.y);
			break;
	}
	mousePrev = mouseCurr;
}

void Camera::applyProjectionMatrix(std::shared_ptr<MatrixStack> P) const
{
	// Modify provided MatrixStack
	P->multMatrix(glm::perspective(fovy, aspect, znear, zfar));
}

glm::vec3 Camera::getPos()
{
  return pos;
}

void Camera::transpose(glm::vec3 t)
{
  glm::vec3 target(sin(rotations.x), 0, cos(rotations.x));
  pos -= (cross(glm::vec3(0, 1, 0), target))*t.x;
  pos -= target*t.z;
}

void Camera::applyViewMatrix(std::shared_ptr<MatrixStack> MV) const
{
  glm::vec3 target(sin(rotations.x), sin(rotations.y), cos(rotations.x));
  MV->multMatrix(glm::lookAt(pos, pos + target, glm::vec3(0,1,0)));
}
