/* -*- mia-c++  -*-
 *
 * This file is part of MIA - a toolbox for medical image analysis 
 * Copyright (c) Leipzig, Madrid 1999-2017 Gert Wollny
 *
 * MIA 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.
 *
 * This program 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 MIA; if not, see <http://www.gnu.org/licenses/>.
 *
 */

#ifndef __mia_2d_matrix_hh
#define __mia_2d_matrix_hh

#include <mia/2d/vector.hh>

NS_MIA_BEGIN

/**
   @ingroup misc 
   \brief A simple 2x2 matrix 
   
   Simple implementation of a 2D Matrix to store 2nd order derivatives. 
 */

template <typename T> 
struct T2DMatrix: public T2DVector< T2DVector<T> > {
	
	T2DMatrix(); 

	/// copy constructor 
	T2DMatrix(const T2DMatrix<T>& o); 

	/// construct the matrix from a 2D vector of 2D vectors 
	T2DMatrix(const T2DVector< T2DVector<T> >& o); 
	
	/** construct  the matrix from two 2D vectors 
	    \param x 1st row 
	    \param y 2nd row 
	*/
	T2DMatrix(const T2DVector< T >& x, const T2DVector< T >& y ); 
	
	/// assignment operator 
	T2DMatrix& operator = (const T2DMatrix<T>& o);
	
	/// element wise subtract operator 
	T2DMatrix& operator -= (const T2DMatrix<T>& o);

	/**
	   \returns the transposed of this matrix 
	 */
	T2DMatrix<T>  transposed()const; 


	static const T2DMatrix _1; 
	static const T2DMatrix _0; 

}; 

template <typename T> 
const T2DMatrix<T> T2DMatrix<T>::_1(T2DVector< T >(1,0), 
				    T2DVector< T >(0,1));

template <typename T> 
const T2DMatrix<T> T2DMatrix<T>::_0;


template <typename T> 
T2DMatrix<T>::T2DMatrix():
	T2DVector<T2DVector<T> >(T2DVector<T>(), T2DVector<T>())
{
}

template <typename T> 
T2DMatrix<T>::T2DMatrix(const T2DMatrix<T>& o):
	T2DVector<T2DVector<T> >(o.x, o.y)
{
}

template <typename T> 
T2DMatrix<T>::T2DMatrix(const T2DVector< T2DVector<T> >& o):
	T2DVector<T2DVector<T> >(o.x, o.y)
{
}

template <typename T> 
T2DMatrix<T>::T2DMatrix(const T2DVector< T >& x, const T2DVector< T >& y ):
	T2DVector<T2DVector<T> >(x, y)
{
}


template <typename T> 
T2DMatrix<T>& T2DMatrix<T>::operator = (const T2DMatrix<T>& o)
{
	this->x = o.x; 
	this->y = o.y; 
	return *this; 
}

template <typename T> 
T2DMatrix<T>& T2DMatrix<T>::operator -= (const T2DMatrix<T>& o)
{
	this->x -= o.x; 
	this->y -= o.y; 
	return *this; 
}

template <typename T> 
T2DMatrix<T>  T2DMatrix<T>::transposed()const
{
	return T2DMatrix<T>(T2DVector< T >(this->x.x, this->y.x), 
			    T2DVector< T >(this->y.y, this->y.y)); 
}

/**
   Left hand side product of a matrix m and a vector x 
   \param x
   \param m
   \returns x * m 
 */

template <typename T> 
T2DVector<T> operator * (const T2DVector<T>& x, const T2DMatrix<T>& m)
{
	return T2DVector<T>(dot(m.x, x), dot(m.y, x)); 
}

/**
   right hand side product of a matrix m and a vector x 
   \param m
   \param x
   \returns m * x
 */

template <typename T> 
T2DVector<T> operator * (const T2DMatrix<T>& m, const T2DVector<T>& x  )
{
	return T2DVector<T>(m.x.x * x.x + m.y.x * x.y, 
			    m.x.y * x.x + m.y.y * x.y);
}

/// a simple 2x2 matrix 
typedef T2DMatrix<float> C2DFMatrix; 

NS_MIA_END

#endif
