
#if !defined( INCLUDED_VECTOR_H )
#define INCLUDED_VECTOR_H

#include <cstddef>

template <typename Element>
class BasicVector2
{
Element m_elements[2];
public:
BasicVector2(){
}
BasicVector2( const Element& x_, const Element& y_ ){
	x() = x_;
	y() = y_;
}

Element& x(){
	return m_elements[0];
}
const Element& x() const {
	return m_elements[0];
}
Element& y(){
	return m_elements[1];
}
const Element& y() const {
	return m_elements[1];
}

const Element& operator[]( std::size_t i ) const {
	return m_elements[i];
}
Element& operator[]( std::size_t i ){
	return m_elements[i];
}

Element* data(){
	return m_elements;
}
const Element* data() const {
	return m_elements;
}
};

/// \brief A 3-element vector.
template<typename Element>
class BasicVector3
{
Element m_elements[3];
public:

BasicVector3(){
}
template<typename OtherElement>
BasicVector3( const BasicVector3<OtherElement>& other ){
	x() = static_cast<Element>( other.x() );
	y() = static_cast<Element>( other.y() );
	z() = static_cast<Element>( other.z() );
}
BasicVector3( const Element& x_, const Element& y_, const Element& z_ ){
	x() = x_;
	y() = y_;
	z() = z_;
}

Element& x(){
	return m_elements[0];
}
const Element& x() const {
	return m_elements[0];
}
Element& y(){
	return m_elements[1];
}
const Element& y() const {
	return m_elements[1];
}
Element& z(){
	return m_elements[2];
}
const Element& z() const {
	return m_elements[2];
}

const Element& operator[]( std::size_t i ) const {
	return m_elements[i];
}
Element& operator[]( std::size_t i ){
	return m_elements[i];
}

Element* data(){
	return m_elements;
}
const Element* data() const {
	return m_elements;
}
};

/// \brief A 4-element vector.
template<typename Element>
class BasicVector4
{
Element m_elements[4];
public:

BasicVector4(){
}
BasicVector4( Element x_, Element y_, Element z_, Element w_ ){
	x() = x_;
	y() = y_;
	z() = z_;
	w() = w_;
}
BasicVector4( const BasicVector3<Element>& self, Element w_ ){
	x() = self.x();
	y() = self.y();
	z() = self.z();
	w() = w_;
}

Element& x(){
	return m_elements[0];
}
const Element& x() const {
	return m_elements[0];
}
Element& y(){
	return m_elements[1];
}
const Element& y() const {
	return m_elements[1];
}
Element& z(){
	return m_elements[2];
}
const Element& z() const {
	return m_elements[2];
}
Element& w(){
	return m_elements[3];
}
const Element& w() const {
	return m_elements[3];
}

Element index( std::size_t i ) const {
	return m_elements[i];
}
Element& index( std::size_t i ){
	return m_elements[i];
}
Element operator[]( std::size_t i ) const {
	return m_elements[i];
}
Element& operator[]( std::size_t i ){
	return m_elements[i];
}

Element* data(){
	return m_elements;
}
const Element* data() const {
	return m_elements;
}
};

template<typename Element>
inline BasicVector3<Element> vector3_from_array( const Element* array ){
	return BasicVector3<Element>( array[0], array[1], array[2] );
}

template<typename Element>
inline Element* vector3_to_array( BasicVector3<Element>& self ){
	return self.data();
}
template<typename Element>
inline const Element* vector3_to_array( const BasicVector3<Element>& self ){
	return self.data();
}

template<typename Element>
inline Element* vector4_to_array( BasicVector4<Element>& self ){
	return self.data();
}
template<typename Element>
inline const Element* vector4_to_array( const BasicVector4<Element>& self ){
	return self.data();
}

template<typename Element>
inline BasicVector3<Element>& vector4_to_vector3( BasicVector4<Element>& self ){
	return *reinterpret_cast<BasicVector3<Element>*>( vector4_to_array( self ) );
}
template<typename Element>
inline const BasicVector3<Element>& vector4_to_vector3( const BasicVector4<Element>& self ){
	return *reinterpret_cast<const BasicVector3<Element>*>( vector4_to_array( self ) );
}

/// \brief A 2-element vector stored in single-precision floating-point.
typedef BasicVector2<float> Vector2;

/// \brief A 3-element vector stored in single-precision floating-point.
typedef BasicVector3<float> Vector3;

/// \brief A 4-element vector stored in single-precision floating-point.
typedef BasicVector4<float> Vector4;


#endif
