//	LuaDrawer.cpp - Wrapper for passing a Drawer to a lua script.
//  ----------------------------------------------------------------------------
//	This file is part of 'NiallsAVLib', base code for any kind of audiovisual
//	apps.
//	Copyright (C) 2013  Niall Moody
//	
//	This program is free software: you can redistribute it and/or modify
//	it under the terms of the GNU General Public License as published by
//	the Free Software Foundation, either version 3 of the License, or
//	(at your option) any later version.
//
//	This program is distributed in the hope that it will be useful,
//	but WITHOUT ANY WARRANTY; without even the implied warranty of
//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//	GNU General Public License for more details.
//
//	You should have received a copy of the GNU General Public License
//	along with this program.  If not, see <http://www.gnu.org/licenses/>.
//	----------------------------------------------------------------------------

#include "drawing/TextLayout.h"
#include "drawing/Drawer.h"
#include "LuaDrawer.h"

extern "C" {
  #include "lua.h"
  #include "lualib.h"
  #include "lauxlib.h"
}

#include "luabind/luabind.hpp"

//------------------------------------------------------------------------------
LuaDrawer::LuaDrawer()
{

}

//------------------------------------------------------------------------------
LuaDrawer::~LuaDrawer()
{

}

//------------------------------------------------------------------------------
void LuaDrawer::setDrawer(shared_ptr<Drawer>& d)
{
	drawer = d;
}

//------------------------------------------------------------------------------
void LuaDrawer::registerLuaMethods(lua_State *luaState)
{
	luabind::module(luaState)
	[
		luabind::class_<TextLayout>("TextLayout")
			.def(luabind::constructor<>())
			.def("clear", &TextLayout::clear),
		luabind::class_<LuaDrawer>("LuaDrawer")
			.def("setClearBetweenFrames", &LuaDrawer::setClearBetweenFrames)
			.def("registerShaderParam", &LuaDrawer::registerShaderParam)
			.def("useShader", &LuaDrawer::useShader)
			.def("setShaderParam", &LuaDrawer::setShaderParam)
			.def("drawImage", &LuaDrawer::drawImage)
			.def("drawRotImage", &LuaDrawer::drawRotImage)
			.def("drawSubImage", &LuaDrawer::drawSubImage)
			.def("drawTiledImage", &LuaDrawer::drawTiledImage)
			.def("drawText", &LuaDrawer::drawText)
			.def("drawTextCached", &LuaDrawer::drawTextCached)
			.def("drawLine", &LuaDrawer::drawLine)
			.def("drawConnectedLine", &LuaDrawer::drawConnectedLine)
			.def("fillRect", &LuaDrawer::fillRect)
			.def("fillGradient", &LuaDrawer::fillGradient)
			.def("translate", &LuaDrawer::translate)
			.def("scale", &LuaDrawer::scale)
			.def("rotate", &LuaDrawer::rotate)
			.def("setViewport", &LuaDrawer::setViewport)
			.def("resetViewport", &LuaDrawer::resetViewport)
			.def("startFrameBufferDrawing", &LuaDrawer::startFrameBufferDrawing)
			.def("endFrameBufferDrawing", &LuaDrawer::endFrameBufferDrawing)
			.def("getFrameBufferImage", &LuaDrawer::getFrameBufferImage)
			.def("getDrawingAreaSize", &LuaDrawer::getDrawingAreaSize)
			.def("getWindowSize", &LuaDrawer::getWindowSize)
	];
}

//------------------------------------------------------------------------------
void LuaDrawer::setClearBetweenFrames(bool val)
{
	drawer->setClearBetweenFrames(val);
}

//------------------------------------------------------------------------------
void LuaDrawer::registerShaderParam(const std::string& name)
{
	drawer->registerShaderParam(getWideName(name));
}

//------------------------------------------------------------------------------
void LuaDrawer::useShader(const std::string& shader)
{
	drawer->useShader(getWideName(shader));
}

//------------------------------------------------------------------------------
void LuaDrawer::setShaderParam(const std::string& param, float val)
{
	drawer->setShaderParam(getWideName(param), val);
}

//------------------------------------------------------------------------------
void LuaDrawer::drawImage(const std::string& name,
						  const TwoFloats& position,
						  const TwoFloats& size,
						  const ThreeFloats& colour,
						  float alpha)
{
	drawer->drawImage(getWideName(name),
					  position,
					  size,
					  colour,
					  alpha);
}

//------------------------------------------------------------------------------
void LuaDrawer::drawRotImage(const std::string& name,
							 const TwoFloats& position,
							 float angle,
							 const TwoFloats& pivot,
							 const TwoFloats& size,
							 const ThreeFloats& colour,
							 float alpha)
{
	drawer->drawRotImage(getWideName(name),
						 position,
						 angle,
						 pivot,
						 size,
						 colour,
						 alpha);
}

//------------------------------------------------------------------------------
void LuaDrawer::drawSubImage(const std::string& name,
							 const TwoFloats& position,
							 const TwoFloats& subPos,
							 const TwoFloats& subSize,
							 const TwoFloats& size,
							 const ThreeFloats& colour,
							 float alpha)
{
	drawer->drawSubImage(getWideName(name),
						 position,
						 subPos,
						 subSize,
						 size,
						 colour,
						 alpha);
}

//------------------------------------------------------------------------------
void LuaDrawer::drawTiledImage(const std::string& name,
							   const TwoFloats& position,
							   const TwoFloats& size,
							   const TwoFloats& tilePos,
							   const TwoFloats& tileNum,
							   const ThreeFloats& colour,
							   float alpha)
{
	drawer->drawTiledImage(getWideName(name),
						   position,
						   size,
						   tilePos,
						   tileNum,
						   colour,
						   alpha);
}

//------------------------------------------------------------------------------
void LuaDrawer::drawText(const std::string& text,
						 const std::string& font,
						 const TwoFloats& position,
						 float boxWidth,
						 int justification,
						 float size,
						 const ThreeFloats& colour,
						 float alpha)
{
	drawer->drawText(getWideName(text),
					 getWideName(font),
					 position,
					 boxWidth,
					 (TextLayout::Justification)justification,
					 size,
					 colour,
					 alpha);
}

//------------------------------------------------------------------------------
void LuaDrawer::drawTextCached(const std::string& text,
							   const std::string& font,
							   TextLayout& layout,
							   const TwoFloats& position,
							   float boxWidth,
							   int justification,
							   float size,
							   const ThreeFloats& colour,
							   float alpha)
{
	drawer->drawText(getWideName(text),
					 getWideName(font),
					 layout,
					 position,
					 boxWidth,
					 (TextLayout::Justification)justification,
					 size,
					 colour,
					 alpha);
}

//------------------------------------------------------------------------------
void LuaDrawer::drawLine(const std::string& image,
						 const TwoFloats& start,
						 const TwoFloats& end,
						 const ThreeFloats& colour,
						 float alpha)
{
	drawer->drawLine(getWideName(image),
					 start,
					 end,
					 colour,
					 alpha);
}

//------------------------------------------------------------------------------
void LuaDrawer::drawConnectedLine(const std::string& image,
								  const luabind::object& points,
								  const luabind::object& pointsScale,
								  const luabind::object& pointsColour,
								  const luabind::object& pointsAlpha)
{
	//Make sure the correct type objects have been passed in.
	if((luabind::type(points) == LUA_TTABLE) &&
	   (luabind::type(pointsScale) == LUA_TTABLE) &&
	   (luabind::type(pointsColour) == LUA_TTABLE) &&
	   (luabind::type(pointsAlpha) == LUA_TTABLE))
	{
		linePoints.clear();
		lineScales.clear();
		lineColours.clear();
		lineAlphas.clear();

		for(luabind::iterator it(points), end; it != end; ++it)
			linePoints.push_back(luabind::object_cast<TwoFloats>(*it));
		for(luabind::iterator it(pointsScale), end; it != end; ++it)
			lineScales.push_back(luabind::object_cast<float>(*it));
		for(luabind::iterator it(pointsColour), end; it != end; ++it)
			lineColours.push_back(luabind::object_cast<ThreeFloats>(*it));
		for(luabind::iterator it(pointsAlpha), end; it != end; ++it)
			lineAlphas.push_back(luabind::object_cast<float>(*it));

		drawer->drawConnectedLine(getWideName(image),
								  linePoints,
								  lineScales,
								  lineColours,
								  lineAlphas);
	}
}

//------------------------------------------------------------------------------
void LuaDrawer::fillRect(const TwoFloats& position,
						 const TwoFloats& size,
						 const ThreeFloats& colour,
						 float alpha)
{
	drawer->fillRect(position, size, colour, alpha);
}

//------------------------------------------------------------------------------
void LuaDrawer::fillGradient(const TwoFloats& position,
							 const TwoFloats& size,
							 const ThreeFloats& colourTop,
							 const ThreeFloats& colourBottom,
							 float alphaTop,
							 float alphaBottom)
{
	drawer->fillGradient(position,
						 size,
						 colourTop,
						 colourBottom,
						 alphaTop,
						 alphaBottom);
}

//------------------------------------------------------------------------------
void LuaDrawer::translate(const TwoFloats& offset)
{
	drawer->translate(offset);
}

//------------------------------------------------------------------------------
void LuaDrawer::scale(const TwoFloats& size)
{
	drawer->scale(size);
}

//------------------------------------------------------------------------------
void LuaDrawer::rotate(float angle, const TwoFloats& pivot)
{
	drawer->rotate(angle, pivot);
}

//------------------------------------------------------------------------------
void LuaDrawer::setViewport(const TwoFloats& position, const TwoFloats& size)
{
	drawer->setViewport(position, size);
}

//------------------------------------------------------------------------------
void LuaDrawer::resetViewport()
{
	drawer->resetViewport();
}

//------------------------------------------------------------------------------
void LuaDrawer::startFrameBufferDrawing()
{
	drawer->startFrameBufferDrawing();
}

//------------------------------------------------------------------------------
void LuaDrawer::endFrameBufferDrawing()
{
	drawer->endFrameBufferDrawing();
}

//------------------------------------------------------------------------------
const std::string LuaDrawer::getFrameBufferImage() const
{
	std::string retval;

	UTF8File::wstringToChar(drawer->getFrameBufferImage(), retval);

	return retval;
}

//------------------------------------------------------------------------------
const TwoFloats LuaDrawer::getDrawingAreaSize() const
{
	return drawer->getDrawingAreaSize();
}

//------------------------------------------------------------------------------
const TwoFloats LuaDrawer::getWindowSize() const
{
	return drawer->getWindowSize();
}
