//////////////////////////////////////////////////////////////////////
//
// Gospodnetic Luka, 0036375942, v1.0, 15.03.2003,	
// 
// Ova datoteka sadrzi klasu matrica te prototipove svih funkcija
// vezanih uz tu klasu. Tu se nalazi i klasa za exceptione koji se
// mogu pojaviti prilikom baratanja s klasom matrica.
//  
//////////////////////////////////////////////////////////////////////

#ifndef Matrix_h
#define Matrix_h

#include <iostream>	// std::cin, std::cout, std::cerr ...
#include <string>   // std::string

//////////////////////////////////////////////////////////////////////
//
// Exception klase.
//  
//////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////
	//
	// class EMatrixException
	// ----------------------
	//
	// Osnovna klasa za sve exceptione koje baca klasa Matrix.
	//  
	//////////////////////////////////////////////////////////////////

		class EMatrixException
		{
		protected:
			const std::string errorMessage_;

		protected:
			EMatrixException( const std::string& errorMessage ) : errorMessage_(errorMessage) {}

		public:
			std::string getErrorMessage( void ) const { return errorMessage_; }
		};

	//////////////////////////////////////////////////////////////////
	//
	// class EInvalidMatrix
	// --------------------
	//
	// Exception koji baca objekt klase Matrix ukoliko ima neispravne
	// dimenzije.
	//  
	//////////////////////////////////////////////////////////////////

		class EInvalidMatrix: public EMatrixException
		{
		public:
			EInvalidMatrix( void ) : EMatrixException( "Error: invalid size!" ) {}
		};

	//////////////////////////////////////////////////////////////////
	//
	// class ENotAllocated
	// -------------------
	//
	// Exception koji baca objekt klase Matrix kada nije inicijaliziran,
	// a trebao bi biti.
	//  
	//////////////////////////////////////////////////////////////////

		class ENotAllocated: public EMatrixException
		{
		public:
			ENotAllocated( void ) : EMatrixException( "Error: not allocated!" ) {}
		};

//////////////////////////////////////////////////////////////////////
//
// class Matrix
// ------------
//
// Klasa koja modelira konacnodimenzionalne realne matrice.
//  
//////////////////////////////////////////////////////////////////////

	class Matrix
	{
		private:
			int brRedova_;
			int brStupaca_;
			double* data_;

		public:
		// Public destructor.
			~Matrix( void );

		// Public constructors.
			Matrix( void );
			Matrix( int brRedak, int brStupac );
			Matrix( const Matrix& );

		// Public getters.
			// dohvati podatke o broju redova
			int getBrojRedova( void ) const;
			// dohvati podatke o broju stupaca
			int getBrojStupaca( void ) const;
			// dohvati podatak iz matrice
			double getData( int redak, int stupac ) const;
			
		// Public information.
			// je li matrica inicijalizirana?
			bool allocated( void ) const;
			// je li matrica kvadratna?
			bool check_quadratic( void ) const;
			// je li matrica kvadratna dimenzije dimension?
			bool check_quadratic_dimension( int dimension ) const;
			// je li matrica zadanih dimenzija?
			bool check_dimension( int brRedak, int brStupac ) const;

		// Public operations.
			// obrisi podatke
			void clear( void );
			// alociraj memoriju za (i,j)
			void create( int brRedak, int brStupac );
			// stavi podatak u matricu
			void putData( int redak, int stupac, double );
			// zamijeni vrijednosti retku1 i retku2
			void replaceRows( int redak1, int redak2 );
			// swap dvije matrice.
			void swap( Matrix& rhs );
			// transponiraj matricu.
			void transpose( void );
			
			// Operatori.
			Matrix& operator= ( const Matrix& );
			Matrix& operator+=( const Matrix& );
			Matrix& operator-=( const Matrix& );
			Matrix& operator*=( const Matrix& ); 
			Matrix& operator*=( double		  );
			bool	operator==( const Matrix& ) const;
	};

//////////////////////////////////////////////////////////////////////
//
// Inline member funkcije klase Matrix.
//  
//////////////////////////////////////////////////////////////////////

	inline bool Matrix::allocated     ( void ) const { return !!data_   ; }
	inline int  Matrix::getBrojRedova ( void ) const { return brRedova_ ; }
	inline int  Matrix::getBrojStupaca( void ) const { return brStupaca_; }

//////////////////////////////////////////////////////////////////////
//
// Deklaracije eksternog interfacea klase Matrix.
//  
//////////////////////////////////////////////////////////////////////

	void check_allocated      ( const Matrix&                );
	void check_matrixSizeMatch( const Matrix&, const Matrix& );
	void check_matrixChained  ( const Matrix&, const Matrix& );
			
	std::istream& operator>>( std::istream&, Matrix& );
	std::ostream& operator<<( std::ostream&, const Matrix& );

//////////////////////////////////////////////////////////////////////
//
// Inline funkcije eksternog inferfacea klase Matrix.
//  
//////////////////////////////////////////////////////////////////////

	inline Matrix operator+( const Matrix& lhs, const Matrix& rhs ) { return Matrix(lhs) += rhs; }
	inline Matrix operator-( const Matrix& lhs, const Matrix& rhs ) { return Matrix(lhs) -= rhs; }
	inline Matrix operator*( const Matrix& lhs, const Matrix& rhs ) { return Matrix(lhs) *= rhs; }
	inline Matrix operator*( const Matrix& lhs, const double rhs )  { return Matrix(lhs) *= rhs; }
	inline Matrix operator*( const double lhs, const Matrix& rhs )  { return Matrix(rhs) *= lhs; }

#endif 