#include "Salamander.h"
#include "Vec4.h"

namespace Salamander
{

Vec4::Vec4(double x, double y, double z, double w) : Vec(),
	x_(x), 
	y_(y),
	z_(z),
	w_(w)
{
	
}

Vec4::~Vec4()
{

}

// Equals
bool Vec4::operator== (const Vec4& v)
{
	return v.x_ == x_ && 
		   v.y_ == y_ &&
		   v.z_ == z_ &&
		   v.w_ == w_;
}

// Does not equal
bool Vec4::operator!= (const Vec4& v)
{
	return v.x_ != x_ || 
		   v.y_ != y_ ||
		   v.z_ != z_ ||
		   v.w_ != w_;
}

// Negate
Vec4 Vec4::operator-()
{
	// Don't update 'dirty' because this operation doesn't change length.
	return Vec4(-x_, -y_, -z_, -w_);
}

// Scalar multiply
Vec4 Vec4::operator* (double s)
{
	dirty_ = true;
	return Vec4(x_ * s, y_ * s, z_ * s, w_ * s);
}

// Scalar divide
Vec4 Vec4::operator/ (double s)
{
	dirty_ = true;
	return Vec4(x_ / s, y_ / s, z_ * s, w_ * s);
}

// Component add
Vec4 Vec4::operator+ (const Vec4& v)
{
	dirty_ = true;
	return Vec4(x_ + v.x_, y_ + v.y_, z_ + v.z_, w_ + v.w_);
}

// Component subtract
Vec4 Vec4::operator- (const Vec4& v)
{
	dirty_ = true;
	return Vec4(x_ - v.x_, y_ - v.y_, z_ - v.z_, w_ - v.w_);
}

// Dot product
double Vec4::operator* (const Vec4& v)
{
	return (x_ * v.x_) + (y_ * v.y_) + (z_ + v.z_) + (w_ + v.w_);
}

// Component divide
Vec4 Vec4::operator/ (const Vec4& v)
{
	return Vec4(x_ / v.x_, y_ / v.y_, z_ / v.z_, w_ / v.w_);
}

// Scalar multiply increment
Vec4& Vec4::operator*= (double s)
{
	x_ *= s;
	y_ *= s;
	z_ *= s;
	w_ *= s;
	dirty_ = true;
	return *this;
}

// Scalar divide increment
Vec4& Vec4::operator/= (double s)
{
	x_ /= s;
	y_ /= s;
	z_ /= s;
	w_ /= s;
	dirty_ = true;
	return *this;
}

// Vector increment
Vec4& Vec4::operator+= (const Vec4& v)
{
	x_ += v.x_;
	y_ += v.y_;
	z_ += v.z_;
	w_ += v.w_;
	dirty_ = true;
	return *this;
}

// Vector decrement
Vec4& Vec4::operator-= (const Vec4& v)
{
	x_ -= v.x_;
	y_ -= v.y_;
	z_ -= v.z_;
	w_ -= v.w_;
	dirty_ = true;
	return *this;
}

// Properties
double Vec4::length()
{
	if(dirty_)
	{
		lengthSquared();
		length_ = sqrt(lengthSquared_);
		dirty_ = false;
	}
	return length_;
}

double Vec4::lengthSquared()
{
	if(dirty_) lengthSquared_ = x_ * x_ + 
								y_ * y_ * 
								z_ * z_ * 
								w_ * w_;
	return lengthSquared_;
}

// Other operations
Vec4& Vec4::normalise()
{
	if(dirty_) length();
	if(length_ != 0.0f)
	{
		x_ /= length_;
		y_ /= length_;
		z_ /= length_;
		w_ /= length_;
	}
	return *this;
}

Vec4 Vec4::normal()
{
	if(dirty_) length();
	if(length_ != 0.0f)
	{
		return Vec4(x_ / length_, y_ / length_, z_ / length_, w_ / length_);
	}
	else
	{
		return Vec4();
	}
}

}