
#ifndef __WFX_MATH_MATRIX3_H__
#define __WFX_MATH_MATRIX3_H__

#include <WFX/WFXIncludes.h>
#include <WFX/math/Math.h>
#include <WFX/math/Vector3.h>

// freely adapted from Wild Magic  
// http://www.magic-software.com
// and Ogre
// http://ogre.sf.net

// NOTE.  The (x,y,z) coordinate system is assumed to be right-handed.
// Coordinate axis rotation matrices are of the form
//   RX =    1       0       0
//           0     cos(t) -sin(t)
//           0     sin(t)  cos(t)
// where t > 0 indicates a counterclockwise rotation in the yz-plane
//   RY =  cos(t)    0     sin(t)
//           0       1       0
//        -sin(t)    0     cos(t)
// where t > 0 indicates a counterclockwise rotation in the zx-plane
//   RZ =  cos(t) -sin(t)    0
//         sin(t)  cos(t)    0
//           0       0       1
// where t > 0 indicates a counterclockwise rotation in the xy-plane.
namespace WFX {

    namespace math {

        /** A 3x3 matrix which can represent rotations around axes.
            @note
                <b>All the code is adapted from the Wild Magic 0.2 Matrix
                library (http://www.magic-software.com).
            @par
                The coordinate system is assumed to be <b>right-handed</b>.
        */
        class Matrix3 {
        public:
            static const Real EPSILON;
            static const Matrix3 ZERO;
            static const Matrix3 IDENTITY;

            // construction
            Matrix3 ();
            Matrix3 (const Real arr[3][3]);
            Matrix3 (const Matrix3& rkMatrix);
            Matrix3 (Real fEntry00, Real fEntry01, Real fEntry02,
                        Real fEntry10, Real fEntry11, Real fEntry12,
                        Real fEntry20, Real fEntry21, Real fEntry22);

            // member access, allows use of construct mat[r][c]
            Real* operator[] (int iRow) const;
            operator Real* ();

            // assignment and comparison
            Matrix3& operator= (const Matrix3& rkMatrix);
            bool operator== (const Matrix3& rkMatrix) const;
            bool operator!= (const Matrix3& rkMatrix) const;

            // arithmetic operations
            Matrix3 operator+ (const Matrix3& rkMatrix) const;
            Matrix3 operator- (const Matrix3& rkMatrix) const;
            Matrix3 operator* (const Matrix3& rkMatrix) const;
            Matrix3 operator- () const;

            // matrix * vector [3x3 * 3x1 = 3x1]
            Vector3 operator* (const Vector3& rkVector) const;

            // matrix * scalar
            Matrix3 operator* (Real fScalar) const;

            // utilities
            Matrix3 transpose () const;
            bool inverse (Matrix3& rkInverse, Real fTolerance = 1e-06) const;
            Matrix3 inverse (Real fTolerance = 1e-06) const;
            Real determinant () const;

            /** output some debug information */
            const void printDebug() const {
                LOG("|" << m[0][0] << "|" << m[1][0] << "|" << m[2][0] << "|");
                LOG("|" << m[0][1] << "|" << m[1][1] << "|" << m[2][1] << "|");
                LOG("|" << m[0][2] << "|" << m[1][2] << "|" << m[2][2] << "|");
            }

            //generate rotation matrices
            inline static Matrix3 rotationMatrixX(Real r) {
                return Matrix3(1, 0,                 0,
                               0, Math::cos(r),      Math::sin(r),
                               0, (-1)*Math::sin(r), Math::cos(r)
                              );
            }
            inline static Matrix3 rotationMatrixY(Real r) {
                return Matrix3 (Math::cos(r), 0, (-1)*Math::sin(r),
                                0,            1, 0,
                                Math::sin(r), 0, Math::cos(r)
                               );
            }
            inline static Matrix3 rotationMatrixZ(Real r) {
                 return Matrix3 (Math::cos(r),      Math::sin(r), 0,
                                 (-1)*Math::sin(r), Math::cos(r), 0,
                                 0,                 0,            1
                                );
            }
            
            
        protected:
            friend class Matrix4;
            Real m[3][3];

        };

    }

}


#endif //include guard


