/// vector3f.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 __VECTOR3F_H_
#define __VECTOR3F_H_


YG("Math");

/* @class Vector3f
This class represents a single precision 3 dimensional coordinate vector.
 */
YC class _Vector3f : public YAC_Object {
  public:
   sF32 floats[3];

  public:
   _Vector3f(void);
   ~_Vector3f();

   YAC_POOLED(_Vector3f, 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);
   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 *);
   //supports:
   //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 assignGeneric(YAC_ContextHandle _ctx, YAC_Object *_o);

  public:
   //Element access methods
   /* @method setX,float a
      Set x element to a
      @arg a new value for x
    */
   YM void _setX(sF32);
   /* @method setY,float a
      Set y element to a
      @arg a new value for y
    */
   YM void _setY(sF32);
   /* @method setZ,float a
      Set z element to a
      @arg a new value for z
    */
   YM void _setZ(sF32);
   /* @method getX:float
      Get value of x element
      @return value of x element
    */
   YM sF32 _getX(void);
   /* @method getY:float
      Get value of y element
      @return value of y element
    */
   YM sF32 _getY(void);
   /* @method getZ:float
      Get value of z element
      @return value of z element
    */
   YM sF32 _getZ(void);

   //produce string representation
   /* @method getString:String
      Get string representation of vector (x, y, z)
      @return string representation of vector
    */
   YM void _getString(YAC_Value *) const;

   //arithmetic
   /* @method add,Vector3f v
      Add another vector v to this instance
      @arg v vector 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,Vector3f v
      Substract another vector v from this instance
      @arg v vector 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 *);

   //scalar dot product
   /* @method dot,Vector3f v:float
      Calculate dot product from this instance and v
      @arg v Vector3f instance
      @return scalar value
    */
   YM sF32 _dot(YAC_Object *);

   //cross product
   /* @method cross,Vector3f v:Vector3f
      Calculate cross product from this instance and v
      @arg v Vector3f instance
      @return orthogonal vector to this instance and v
    */
   YM void _cross_YAC_RVAL(YAC_Object *, YAC_Value *);
   YM void _cross_YAC_RARG(YAC_Object *, YAC_Object *);


   //triple product (spatprodukt)
   /* @method triple,Vector3f b,Vector3f c:float
      Calculate triple product this.dot(b.cross(c)) (a*(bxc)) 
      ærg b second parameter of triple product
      arg c third parameter of triple product
      @return scalar value
    */
   YM sF32 _triple(YAC_Object *, YAC_Object *);


   //tensor product, produces a Matrix3f out of two Vector3f. The result is written to _retM3f
   /* @method tensor,Vector3f v:Matrix3f
      Create resulting matrix of tensor product from this instance and v
      @arg a Vector3f instance
      @return Matrix3f instance
    */
   YM void _tensor_YAC_RVAL(YAC_Object *, YAC_Value *);
   YM void _tensor_YAC_RARG(YAC_Object *_v3f, YAC_Object *_retM3f);


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

   //multiplies each element individual (not really mathematics, but sometimes useful)
   /* @method mul,Vector3f v
      Multiply the x element of this instance with the x element of v and do the same with the y and z element
      @arg v Vector3f instance
    */
   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 *);

   //return length of vector
   /* @method getAbs:float
      Return length of vector
      @return length of vector
    */
   YM sF32 _getAbs(void);
   /* @method getAbsSqr:float
      Return squared length of vector
      @return length<sup>2</sup> of vector
    */
   YM sF32 _getAbsSqr(void);

   //scale vector to length 1 if possible
   /* @method unit
      Set length to 1
    */
   YM void _unit_YAC_RSELF(void); /* unit */
   YM void _unit_YAC_RVAL(YAC_Value *);
   YM void _unit_YAC_RARG(YAC_Object *);

   //set Vector length to Scale
   /* @method unitScale,float s
      Set length to s
      @arg s new length of vector
    */
   YM void _unitScale_YAC_RSELF(sF32);
   YM void _unitScale_YAC_RVAL(sF32, YAC_Value *);
   YM void _unitScale_YAC_RARG(sF32, YAC_Object *);

   //init element values
   /* @method init,float a,float b,float c
      Initialise values to x=a, y=b and z=c
      @arg a new x value
      @arg b new y value
      @arg c new z value
    */
   YM void _init(sF32,sF32,sF32);
   /* @method initScalef,Vector3f v,float s
      Initialise vector to s*v
      @arg v Vector3f instance
      @arg s scale to multiply
    */
   YM void _initScalef(YAC_Object *_o, sF32 _s);
   /* @method New,float a,float b,float c:Vector3f
      Initialise and return new Vector3f instance with x=a, y=b and z=c
      @arg a new x value
      @arg b new y value
      @arg c new z value
    */
   YM void _New(sF32,sF32,sF32,YAC_Value*);
};

/* @function vector3f,float a,float b,float c:Vector3f
   Initialise and return new Vector3f instance with x=a, y=b and z=c
   @arg a new x value
   @arg b new y value
   @arg c new z value
 */
YF void YAC_CALL _vector3f(sF32,sF32,sF32,YAC_Value*);
#endif
