#include "mof/Board.hpp"
#include "mof/Camera.hpp"
#include "mof/Material.hpp"
#include "mof/private/GraphicsDeviceImpl.hpp"
#include "mof/ConsoleIO.hpp"
#include "mof/Font.hpp"
#include "mof/stream/Constant.hpp"

struct mof::Board::Impl{
	std::shared_ptr<mof::Texture> pTexture;

	Impl(){}
	~Impl(){}
};



mof::Board::Board() : m_pImpl(new Impl()){
}

mof::Board::~Board(){
}
	

void mof::Board::setTexture( const std::shared_ptr<mof::Texture>& pTexture ){
	m_pImpl->pTexture = pTexture;
}


bool mof::Board::isVisible() const{
	return true;
}

void mof::Board::update(){
	world_transform_.update();
    m_textureStream.update();
    m_colorStream.update();
}


void mof::Board::draw() const{
	mof::Rectangle<float> textureCoordinates = getRectangleCoordinatesStream().value();
	mof::Color color = m_colorStream.value().toColorCode();
	static mof::VertexXYZCUV vertices[4];
	vertices[0].x = -0.5f;
	vertices[0].y = 0.5f;
	vertices[0].z = 0;
	vertices[0].color = color;
	vertices[0].tu = textureCoordinates.beginX;
	vertices[0].tv = textureCoordinates.beginY;

	vertices[1].x = 0.5f;
	vertices[1].y = 0.5f;
	vertices[1].z = 0;
	vertices[1].color = color;
	vertices[1].tu = textureCoordinates.endX;
	vertices[1].tv = textureCoordinates.beginY;

	vertices[2].x = -0.5f;
	vertices[2].y = -0.5f;
	vertices[2].z = 0;
	vertices[2].color = color;
	vertices[2].tu = textureCoordinates.beginX;
	vertices[2].tv = textureCoordinates.endY;

	vertices[3].x = 0.5f;
	vertices[3].y = -0.5f;
	vertices[3].z = 0;
	vertices[3].color = color;
	vertices[3].tu = textureCoordinates.endX;
	vertices[3].tv = textureCoordinates.endY;

	mof::GraphicsDevice::setTexture(m_pImpl->pTexture.get());
	mof::Material mat;
	mat.ambientColor = mof::Color4f(color);
	mof::GraphicsDevice::setMaterial(mat);
	mof::Matrix3D::Array view = mof::GraphicsDevice::getViewTransform().getArray();// 一時コード（カメラの回転を無効）
	view.elements[3][0] = view.elements[3][1] = view.elements[3][2] = 0;
	mof::Matrix3D inv_view = mof::Matrix3D::createTransposed(mof::Matrix3D(view));

	// world_transform_をそのまま使わず、回転成分を除去する
	// TODO すごく非効率なので、ここは直さないとなー
	Matrix3D trans = world_transform_.value();
	Vector3D v1 = Vector3D(1, 0, 0) * trans - mof::Matrix3D::getTranslation(trans);
	Vector3D v2 = Vector3D(0, 1, 0) * trans - mof::Matrix3D::getTranslation(trans);
	Vector3D v3 = Vector3D(0, 0, 1) * trans - mof::Matrix3D::getTranslation(trans);
	float s1 = sqrt(v1.x * v1.x + v1.y * v1.y + v1.z * v1.z);
	float s2 = sqrt(v2.x * v2.x + v2.y * v2.y + v2.z * v2.z);
	float s3 = sqrt(v3.x * v3.x + v3.y * v3.y + v3.z * v3.z);
	Matrix3D scaling = Matrix3D::createScaling(Vector3D(s1, s2, s3));
	Matrix3D translation = Matrix3D::createTranslation(Matrix3D::getTranslation(trans));
	mof::GraphicsDevice::setWorldTransform(scaling * inv_view * translation);
	mof::GraphicsDevice::drawVertexArray(vertices[0] , vertices[3] , PRIMITIVE_TYPE_TRIANGLESTRIP);
	
}

void mof::Board::setVisible(bool)
{
	// TODO
}


std::unique_ptr<mof::Board> 
mof::Board::create_text_board(const Font& font, const tstring& text)
{
	using namespace mof;

	std::shared_ptr<PixelMap> pPixelMap( font.createText(text) );
    std::shared_ptr<Texture> pTexture(new Texture( pPixelMap));

	auto p = std::unique_ptr<Board>(new Board());
	p->setTexture(pTexture);
	float scale_x = static_cast<real>(pPixelMap->shape()[0]) / 300;
	float scale_y = static_cast<real>(pPixelMap->shape()[1]) / 300;
	p->world_transform() << Matrix3D::createScaling(mof::Vector3D(scale_x, scale_y, 1));
	float width = static_cast<float>(pPixelMap->shape()[0]) / pTexture->getWidth();
	float height = static_cast<float>(pPixelMap->shape()[1]) / pTexture->getHeight();
	p->getRectangleCoordinatesStream() << Rectangle<float>(0, 0, width, height);
	return p;
}



