#include "mof/Camera.hpp"
#include "mof/streams.hpp"
#include "mof/ConsoleIO.hpp"
#include <d3d9.h>

struct mof::Camera::Impl{
	mof::Manipulator<mof::Vector3D>::Handler eye;
	mof::Manipulator<mof::Vector3D>::Handler center;
	mof::Manipulator<mof::Vector3D>::Handler up;
	mof::FrameNumber frame;

	Impl(
		const mof::Manipulator<mof::Vector3D>::Handler& eye_ ,
		const mof::Manipulator<mof::Vector3D>::Handler& center_ ,
		const mof::Manipulator<mof::Vector3D>::Handler& up_ 
		) : eye(eye_) , center(center_) , up(up_) , frame(0){}

	~Impl(){}
};


mof::Camera::Camera(
	const mof::Manipulator<mof::Vector3D>::Handler& eye , 
	const mof::Manipulator<mof::Vector3D>::Handler& center ,
	const mof::Manipulator<mof::Vector3D>::Handler& up 
	) : m_pImpl(new Impl(eye , center , up)){
}

mof::Camera::Camera(
	const mof::Vector3D& eye , 
	const mof::Vector3D& center , 
	const mof::Vector3D& up
	) : m_pImpl(new Impl(
		mof::makeConstantHandler(eye) ,
		mof::makeConstantHandler(center) ,
		mof::makeConstantHandler(up) 
		)){
}

mof::Camera::~Camera(){
}

mof::Matrix3D mof::Camera::getViewMatrix() const{
	return mof::Matrix3D::createLookAtLH(
		m_pImpl->eye->value(m_pImpl->frame) ,
		m_pImpl->center->value(m_pImpl->frame) ,
		m_pImpl->up->value(m_pImpl->frame) 
		);
}

void mof::Camera::setEye(const mof::Manipulator<mof::Vector3D>::Handler& eye){
	m_pImpl->eye = eye;
}


void mof::Camera::setEye(const mof::Vector3D& eye){
	m_pImpl->eye = mof::makeConstantHandler(eye);
}

void mof::Camera::setCenter(const mof::Manipulator<mof::Vector3D>::Handler& center){
	m_pImpl->center = center;
}


void mof::Camera::setCenter(const mof::Vector3D& center){
	m_pImpl->center = mof::makeConstantHandler(center);
}


void mof::Camera::setUp(const mof::Manipulator<mof::Vector3D>::Handler& up){
	m_pImpl->up = up;
}


void mof::Camera::setUp(const mof::Vector3D& up){
	m_pImpl->up = mof::makeConstantHandler(up);
}

		
mof::Vector3D mof::Camera::getEye() const{
	return m_pImpl->eye->value(m_pImpl->frame);
}

		
mof::Vector3D mof::Camera::getCenter() const{
	return m_pImpl->center->value(m_pImpl->frame);
}

		
mof::Vector3D mof::Camera::getUp() const{
	return m_pImpl->up->value(m_pImpl->frame);
}




void mof::Camera::setFrameNumber(mof::FrameNumber frame){
	m_pImpl->frame = frame;
}


void mof::Camera::update(){
	m_pImpl->frame++;
}


