/*
 * (C) Copyright 1996- ECMWF.
 *
 * This software is licensed under the terms of the Apache Licence Version 2.0
 * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
 * In applying this licence, ECMWF does not waive the privileges and immunities
 * granted to it by virtue of its status as an intergovernmental organisation nor
 * does it submit to any jurisdiction.
 */

#ifndef eckit_maths_Matrix_h
#error Include "eckit/maths/Matrix.h" instead of "eckit/maths/MatrixEigen.h"
#endif

#ifndef eckit_maths_MatrixEigen_h
#define eckit_maths_MatrixEigen_h

#include "eckit/maths/Eigen.h"

namespace eckit {

namespace maths {

//========================================================================================

/// @brief Matrix class, with internal Column-Major storage ordering
///
/// This class is inherited from Eigen's matrix class
/// Eigen::ColMajor is also Eigen's default (recommended) storage ordering.
/// Furthermore it is directly compatible with Fortran matrix manipulation routines
template <typename scalar, typename index = std::ptrdiff_t>
class Matrix : public Eigen::Matrix<scalar,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor>
{
	typedef Eigen::Matrix<scalar,Eigen::Dynamic,Eigen::Dynamic,Eigen::ColMajor> Base;
public:
	typedef typename Base::MapType Proxy;
	typedef typename Base::ConstMapType ConstProxy;

public:

	// Default constructor
	Matrix(void)
		: Base()
	{ }

	// Constructor that allocates matrix with sizes
	template<typename T0, typename T1>
	Matrix(const T0& x, const T1& y)
		: Base(x,y)
	{ }

	// This constructor allows you to construct Matrix from Eigen expressions
	template<typename OtherDerived>
	Matrix(const Eigen::MatrixBase<OtherDerived>& other)
		: Base(other)
	{ }

	// This method allows you to assign Eigen expressions to Matrix
	template<typename OtherDerived>
	Matrix& operator= (const Eigen::MatrixBase <OtherDerived>& other)
	{
		this->Base::operator=(other);
		return *this;
	}
};

//========================================================================================

/// @brief Row-Vector class
///
/// This class is inherited from Eigen's matrix class
template <typename scalar, typename index = std::ptrdiff_t>
class RowVector : public Eigen::Matrix<scalar,1,Eigen::Dynamic>
{
	typedef Eigen::Matrix<scalar,1,Eigen::Dynamic> Base;
public:
	typedef typename Base::MapType Proxy;
public:

	// Default constructor
	RowVector(void)
		: Base()
	{ }

	// Constructor that allocates matrix with sizes
	template<typename T>
	RowVector(const T& x)
		: Base(x)
	{ }

	// This constructor allows you to construct Matrix from Eigen expressions
	template<typename OtherDerived>
	RowVector(const Eigen::MatrixBase<OtherDerived>& other)
		: Base(other)
	{ }

	// This method allows you to assign Eigen expressions to Matrix
	template<typename OtherDerived>
	RowVector& operator= (const Eigen::MatrixBase <OtherDerived>& other)
	{
		this->Base::operator=(other);
		return *this;
	}
};

//========================================================================================

/// @brief Column-Vector class
///
/// This class is inherited from Eigen's matrix class
template <typename scalar, typename index = std::ptrdiff_t>
class ColVector : public Eigen::Matrix<scalar,Eigen::Dynamic,1>
{
	typedef Eigen::Matrix<scalar,Eigen::Dynamic,1> Base;
public:
	typedef typename Base::MapType Proxy;
public:

	// Default constructor
	ColVector(void)
		: Base()
	{ }

	// Constructor that allocates matrix with sizes
	template<typename T>
	ColVector(const T& x)
		: Base(x)
	{ }

	// This constructor allows you to construct Matrix from Eigen expressions
	template<typename OtherDerived>
	ColVector(const Eigen::MatrixBase<OtherDerived>& other)
		: Base(other)
	{ }

	// This method allows you to assign Eigen expressions to Matrix
	template<typename OtherDerived>
	ColVector& operator= (const Eigen::MatrixBase <OtherDerived>& other)
	{
		this->Base::operator=(other);
		return *this;
	}
};

//========================================================================================

} // namespace maths

} // namespace eckit

#endif
