// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2009 Gael Guennebaud <g.gael@free.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef EIGEN_ALIGNED_VECTOR3_MODULE_H
#define EIGEN_ALIGNED_VECTOR3_MODULE_H

#include "../../Eigen/Geometry"

#include "../../Eigen/src/Core/util/DisableStupidWarnings.h"

namespace Eigen {

/**
 * \defgroup AlignedVector3_Module Aligned vector3 module
 *
 * \code
 * #include <unsupported/Eigen/AlignedVector3>
 * \endcode
 */
//@{

/** \class AlignedVector3
 *
 * \brief A vectorization friendly 3D vector
 *
 * This class represents a 3D vector internally using a 4D vector
 * such that vectorization can be seamlessly enabled. Of course,
 * the same result can be achieved by directly using a 4D vector.
 * This class makes this process simpler.
 *
 */
// TODO specialize Cwise
template <typename Scalar_>
class AlignedVector3;

namespace internal {
template <typename Scalar_>
struct traits<AlignedVector3<Scalar_> > : traits<Matrix<Scalar_, 3, 1, 0, 4, 1> > {};
}  // namespace internal

template <typename Scalar_>
class AlignedVector3 : public MatrixBase<AlignedVector3<Scalar_> > {
  typedef Matrix<Scalar_, 4, 1> CoeffType;
  CoeffType m_coeffs;

 public:
  typedef MatrixBase<AlignedVector3<Scalar_> > Base;
  EIGEN_DENSE_PUBLIC_INTERFACE(AlignedVector3)
  using Base::operator*;

  inline Index rows() const { return 3; }
  inline Index cols() const { return 1; }

  Scalar* data() { return m_coeffs.data(); }
  const Scalar* data() const { return m_coeffs.data(); }
  Index innerStride() const { return 1; }
  Index outerStride() const { return 3; }

  inline const Scalar& coeff(Index row, Index col) const { return m_coeffs.coeff(row, col); }

  inline Scalar& coeffRef(Index row, Index col) { return m_coeffs.coeffRef(row, col); }

  inline const Scalar& coeff(Index index) const { return m_coeffs.coeff(index); }

  inline Scalar& coeffRef(Index index) { return m_coeffs.coeffRef(index); }

  inline AlignedVector3() {}

  inline AlignedVector3(const Scalar& x, const Scalar& y, const Scalar& z) : m_coeffs(x, y, z, Scalar(0)) {}

  inline AlignedVector3(const AlignedVector3& other) : Base(), m_coeffs(other.m_coeffs) {}

  template <typename XprType, int Size = XprType::SizeAtCompileTime>
  struct generic_assign_selector {};

  template <typename XprType>
  struct generic_assign_selector<XprType, 4> {
    inline static void run(AlignedVector3& dest, const XprType& src) { dest.m_coeffs = src; }
  };

  template <typename XprType>
  struct generic_assign_selector<XprType, 3> {
    inline static void run(AlignedVector3& dest, const XprType& src) {
      dest.m_coeffs.template head<3>() = src;
      dest.m_coeffs.w() = Scalar(0);
    }
  };

  template <typename Derived>
  inline AlignedVector3(const MatrixBase<Derived>& other) {
    generic_assign_selector<Derived>::run(*this, other.derived());
  }

  inline AlignedVector3& operator=(const AlignedVector3& other) {
    m_coeffs = other.m_coeffs;
    return *this;
  }

  template <typename Derived>
  inline AlignedVector3& operator=(const MatrixBase<Derived>& other) {
    generic_assign_selector<Derived>::run(*this, other.derived());
    return *this;
  }

  inline AlignedVector3 operator+(const AlignedVector3& other) const {
    return AlignedVector3(m_coeffs + other.m_coeffs);
  }

  inline AlignedVector3& operator+=(const AlignedVector3& other) {
    m_coeffs += other.m_coeffs;
    return *this;
  }

  inline AlignedVector3 operator-(const AlignedVector3& other) const {
    return AlignedVector3(m_coeffs - other.m_coeffs);
  }

  inline AlignedVector3 operator-() const { return AlignedVector3(-m_coeffs); }

  inline AlignedVector3 operator-=(const AlignedVector3& other) {
    m_coeffs -= other.m_coeffs;
    return *this;
  }

  inline AlignedVector3 operator*(const Scalar& s) const { return AlignedVector3(m_coeffs * s); }

  inline friend AlignedVector3 operator*(const Scalar& s, const AlignedVector3& vec) {
    return AlignedVector3(s * vec.m_coeffs);
  }

  inline AlignedVector3& operator*=(const Scalar& s) {
    m_coeffs *= s;
    return *this;
  }

  inline AlignedVector3 operator/(const Scalar& s) const { return AlignedVector3(m_coeffs / s); }

  inline AlignedVector3& operator/=(const Scalar& s) {
    m_coeffs /= s;
    return *this;
  }

  inline Scalar dot(const AlignedVector3& other) const {
    eigen_assert(m_coeffs.w() == Scalar(0));
    eigen_assert(other.m_coeffs.w() == Scalar(0));
    return m_coeffs.dot(other.m_coeffs);
  }

  inline void normalize() { m_coeffs /= norm(); }

  inline AlignedVector3 normalized() const { return AlignedVector3(m_coeffs / norm()); }

  inline Scalar sum() const {
    eigen_assert(m_coeffs.w() == Scalar(0));
    return m_coeffs.sum();
  }

  inline Scalar squaredNorm() const {
    eigen_assert(m_coeffs.w() == Scalar(0));
    return m_coeffs.squaredNorm();
  }

  inline Scalar norm() const {
    using std::sqrt;
    return sqrt(squaredNorm());
  }

  inline AlignedVector3 cross(const AlignedVector3& other) const {
    return AlignedVector3(m_coeffs.cross3(other.m_coeffs));
  }

  template <typename Derived>
  inline bool isApprox(const MatrixBase<Derived>& other,
                       const RealScalar& eps = NumTraits<Scalar>::dummy_precision()) const {
    return m_coeffs.template head<3>().isApprox(other, eps);
  }

  CoeffType& coeffs() { return m_coeffs; }
  const CoeffType& coeffs() const { return m_coeffs; }
};

namespace internal {

template <typename Scalar_>
struct eval<AlignedVector3<Scalar_>, Dense> {
  typedef const AlignedVector3<Scalar_>& type;
};

template <typename Scalar>
struct evaluator<AlignedVector3<Scalar> > : evaluator<Matrix<Scalar, 4, 1> > {
  typedef AlignedVector3<Scalar> XprType;
  typedef evaluator<Matrix<Scalar, 4, 1> > Base;

  evaluator(const XprType& m) : Base(m.coeffs()) {}
};

}  // namespace internal

//@}

}  // namespace Eigen

#include "../../Eigen/src/Core/util/ReenableStupidWarnings.h"

#endif  // EIGEN_ALIGNED_VECTOR3_MODULE_H
