/*
 *  mmatrix.h
 *  (C) Porkolab Zoltan, ELTE, Budapest, Hungary
 *  (C) 2003
 */


#ifndef MMATRIX_H
#define MMATRIX_H

#include <vector>

template <typename T>
class mmatrix
{
public:
    class index : public std::vector<int>
    {
    public:
        void   reset() { clear(); }
        index &put(int i) { push_back(i); return *this; }
        int    maxIndex() const; 
    };
    typedef typename std::vector<T>::iterator iterator;
    typedef typename std::vector<T>::const_iterator const_iterator;

    iterator begin() { return vec_.begin(); }    
    const_iterator begin() const { return vec_.begin(); }    
    iterator end() { return vec_.end(); }
    const_iterator end()   const { return vec_.end();   }

    mmatrix(index ix) : size_(ix), vec_(ix.maxIndex()) { } 
    int  dim() const { return size_.size(); }

    T& at(index ix);
    const T& at(index ix) const;
    T& operator[](index ix);
    const T& operator[](index ix) const;
private:
    const std::vector<int> size_;   
    std::vector<T>   vec_; 

    int plainIndex(index ix) const;
};

template <typename T>
int mmatrix<T>::index::maxIndex() const
{
    int max = 1;
    for (size_t i = 0; i < size(); ++i)
        max *= operator[](i);
    return max; 
}
template <typename T>
int mmatrix<T>::plainIndex( index ix) const
{
    int ind = ix[0];
    for ( size_t i = 0; i < ix.size()-1; ++i)
        ind = ind * size_[i+1] + ix[i+1];
    return ind;
}
template <typename T>
T& mmatrix<T>::at(index ix)
{
    return vec_.at(plainIndex(ix));    
}
template <typename T>
const T& mmatrix<T>::at(index ix) const
{
    return vec_.at(plainIndex(ix));    
}
template <typename T>
T& mmatrix<T>::operator[](index ix)
{
    return vec_[plainIndex(ix)];    
}
template <typename T>
const T& mmatrix<T>::operator[](index ix) const
{
    return vec_[plainIndex(ix)];    
}

#endif /* MMATRIX_H */