#ifndef PW_SCENE_TRANSFORM_HPP
#define PW_SCENE_TRANSFORM_HPP

#include <pw/core/matrix.hpp>
#include <pw/core/quaternion.hpp>
#include <pw/core/vector.hpp>

namespace pw {

class node;

class transform {
public:

	transform(node &host);

	inline const matrix4x4& local() const { return _local; }
	void set_local(const matrix4x4 &local);

	inline const matrix4x4& global() const { return _global; }
	void set_global(const matrix4x4 &global);

	inline const matrix4x4& global_inverse() const { return _global_inverse; }

	inline transform& translate(const real_t &x, const real_t &y, const real_t &z) {
        _local(0,3) += x;_local(1,3) += y;_local(2,3) += z;
		update_global_from_local();
		return *this;
	}

	inline transform& set_translation(const real_t &x, const real_t &y, const real_t &z) {
		_local(0,3) = x;_local(1,3) = y;_local(2,3) = z;
		update_global_from_local();
		return *this;
	}

	inline transform& rotate(const quaternion& q) {
        _local = _local * q.to_matrix();
		update_global_from_local();
		return *this;
	}

	inline transform& set_rotation(const quaternion& q) {
		_local = q.to_matrix();
		update_global_from_local();
		return *this;
	}

	inline transform& scale(const real_t &sx, const real_t &sy, const real_t &sz) {
		_local(0,0) *= sx; _local(1,1) *= sy; _local(2,2) *= sz;
		update_global_from_local();
		return *this;
	}

	inline transform& set_scale(const real_t &sx, const real_t &sy, const real_t &sz) {
		_local(0,0) = sx; _local(1,1) = sy; _local(2,2) = sz;
		update_global_from_local();
		return *this;
	}

	inline transform& scale(const real_t& uniform_scale) {
		return scale(uniform_scale,uniform_scale,uniform_scale);
	}

protected:

	matrix4x4 _local;
	matrix4x4 _global;

	matrix4x4 _global_inverse;

private:

	node &_node;

	//! updates the global transform from parent globals and local transform
	void update_global_from_local();

	//! updates the local transform from parent and new global
	void update_local_from_global();
};

}

#endif
