#ifndef VECTOR_HPP
#define VECTOR_HPP

//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------
#include <Extern/GLMConfig.hpp>
#include <iostream>

namespace Math
{
  using glm::vec4;
  using glm::vec2;
  using glm::uvec4;
  using glm::uvec2;
  using glm::bvec3;
  using glm::bvec4;
  using glm::bvec2;  
  using glm::uvec3;
  using glm::ivec4;
  using glm::ivec3;
  using glm::ivec2;
  using glm::mat4;
  using glm::mat3;
  using glm::comp;
  //using glm::vec3;
  
  class vec3 {
  public:
    float swizzle(comp X) const {
      glm::vec3 v=*this;
      return v.swizzle(X);
    }
    vec2 const swizzle(comp X, comp Y) const { 
      glm::vec3 v=*this;
      return v.swizzle(X,Y);
    }
    vec3 const swizzle(comp X, comp Y, comp Z) const {
      glm::vec3 v=*this;
      return vec3(v.swizzle(X,Y,Z));
    }
    vec4 const swizzle(comp X, comp Y, comp Z, comp W) const {
      glm::vec3 v=*this;
      return v.swizzle(X,Y,Z,W);
    }
    
  };
  

  inline mat4 lookAt(const vec3& v1, const vec3& v2, const vec3& v3){
    glm::vec3 vv1=v1;
    glm::vec3 vv2=v2;
    glm::vec3 vv3=v3;
    return glm::lookAt(vv1,vv2,vv3);
  }
    
  inline double length(const vec3& v1) { 
    glm::vec3 v=v1;
    return glm::length(v);
  }

  inline float dot(const vec3& v1, const vec3& v2) {
    glm::vec3 vv1=v1;
    glm::vec3 vv2=v2;
    return glm::dot(vv1,vv2);
  }

  inline vec3 cross(const vec3& v1, const vec3& v2){
    glm::vec3 vv1=v1;
    glm::vec3 vv2=v2;
    return vec3(glm::cross(vv1,vv2));
   
  }
  inline bool isNull(const vec3& v) {
    glm::vec3 vv1=v;
    return glm::isNull(vv1);
   
  }

  using glm::normalize;
  inline vec3 normalize(const vec3& v) {
    glm::vec3 vv=v;
    return vec3(glm::normalize(vv));
  }
    

  ////////////////////

  // Generic vector output
	template<class T, int nComponents>
	std::string VectorToString(const T& _value);

	// Float vector output
	inline std::string ToString(const vec2& _value);
	inline std::string ToString(const vec3& _value);
	inline std::string ToString(const vec4& _value);

	// Integer vector output
	inline std::string ToString(const ivec2& _value);
	inline std::string ToString(const ivec3& _value);
	inline std::string ToString(const ivec4& _value);

	// Unsigned integer vector output
	inline std::string ToString(const uvec2& _value);
	inline std::string ToString(const uvec3& _value);
	inline std::string ToString(const uvec4& _value);

	// Boolean vector output
	inline std::string ToString(const bvec2& _value);
	inline std::string ToString(const bvec3& _value);
	inline std::string ToString(const bvec4& _value);

	// Scalar output
	template<class T>
	inline std::string ToString(const T& _value);
}

//-----------------------------------------------------------------
// Include inline definitions
//-----------------------------------------------------------------
#include <Math/Vector.inl>


#endif /*VECTOR_HPP*/
