/// matrix2f.h
///
/// (c) 2008 by Carsten Busse <carsten.busse@googlemail.com>
///             Bastian Spiegel <bs@tkscript.de> (additional coding)
///     - Distributed under terms of the Lesser GNU General Public License (LGPL).
///       See COPYING and <http://www.gnu.org/licenses/licenses.html#LGPL> for further information.
///
///

#ifndef __MATRIX2F_H_
#define __MATRIX2F_H_


YG("Math");

/* @class Matrix2f,Object
This class represents a single precision 2x2 square matrix.
 */
YC class _Matrix2f : public YAC_Object {
  public:
   sF32 floats[4];

   public:
   _Matrix2f(void);
   ~_Matrix2f();
   YAC_POOLED(_Matrix2f,YAC_POOL_PRIORITY_HIGH);
   sUI YAC_VCALL yacArrayGetNumElements(void);
   sUI YAC_VCALL yacArrayGetMaxElements(void);
   sUI YAC_VCALL yacArrayGetElementType(void);
   sUI YAC_VCALL yacArrayGetElementByteSize(void);
   void YAC_VCALL yacArraySet(YAC_ContextHandle, sUI, YAC_Value *);
   void YAC_VCALL yacArrayGet(YAC_ContextHandle, sUI, YAC_Value *);
   void *YAC_VCALL yacArrayGetPointer(void);
   sUI YAC_VCALL yacArrayGetWidth(void);
   sUI YAC_VCALL yacArrayGetHeight(void);
   sUI YAC_VCALL yacArrayGetStride(void);
   sSI YAC_VCALL yacTensorRank(void);
   void YAC_VCALL yacSerialize(YAC_Object *, sUI);
   sUI YAC_VCALL yacDeserialize(YAC_Object *, sUI);
   void YAC_VCALL yacOperatorClamp(YAC_Object *, YAC_Object *);
   void YAC_VCALL yacOperatorWrap(YAC_Object *, YAC_Object *);
//YAC_OP_CEQ, YAC_OP_CNE, YAC_OP_ASSIGN, YAC_OP_ADD = _add,
//YAC_OP_SUB = _sub, YAC_OP_MUL = _mul, YAC_OP_NEG, YAC_OP_INIT
   void YAC_VCALL yacOperator(sSI, YAC_Object *, YAC_Value *);
   void YAC_VCALL yacOperatorI(sSI, sSI, YAC_Value *);
   void YAC_VCALL yacOperatorF32(sSI, sF32, YAC_Value *);
   sBool YAC_VCALL yacToString(YAC_String *) const;

   // Helper methods
   void assignFloats(sF32 *_fv, sUI _ne);
   void assignFloatArray(YAC_FloatArray *_fa);
   void assignFloatMatrix(YAC_Object *_o);
   void assignGeneric(YAC_ContextHandle _ctx, YAC_Object *_o);


//element access methods
   /* @method setA,float v
      Set a element to v
      @arg v new value for a
    */
   YM void _setA(sF32);
   /* @method setB,float v
      Set b element to v
      @arg v new value for b
    */
   YM void _setB(sF32);
   /* @method setC,float v
      Set c element to v
      @arg v new value for c
    */
   YM void _setC(sF32);
   /* @method setD,float v
      Set d element to v
      @arg v new value for d
    */
   YM void _setD(sF32);

   /* @method getA:float
      Get value of a element
      @return value of a element
    */
   YM sF32 _getA(void);
   /* @method getB:float
      Get value of b element
      @return value of b element
    */
   YM sF32 _getB(void);
   /* @method getC:float
      Get value of c element
      @return value of c element
    */
   YM sF32 _getC(void);
   /* @method getD:float
      Get value of d element
      @return value of d element
    */
   YM sF32 _getD(void);

//produce string representation
   /* @method getString:String
      Get string representation of matrix ((a, b), (c, d))
      @return string representation of matrix
    */
   YM void _getString(YAC_Value *) const;

//arithmetics
   /* @method add,Matrix2f m
      Add another matrix m to this instance
      @arg m matrix to add
    */
   YM void _add_YAC_RSELF(YAC_Object *);
   YM void _add_YAC_RVAL(YAC_Object *, YAC_Value *);
   YM void _add_YAC_RARG(YAC_Object *, YAC_Object *);

   /* @method sub,Matrix2f m
      Substract another matrix m from this instance
      @arg m matrix to substract
    */
   YM void _sub_YAC_RSELF(YAC_Object *);
   YM void _sub_YAC_RVAL(YAC_Object *, YAC_Value *);
   YM void _sub_YAC_RARG(YAC_Object *, YAC_Object *);

//multiply with scalar
   /* @method mulf,float v
      Multiply this instance with scalar value v
      @arg v value to multiply
    */
   YM void _mulf_YAC_RSELF(sF32);
   YM void _mulf_YAC_RVAL(sF32, YAC_Value *);
   YM void _mulf_YAC_RARG(sF32, YAC_Object *);

//matrix multiplication
   /* @method mul,Matrix2f m
      Multiply this instance with matrix m
      @arg m matrix to multiply
    */
   YM void _mul_YAC_RSELF(YAC_Object *);
   YM void _mul_YAC_RVAL(YAC_Object *, YAC_Value *);
   YM void _mul_YAC_RARG(YAC_Object *, YAC_Object *);

//multiply matrix with vector (result is a vector)
   /* @method mulv,Vector2f v:Vector2f
      Multiply this instance with a 2dim vector
      @arg v vector to multiply
      @return resulting vector
    */
   YM void _mulv_YAC_RVAL(YAC_Object *, YAC_Value *);
   YM void _mulv_YAC_RARG(YAC_Object *, YAC_Object *);

//get "absolute" value for matrix
   /* @method getAbs:float
      Calculate the Hilbert-Schmidt norm of the matrix
      @return scalar matrix norm value
    */
   YM sF32 _getAbs(void);
   /* @method getAbsSqr:float
      Calculate the squared Hilbert-Schmidt norm of the matrix
      @return scalar matrix norm value
    */
   YM sF32 _getAbsSqr(void);

//normalize matrix

   /* @method unit
      Normalise matrix with Hilbert-Schmidt norm
    */
   YM void _unit_YAC_RSELF(void); /* unit */
   YM void _unit_YAC_RVAL(YAC_Value *);
   YM void _unit_YAC_RARG(YAC_Object *);

//normalize and scale matrix
   /* @method unitScale,float v
      Normalise matrix with Hilbert-Schmidt norm and multiply with v afterwards
      @arg v value to scale matrix
    */
   YM void _unitScale_YAC_RSELF(sF32);
   YM void _unitScale_YAC_RVAL(sF32, YAC_Value *);
   YM void _unitScale_YAC_RARG(sF32, YAC_Object *);

//get scalar determinabt
   /* @method det:float
      Calculate determinant of matrix
      @return value of determinant
    */
   YM sF32 _det(void);

//invert matrix so the A*A^-1=E
   /* @method invert
      Calculate inversion of matrix, so that A*A<sup>-1</sup>=U
    */
   YM void _invert_YAC_RSELF(void);
   YM void _invert_YAC_RVAL(YAC_Value *);
   YM void _invert_YAC_RARG(YAC_Object *);

//transpose matrix
   /* @method transpose
      Transpose matrix
    */
   YM void _transpose_YAC_RSELF(void);
   YM void _transpose_YAC_RVAL(YAC_Value *);
   YM void _transpose_YAC_RARG(YAC_Object *);

//access row and column vectors
   /* @method setRow,int r,Vector2f v
      Set row r with values from v
      @arg r row number
      @arg v Vector2f instance
    */
   YM void _setRow(sUI, YAC_Object*);

   /* @method getRow,int r:Vector2f
      Get row r values
      @arg r row number
      @return vector with values from row r
    */
   YM void _getRow_YAC_RVAL(sUI, YAC_Value*);
   YM void _getRow_YAC_RARG(sUI, YAC_Object*);

   /* @method setCol,int c,Vector2f v
      Set column c with values from v
      @arg c column number
      @arg v Vector2f instance
    */
   YM void _setCol(sUI, YAC_Object*);

   /* @method getCol,int c:Vector2f
      Get column c values
      @arg c column number
      @return vector with values from column c
    */
   YM void _getCol_YAC_RVAL(sUI, YAC_Value*);
   YM void _getCol_YAC_RARG(sUI, YAC_Object*);
//init matrix values
   /* @method init,float va,float vb,float vc,float vd
      Initialise matrix
      @arg va value for a
      @arg vb value for b
      @arg vc value for c
      @arg vd value for d
    */
   YM void _init(sF32,sF32,sF32,sF32);
   /* @method initRow,int r,float va,float vb
      Initialise row r of matrix
      @arg r row number
      @arg va value for first element
      @arg vb value for second element
    */
   YM void _initRow(sUI,sF32,sF32);
   /* @method initCol,int c,float va,float vb
      Initialise column c of matrix
      @arg c column number
      @arg va value for first element
      @arg vb value for second element
    */
   YM void _initCol(sUI,sF32,sF32);
   /* @method initRowV,int r,Vector2f v
      Initialise row r of matrix
      @arg r row number
      @arg v vector with values
    */
   YM void _initRowV(sUI,YAC_Object*);
   /* @method initColV,int c,Vector2f v
      Initialise column c of matrix
      @arg c column number
      @arg v vector with values
    */
   YM void _initColV(sUI,YAC_Object*);
   /* @method New,float va,float vb,float vc,float vd:Matrix2f
      Initialise and return new instance of Matrix2f
      @arg va value for a
      @arg vb value for b
      @arg vc value for c
      @arg vd value for d
      @return new instance of Matrix2f
    */
   YM void _New(sF32,sF32,sF32,sF32,YAC_Value*);


   /* @method initIdentity
      Initialize with identity matrix.
   */
   YM void _initIdentity(void);
};

/* @function matrix2f,float va,float vb,float vc,float vd:Matrix2f
   Initialise and return new instance of Matrix2f
   @arg va value for a
   @arg vb value for b
   @arg vc value for c
   @arg vd value for d
   @return new instance of Matrix2f
 */
YF void YAC_CALL _matrix2f(sF32,sF32,sF32,sF32,YAC_Value*);
#endif
