#include "pw/core/vector.hpp"
#include "pw/core/quaternion.hpp"
#include "pw/core/axisangle.hpp"
#include "pw/core/debug.hpp"
#include "pw/core/size.hpp"
#include "pw/core/point.hpp"
#include "pw/core/time.hpp"
#include "pw/core/mesh.hpp"
#include "pw/core/image.hpp"

#include "runtime_lua.hpp"


// seems CRTP magic doesnt work with SOL
namespace sol {
    template <> struct is_automagical<pw::matrix4x4> : std::false_type {};
    template <> struct is_automagical<pw::vector3> : std::false_type {};
    template <> struct is_automagical<pw::quaternion> : std::false_type {};
}

namespace pw {

void register_core_function(sol::state& lua,sol::table& ns)
{

	typedef real_t Scalar;

	ns.set("pi",pw::pi<Scalar>());


	ns.new_usertype<matrix4x4>("matrix4x4"
							   , sol::constructors<matrix4x4()>()
							   , "row",&matrix4x4::row
							   , "column",&matrix4x4::column
							   , "set_identity",&matrix4x4::set_identity
							   , "inverse",&matrix4x4::inverse
							   );

	ns.new_usertype<vector3>("vector3"
							 ,sol::constructors<vector3(),vector3(Scalar,Scalar,Scalar)>()
							 ,"x", sol::property(sol::resolve<const vector3::value_type&() const>(&vector3::x), [](vector3& v,vector3::value_type val){ v.x() = val;})
							 ,"y", sol::property(sol::resolve<const vector3::value_type&() const>(&vector3::y), [](vector3& v,vector3::value_type val){ v.y() = val;})
							 ,"z", sol::property(sol::resolve<const vector3::value_type&() const>(&vector3::z), [](vector3& v,vector3::value_type val){ v.z() = val;})
							 ,"cross",&vector3::cross
							 ,"transposed",&vector3::transposed
							 ,"lerp",&vector3::lerp
							 );

    ns.new_usertype<quaternion>("quaternion"
                                , sol::constructors<quaternion(), quaternion(quaternion::value_type,quaternion::value_type,quaternion::value_type,quaternion::value_type)>()
                                ,"x", sol::property(sol::resolve<const quaternion::value_type&() const>(&quaternion::x), [](quaternion& v,quaternion::value_type val){ v.x() = val;})
                                ,"y", sol::property(sol::resolve<const quaternion::value_type&() const>(&quaternion::y), [](quaternion& v,quaternion::value_type val){ v.y() = val;})
                                ,"z", sol::property(sol::resolve<const quaternion::value_type&() const>(&quaternion::z), [](quaternion& v,quaternion::value_type val){ v.z() = val;})
                                ,"w", sol::property(sol::resolve<const quaternion::value_type&() const>(&quaternion::w), [](quaternion& v,quaternion::value_type val){ v.w() = val;})
                                ,"identity",sol::readonly_property(&quaternion::identity)
                                ,"dot",&quaternion::dot
								,"inverse",sol::readonly_property(&quaternion::inverse)
								,"normalized",&quaternion::normalized
								,"lerp",&quaternion::lerp
								,"slerp",&quaternion::slerp
								);

	ns.new_usertype<axisangle>
			("axisangle",
			 sol::constructors<axisangle(), axisangle(vector3,Scalar)>(),
			 "axis",&axisangle::axis,
			 "angle",&axisangle::angle,
			 "from_matrix",&axisangle::from_matrix,
			 "to_matrix",&axisangle::to_matrix
			 );


	ns.new_usertype<size>("size"
						  , sol::constructors<size(),size(Scalar,Scalar)>()
						  , "width",&size::width
						  , "height",&size::height
						  );

    ns.new_usertype<sizei>("sizei"
                          , sol::constructors<sizei(),sizei(int,int)>()
                          , "width",&sizei::width
                          , "height",&sizei::height
                          );

	ns.new_usertype<point>("point",
						   sol::constructors<point(),point(Scalar,Scalar)>(),
						   "x",&point::x,
						   "y",&point::y
						   );


	ns.new_usertype<debug>("debug",
						   "new",sol::no_constructor,
						   "get",&debug::get,
						   "write",&debug::write
						   //						   "none",sol::debug::level::none
						   );


	ns.new_usertype<time>("time",
						  "now",sol::readonly_property(&time::now),
						  "elapsed",sol::readonly_property(&time::elapsed),
						  "reset",&time::reset
						  );

    auto geoom_type = ns.new_usertype<geometry>("geometry"
                                           , sol::constructors<geometry()>()
                                           , "topology", sol::property(&geometry::topology,&geometry::set_topology)
                                           , "vertices", sol::property(&geometry::vertices,&geometry::set_vertices)
                                           , "indices", sol::property(&geometry::indices,&geometry::set_indices)
                                           );
    geoom_type.new_enum("topology"
                       , "points", geometry::topology_type::points
                       , "lines", geometry::topology_type::lines
                       , "line_strip", geometry::topology_type::line_strip
                       );

    ns.new_usertype<image>("image"
                           ,"create",&image::create
                           ,"size",sol::readonly_property(&image::size)
                           ,"change_count",sol::property(&image::change_count,&image::set_change_count)

                           ).new_enum("layout"
                                      ,"rgb8", image::RGB8
                                      ,"rgb32", image::RGBA8
                                      ,"gray", image::LUM);


}


PW_REGISTER_LUA(core)

}
