// Implementation file for the Point class
// Created by:		Michael Edwards
// Date Started:	1/10/04
// Date Finished:
// Compiler Used:	Microsoft Visual C++, Version 6.0 Enterprise Edition

#ifndef POINT_CPP
#define POINT_CPP

#include "Point.h"

namespace MCL
{
	template <class NumberType>
	Point<NumberType>::Point(unsigned userDimension): dimension(userDimension)
	// Creates a Point of size userDimension and initialized to 0
	// PRECONDITION:  none.
	// POSTCONDITION: creates a point at the origin of size userDimension
	{
		coordinate = new NumberType[userDimension];
		memset(coordinate, 0, sizeof(NumberType) * userDimension);
	}

	template <class NumberType>
	Point<NumberType>::Point(unsigned userDimension, NumberType* data): dimension(userDimension)
	// Creates a Point of size userDimension and initialized to data
	// PRECONDITION:  size of data >= userDimension
	// POSTCONDITION: creates a point of size userDimension and 
	//				  initialized with data
	{
		coordinate = new NumberType[userDimension];
		memcpy(coordinate, data, sizeof(NumberType) * dimension);
	}

	template <class NumberType>
	Point<NumberType>::Point(const Point& rhs): dimension(rhs.dimension)
	// copy constructor
	{
		coordinate = new NumberType[dimension];
		memcpy(coordinate, rhs.coordinate, sizeof(NumberType) * dimension);
	}

	template <class NumberType>
	Point<NumberType>::~Point()
	// default destructor
	{
		delete [] coordinate;
	}

	template <class NumberType>
	Point<NumberType> Point<NumberType>::operator+(const Point& rhs) const
	// the point is offsetted by rhs
	// PRECONDITION:  this->dimension == rhs.dimension
	// POSTCONDITION: this + rhs is returned
	{
		assert(dimension == rhs.dimension);
		Point temp(rhs.dimension);
		for (unsigned i = 0; i < dimension; ++i)
			temp.coordinate[i] = coordinate[i] + rhs.coordinate[i];
		return temp;
	}

	template <class NumberType>
	Point<NumberType> Point<NumberType>::operator-(const Point& rhs) const
	// the point is negatively offsetted by rhs
	// PRECONDITION:  this->dimension == rhs.dimension
	// POSTCONDITION: this - rhs is returned
	{
		assert(dimension == rhs.dimension);
		Point temp(rhs.dimension);
		for (unsigned i = 0; i < dimension; ++i)
			temp.coordinate[i] = coordinate[i] - rhs.coordinate[i];
		return temp;
	}

	template <class NumberType>
	Point<NumberType> Point<NumberType>::operator*(NumberType rhs) const
	// the point is scalar multiplied with rhs
	// PRECONDITION:  none.
	// POSTCONDITION: this * rhs is returned
	{
		Point<NumberType> temp(dimension);
		for (unsigned i = 0; i < dimension; ++i)
			temp.coordinate[i] = coordinate[i] * rhs;
		return temp;
	}

	template <class NumberType>
	Point<NumberType> operator * (NumberType lhs, const Point<NumberType>& rhs)
	// the point, rhs, is scalar multiplied with lhs
	// PRECONDITION:  none.
	// POSTCONDITION: lhs * rhs is returned
	{
		Point<NumberType> temp(rhs.dimension);
		for (unsigned i = 0; i < rhs.dimension; ++i)
			temp.coordinate[i] = lhs * rhs.coordinate[i];
		return temp;
	}

	template <class NumberType>
	Point<NumberType> Point<NumberType>::operator/(NumberType rhs) const
	// the point is scalar divided with rhs
	// PRECONDITION:  rhs != 0.
	// POSTCONDITION: this / rhs is retured.
	{
		assert(rhs != 0);
		Point<NumberType> temp(dimension);
		for (unsigned i = 0; i < dimension; ++i)
			temp.coordinate[i] = coordinate[i] / rhs;
		return temp;
	}

	template <class NumberType>
	Point<NumberType>& Point<NumberType>::operator=(const Point& rhs)
	// assignment operator.
	// PRECONDITION:  none.
	// POSTCONDITION: this = rhs
	{
		if (dimension != rhs.dimension)
		// self-reference is covered because if this is rhs then the dimensions are
		// equal.
		{
			delete [] coordinate;
			coordinate = new NumberType[rhs.dimension];
			dimension = rhs.dimension;
		}
		memcpy(coordinate, rhs.coordinate, sizeof(NumberType) * dimension);
		return *this;
	}

	template <class NumberType>
	Point<NumberType>& Point<NumberType>::operator+=(const Point& rhs)
	// adds rhs to this
	// PRECONDITION:  this->dimension == rhs.dimension
	// POSTCONDITION:
	{
		assert(dimension == rhs.dimension);
		for (unsigned i = 0; i < dimension; ++i)
			coordinate[i] += rhs.coordinate[i];
		return *this;
	}

	template <class NumberType>
	Point<NumberType>& Point<NumberType>::operator-=(const Point& rhs)
	// substracts rhs to this
	// PRECONDITION:  this->dimension == rhs.dimension
	// POSTCONDITION:
	{
		assert(dimension == rhs.dimension);
		for (unsigned i = 0; i < dimension; ++i)
			coordinate[i] -= rhs.coordinate[i];
		return *this;
	}

	template <class NumberType>
	Point<NumberType>& Point<NumberType>::operator*=(NumberType rhs)
	// multiplies this by rhs
	// PRECONDITION:  none.
	// POSTCONDITION:
	{
		for (unsigned i = 0; i < dimension; ++i)
			coordinate[i] *= rhs;
		return *this;
	}

	template <class NumberType>
	Point<NumberType>& Point<NumberType>::operator/=(NumberType rhs)
	// divides this by rhs
	// PRECONDITION:  rhs != 0.
	// POSTCONDITION:
	{
		assert(rhs != 0);
		for (unsigned i = 0; i < dimension; ++i)
			coordinate[i] /= rhs;
		return *this;
	}

	template <class NumberType>
	bool Point<NumberType>::operator==(const Point& rhs) const
	// checks to see if the points are equal.
	// PRECONDITION:  none.
	// POSTCONDITION: checks to see if this == rhs
	{
		return (memcmp(coordinate, rhs.coordinate, 
			sizeof(NumberType) * (dimension < rhs.dimension) ? dimension: rhs.dimension) == 0);
	}

	template <class NumberType>
	bool Point<NumberType>::operator!=(const Point& rhs) const
	// checks to see if he points are not equal
	// PRECONDITION:  none.
	// POSTCONDITION: checks to see if this != rhs
	{
		return (memcmp(coordinate, rhs.coordinate, 
			sizeof(NumberType) * (dimension < rhs.dimension) ? dimension: rhs.dimension) != 0);
	}

	template <class NumberType>
	NumberType Point<NumberType>::operator[](unsigned k) const
	// grabs member pk from the coordinate set
	// PRECONDITION:  k < dimension
	// POSTCONDITION: pk is returned.
	{
		assert(k < dimension);
		return coordinate[k];
	}

	template <class NumberType>
	NumberType& Point<NumberType>::operator[](unsigned k)
	// grabs member pk from the coordinate set
	// PRECONDITION:  k < dimension
	// POSTCONDITION: pk is returned.
	{
		assert(k < dimension);
		return coordinate[k];

	}

	template <class NumberType>
	NumberType Point<NumberType>::FindDistance(const Point<NumberType>& rhs) const
	// Finds the distance between this and rhs.
	// PRECONDITION:  this->dimension == rhs.dimension
	// POSTCONDITION: distance between the points is returned
	{
		assert(dimension == rhs.dimension);
		NumberType total = 0;
		for (unsigned i = 0; i < dimension; ++i)
			total += (coordinate[i] - rhs.coordinate[i]) * (coordinate[i] - rhs.coordinate[i]);
		return sqrt(double(total));
	}
}

#endif