#ifndef SIMPLE_MATRIX_H
#define SIMPLE_MATRIX_H

#include <iclSmartPtr.h>
#include <algorithm>

namespace icl{
  
  /// Template parameter class for the SimpleMatrix template \ingroup UTILS
  template<class T>
  struct NullSimpleMatrixAlloc{
    static T create() { return T(0); }
  };

  /// Template parameter class for the SimpleMatrix template \ingroup UTILS
  template<class T>
  struct DefSimpleMatrixAlloc{
    static T create() { return T(); }
  };
  
  /// A Low-Weight Matrix representation for block aligned data \ingroup UTILS
  /** <h1>General</h1>
      The SimpleMatrix class is a utility class, for organizing
      a linear aligned data block, whiches content is associated
      with a matrix of column vectors. It provides a <b>very
      convenient access </b> to the data elements using the 
      "[][]-operator". Although the "[][]"-operator is a combined
      operator, consisting of two successive "[]"-operators, it
      is possible to call this operator because the array-operator 
      "[]" is defined for the SimpleMatrix class to return a pointer 
      to the according column vector (as T*), which can then again
      be accessed using another "[]" operator.

      <h1>Example</h1>
      <pre>
      typedef SimpleMatrix<float> mat;

      mat transpose(mat &src){
          ICLASSERT_RETURN( src.w() = src.h() ); // test for w==h
          mat dst(src.w(),src.h());              // ensures dst. size
          for(int x=0;x<src.w();x++){            // transposed copy
             for(int x=0;x<src.w();x++){
                dst[x][y] = src[y][x];
             }
          }
      }
      
      </pre>
  
      <h1>Performance</h1>
      Because the SimpleMatrix class is pure inline, an as the data
      access operator can easily be optimized to "pointer[y+h*x]",
      is is not slower - but much more convenient - to work with it.
  
      <h1>Data alignment</h1>
      <b>In contrast to ICL Image class Img, the data is aligned 
      horizontally</b> \n
      The following ascii image demonstrates this:
      <pre>
         +             +     +  -+-  -+-  -+-  +              +    +
         | m00 m10 m20 |     |   |    |    |   |              | mi0| 
      M =| m01 m11 m21 |  =  |   v0   v1   v2  |    with vi = | mi1|  
         | m02 m12 m22 |     |   |    |    |   |              | mi2|
         +             +     +  -+-  -+-  -+-  +              +    +
            matrix           set of column vectors
  
       corresponding data array:  data = [ |-v0-|  |-v1-|  |-v2-| ]     
                                       = [ m00 m01 m02 m10 .. m22 ] 
      </pre>

      <h1>Shared data concept</h1>
      As the ICL-image class Img, the SimpleMatrix class uses a 
      smart pointer (see SmartPtr class in the ICLUtils package)
      to facilitate an efficient memory management. All default
      copy mechanisms (copy constructor and assignment operator) 
      will only perform a shallow copy of the source SimpleMatrix
      object. If an explicit "deep copy" is demanded, one of the
      two <em>deepCopy</em>-functions must be used. 
  */
  template<class T, class Alloc=NullSimpleMatrixAlloc<T> >
  struct SimpleMatrix{
    
    /// Creates an empty SimpleMatrix w=h=0
    inline SimpleMatrix():
      m_iW(0),m_iH(0){}
    
    /// Creates a square matrix of size dim x dim filled with 0
    inline SimpleMatrix(int dim): 
      m_oData(new T[dim*dim]),m_iW(dim), m_iH(dim){
      std::fill(m_oData.get(),m_oData.get()+this->dim(),Alloc::create());
    }
  
    /// Creates a matrix of size w x h filled with 0
    inline SimpleMatrix(int w, int h): 
      m_oData(new T[w*h]),m_iW(w), m_iH(h){
      std::fill(m_oData.get(),m_oData.get()+dim(),Alloc::create());
    }
  
    /// Creates a matrix of size w x h, using given shared data
    inline SimpleMatrix(int w, int h, T *sharedData):
      m_oData(sharedData,false), m_iW(w), m_iH(h) {
    }
    
    /// returning a pointer to the column vector at given x offset
    inline T *operator[](int x){ return m_oData.get()+m_iH*x; }

    /// returning a pointer to the column vector at given x offset
    inline const T *operator[](int x) const{ return m_oData.get()+m_iH*x; }

    /// performs a deep copy of the matrix into a destination matrix
    inline void deepCopy(SimpleMatrix &m) const{
      m.m_iW = m_iW;
      m.m_iH = m_iH;
      m.m_oData = SmartPtr<T>(new T[dim()]);
      for(int i=0;i<dim();i++){
        m.data()[i] = T(data()[i]); // explicit call to the copy constructor
      }
    }
    
    /// creates a deep copy of the SimpleMatrix
    inline SimpleMatrix deepCopy() const{
      SimpleMatrix m;
      deepCopy(m);
      return m;
    }
    
    /// returns the data pointer
    inline T* data() { return m_oData.get(); }

    /// returns the data pointer (const version)
    inline const T* data() const { return m_oData.get(); }

    /// width of the matrix (max x index is w()-1
    inline int w() const { return m_iW; }

    /// height of the matrix (max y index is h()-1
    inline int h() const { return m_iH; }

    /// returns the number of matrix elements w*h
    inline int dim() const { return w()*h(); }

    
    inline T min() const { return *std::min_element(data(),data()+dim()); }
    inline T max() const { return *std::max_element(data(),data()+dim()); }

    private:
    /// Shared data pointer
    SmartPtr<T> m_oData;

    /// Matrix dimensions
    int m_iW,m_iH;
  };
  


}

#endif