/*
 *  Copyright (C) 2008 Kristian Kristola
 *
 *  This program is distributed under the terms of the
 *  GNU General Public License.
 *
 *  This file is part of Dave the Ordinary Spaceman.
 *
 *  Dave the Ordinary Spaceman is free software: you can redistribute
 *  it and/or modify it under the terms of the GNU General Public
 *  License as published by the Free Software Foundation, either
 *  version 3 of the License, or (at your option) any later version.
 *
 *  Dave the Ordinary Spaceman 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with Dave the Ordinary Spaceman. If not, see
 *  <http://www.gnu.org/licenses/>.
 *
 */

#ifndef __VIHTORIN_EDISTAVA_CAAPPICELLO_TOIMITETTIIN_OIKOPAATA_ROSKIKSEEN__
#define __VIHTORIN_EDISTAVA_CAAPPICELLO_TOIMITETTIIN_OIKOPAATA_ROSKIKSEEN__

#include <math.h>
#include <assert.h>
#include <iostream>

using namespace std;

class Vector
{
public:
  float x;
  float y;
  Vector()
  {
    x = y = 0.0f;
  }
  Vector(float ix, float iy)
  {
    x = ix;
    y = iy;
  }
  Vector operator +(const Vector &p) const
  {
    return Vector(x + p.x, y + p.y);
  }
  Vector operator -(const Vector &p) const
  {
    return Vector(x - p.x, y - p.y);
  }
  Vector operator -() const
  {
    return Vector(-x, -y);
  }
  Vector &operator +=(const Vector &p)
  {
    x += p.x;
    y += p.y;
    return *this;
  }
  Vector &operator -=(const Vector &p)
  {
    x -= p.x;
    y -= p.y;
    return *this;
  }
  Vector operator *(float scalar) const
  {
    return Vector(scalar * x, scalar * y);
  }
  Vector operator /(float scalar) const
  {
    assert(scalar != 0.0f);
    return Vector(x / scalar, y / scalar);
  }
  Vector &operator *=(float scalar)
  {
    x *= scalar;
    y *= scalar;
    return *this;
  }
  friend Vector operator *(float scalar, const Vector &vec)
  {
    return vec * scalar;
  }
  Vector &operator /=(float scalar)
  {
    assert(scalar != 0.0f);
    x /= scalar;
    y /= scalar;
    return *this;
  }
  void normalize()
  {
    *this /= magnitude();
  }
  Vector get_normalized() const
  {
    Vector r(*this);
    r /= magnitude();
    return r;
  }
  bool is_zero() const
  {
    return x == 0 && y == 0;
  }
  float operator *(const Vector &p) const
  {
    return x*p.x + y*p.y;
  }
  Vector multiply(const Vector &p) const
  {
    return Vector(x*p.x, y*p.y);
  }
  float operator ^(const Vector &p) const // Laskee kahden paikkavektorin määräämän janan kulman
  {
    const Vector d = p - *this;
    const float a = atan2(d.y, d.x);
    return a >= 0 ? a : 2.0f*3.14159f + a;
  }
  float magnitude() const
  {
    //cerr << x << " " << y << endl;
    return sqrt(x*x + y*y);
  }
  friend std::ostream &operator <<(std::ostream &s, const Vector &v)
  {
    return s << "(" << v.x << ", " << v.y << ")";
  }
  bool operator ==(const Vector &v) const
  {
    return x == v.x && y == v.y;
  }
  bool operator !=(const Vector &v) const
  {
    return !(*this == v);
  }
};

class Vector3D : public Vector
{
public:
  float z;
  Vector3D() : z(0.0f) {}
  Vector3D(float _x, float _y, float _z) : Vector(_x, _y), z(_z) {}
  Vector3D &operator +=(const Vector3D &p)
  {
    x += p.x;
    y += p.y;
    z += p.z;
    return *this;
  }
  Vector3D operator *(float a) const
  {
    return Vector3D(a * x, a * y, a * z);
  }
  friend Vector3D operator *(float a, const Vector3D &b)
  {
    return Vector3D(a * b.x, a * b.y, a * b.z);
  }
  Vector3D operator +(const Vector3D &p) const
  {
    return Vector3D(x + p.x, y + p.y, z + p.z);
  }
};

#endif
