/////////////////////////////////////////////////////////////
//                                                         //
// Copyright (c) 2007-2017 by The University of Queensland //
// Centre for Geoscience Computing                         //
// http://earth.uq.edu.au/centre-geoscience-computing      //
//                                                         //
// Primary Business: Brisbane, Queensland, Australia       //
// Licensed under the Open Software License version 3.0    //
// http://www.apache.org/licenses/LICENSE-2.0              //
//                                                         //
/////////////////////////////////////////////////////////////

#ifndef __VECTOR3_H
#define __VECTOR3_H

#define DO_INLINE_VECTOR3 1

#if DO_INLINE_VECTOR3 >= 1
#define VECTOR3_INLINE inline
#else
#define VECTOR3_INLINE
#endif

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

//#include "Foundation/Error.h"

using std::ostream;
using std::istream;
using std::string;

//class Matrix3;

/*
class VecErr:public MError
{
 public:
  VecErr(const string&);
  virtual ~VecErr(){};
};
*/

struct VDMulVadd;
struct VDMul;

class Vector3
{
protected:
  double data[3];

public:
  static const Vector3 ZERO; //! The zero vector.
  // constructors
  VECTOR3_INLINE Vector3();
  VECTOR3_INLINE explicit Vector3(double s);
  VECTOR3_INLINE Vector3(double,double,double);
  VECTOR3_INLINE Vector3(const Vector3&);

  // vec-vec operators
  VECTOR3_INLINE Vector3& operator=(const Vector3&);
  VECTOR3_INLINE Vector3& operator=(double s);
  VECTOR3_INLINE Vector3& operator-=(const Vector3&);
  VECTOR3_INLINE Vector3& operator+=(const Vector3&);
  VECTOR3_INLINE Vector3 operator+(const Vector3&) const;
  VECTOR3_INLINE Vector3 operator-(const Vector3&) const;
//wangyc added !
//  VECTOR3_INLINE Vector3 operator*(const Matrix3 &m) const;
  VECTOR3_INLINE double operator*(const Vector3&) const; 
  VECTOR3_INLINE Vector3 operator-() const;
  
  // vec-dbl ops
  VECTOR3_INLINE Vector3 operator*(double) const;
  VECTOR3_INLINE Vector3& operator*=(double);
  VECTOR3_INLINE Vector3 operator/(double) const;
  VECTOR3_INLINE Vector3 operator-(double) const;
  VECTOR3_INLINE Vector3 operator+(double) const;
  VECTOR3_INLINE Vector3& operator+=(double);
  VECTOR3_INLINE Vector3& operator-=(double);

// wangyc added !
  VECTOR3_INLINE Vector3& operator/=(double);
  VECTOR3_INLINE double norm() const;
  VECTOR3_INLINE double wnorm(double,double,double) const;
  VECTOR3_INLINE double norm2() const;
  VECTOR3_INLINE double wnorm2(double,double,double) const;
  VECTOR3_INLINE Vector3 unit() const;
//  VECTOR3_INLINE Vector3 unit_s() const; //safe version (throw exceptions)
  VECTOR3_INLINE double max() const;
  VECTOR3_INLINE double min() const;

  VECTOR3_INLINE Vector3 rotate(const Vector3 &axis, const Vector3 &axisPt) const;

  VECTOR3_INLINE bool operator==(const Vector3&) const;
  VECTOR3_INLINE bool operator!=(const Vector3&) const;

  VECTOR3_INLINE friend Vector3 cmax(const Vector3&,const Vector3&);
  VECTOR3_INLINE friend Vector3 cmin(const Vector3&,const Vector3&);

  VECTOR3_INLINE friend Vector3 cross(const Vector3&,const Vector3&);
  VECTOR3_INLINE friend double dot(const Vector3&,const Vector3&); 
  VECTOR3_INLINE friend Vector3 operator*(double,const Vector3&);

  //n+1-ary operators
  VECTOR3_INLINE void mul_add_and_assign(const Vector3*,const Vector3*,const double&);
  VECTOR3_INLINE void mul_and_assign(const Vector3*,const double&);

  VECTOR3_INLINE Vector3(const VDMulVadd&);
  VECTOR3_INLINE Vector3& operator=(const VDMulVadd&);

  VECTOR3_INLINE Vector3(const VDMul&);
  VECTOR3_INLINE Vector3& operator=(const VDMul&);

  //access stuff
  VECTOR3_INLINE void set_x(double x) {data[0] = x;}
  VECTOR3_INLINE void set_y(double y) {data[1] = y;}
  VECTOR3_INLINE void set_z(double z) {data[2] = z;}
//  void set_xyz(double x, double y, double z)
//  { data[0] = x; data[1] = y; data[2] = z;}
  
  VECTOR3_INLINE double& X() {return data[0];};
  VECTOR3_INLINE double& Y() {return data[1];};
  VECTOR3_INLINE double& Z() {return data[2];};
  VECTOR3_INLINE double x() const {return data[0];};
  VECTOR3_INLINE double y() const {return data[1];};
  VECTOR3_INLINE double z() const {return data[2];};
  VECTOR3_INLINE const double &operator[](int i) const {return data[i];}
  VECTOR3_INLINE double& operator[](int i) {return data[i];}

  // in/output
  VECTOR3_INLINE friend ostream& operator << (ostream&,const Vector3&);
  VECTOR3_INLINE friend istream& operator >> (istream&,Vector3&);

  // comparison -> enable to use of Vector3 as key in STL map and set
  bool operator<(const Vector3&) const; 

//  friend class Matrix3;
};

VECTOR3_INLINE Vector3 comp_max(const Vector3&,const Vector3&); //!< per component maximum
VECTOR3_INLINE Vector3 comp_min(const Vector3&,const Vector3&); //!< per component minimum

#if DO_INLINE_VECTOR3 >= 1
#include "vector3.hh"
#endif

#endif // __VECTOR3_H
