/*
 *  Copyright (C) 2005  Andreas Volz
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *  
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *  
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *  
 *  File: Vector2.h
 *  Andreas Volz <linux@brachttal.net>
 *   
 */

#ifndef VECTOR2_H
#define VECTOR2_H 1

#ifdef HAVE_CONFIG_H
  #include <config.h>
#endif

#include <cmath>
#include <string>
#include <sstream>
#include <iomanip>

namespace Animorph {

template <typename T>
class Vector2
{
private:

public:
  T x, y;

  Vector2 () {}

  /// copy constructor
  Vector2 (const Vector2<T> &v) : x (v.x), y (v.y) {}

  /// construct given two values
  /*!
   * \param _x the x component to the Vector3
   * \param _y the y component to the Vector3
   */
  Vector2 (const T& _x, const T& _y) : x (_x), y (_y) {}

  virtual ~Vector2() {}

  /// set all components to zero
  void zero () {x = y = 0.0;}

  /// normalize it
  void normalize ();

  /// return the magnitude
  virtual T getMagnitude () const = 0;

  /// copy values
  Vector2<T>& operator = (const Vector2<T>& v1);

  /*! \return inverted vector */
  Vector2<T> operator - ();

  /// vector_2 += vector_1
  Vector2<T>& operator += (const Vector2<T>& v1);

  /// vector_2 -= vector_1
  Vector2<T>& operator -= (const Vector2<T>& v1);

  /// vector_1 *= scalar
  Vector2<T>& operator *= (const T scalar);
  
  /// vector_1 /= scalar
  Vector2<T>& operator /= (const T scalar);
};

/*****************************/
/* Member Template functions */
/*****************************/

template <typename T>
void Vector2<T>::normalize ()
{
  T magnitude = getMagnitude ();

  if (magnitude > 0.0)
  {
    T one_mag = 1.0 / magnitude;
    *this *= one_mag;
  }
}

/********************/
/* Member-Operators */
/********************/

template <typename T>
Vector2<T>& Vector2<T>::operator = (const Vector2<T>& v1)
{
  x = v1.x;
  y = v1.y;

  return *this;
}

template <typename T>
Vector2<T> Vector2<T>::operator - ()
{
  Vector2<T> v;
  v.x = -x;
  v.y = -y;

  return v;
}

template <typename T>
inline Vector2<T>& Vector2<T>::operator += (const Vector2<T>& v1)
{
  x += v1.x;
  y += v1.y;

  return *this;
}

template <typename T>
inline Vector2<T>& Vector2<T>::operator -= (const Vector2<T>& v1)
{
  x -= v1.x;
  y -= v1.y;

  return *this;
}

template <typename T>
inline Vector2<T>& Vector2<T>::operator *= (const T scalar)
{
  x *= scalar;
  y *= scalar;

  return *this;
}

template <typename T>
inline Vector2<T>& Vector2<T>::operator /= (const T scalar)
{
  x /= scalar;
  y /= scalar;

  return *this;
}

/**************************************/
/* Non-Member operators and functions */
/**************************************/

/// test two Vector3 if they have the same values
template <typename T>
inline bool operator == (const Vector2<T>& v1, const Vector2<T>& v2)
{
  if ((v1.x == v2.x) &&
      (v1.y == v2.y))
  {
    return true;
  }
  
  return false;  
}

/// vector_2 = vector_1 * scalar
template <typename T>
inline Vector2<T> operator * (const Vector2<T>& v1, const float scalar)
{
  Vector2<T> v3 = v1;

  return v3 *= scalar;
}

/// vector_2 = vector_1 / scalar
template <typename T>
inline Vector2<T> operator / (const Vector2<T>& v1, const float scalar)
{
  Vector2<T> v3 = v1;

  return v3 /= scalar;
}

/// vector_3 = vector_1 - vector_2
template <typename T>
inline Vector2<T> operator - (const Vector2<T>& v1, const Vector2<T>& v2)
{
  Vector2<T> v3 = v1;

  return v3 -= v2;
}

/// vector_3 = vector_1 + vector_2
template <typename T>
inline Vector2<T> operator + (const Vector2<T>& v1, const Vector2<T>& v2)
{
  Vector2<T> v3 = v1;

  return v3 += v2;
}

/// calculate the distance between two Vector2
template <typename T>
inline T vectorDistance (const Vector2<T> &v1, const Vector2<T> &v2)
{
  Vector2<T> dist = v1 - v2;

  return dist.getMagnitude ();
}

/// << operator for output
template <typename T>
std::ostream &operator << (std::ostream &s, const Vector2<T> &v)
{
  s << "[";
  s << "x: " << v.x << " y: " << v.y;
  s << "]";

  return s;
}


/* ========================================================================== */
/**
 */
/* ========================================================================== */
class Vector2f : public Vector2<float>
{
public:
  Vector2f ()                   : Vector2<float>() {}
  Vector2f (float _x, float _y) : Vector2<float>(_x, _y) {}

  virtual ~Vector2f() {}

  virtual float getMagnitude () const
  {
    // usage of sqrtf is faster than sqrt for float!
    return ::sqrtf (x * x + y * y);
  }


}; // class Vector2f : public Vector2<float>

/* ========================================================================== */
/**
 */
/* ========================================================================== */
class Vector2d : public Vector2<double>
{
public:
  Vector2d ()                                   : Vector2<double>() {}
  Vector2d (const double& _x, const double& _y) : Vector2<double>(_x, _y) {}

  virtual ~Vector2d() {}

  virtual double getMagnitude () const
  {
    return ::sqrt (x * x + y * y);
  }


}; // class Vector2d : public Vector2<double>

} // end namespace Animorph

#endif	// VECTOR2_H
