#ifndef _NTPM_ARITHIT_H
#define _NTPM_ARITHIT_H

#include <iterator>
#include <arithmetic_iterators/linalg.h>

// make a namespace for this so that Koenig lookup will help not confound
// the lookup of operator + below.
namespace NTPMai {

    using namespace std;

    // XXX get rid of this?
struct arithmetic_iterator {};


// Used to make static type checks.
// check_type<T_WANTED>(T_GIVEN()) fails compilaion if an object of
// of type T_GIVEN can be casted to T_WANTED.
template <class T> void check_type(const T &) {}


template <class _ITER>
class Promise
{
public:
    typedef _ITER const_iterator;
    typedef iterator_traits<const_iterator>::value_type value_type;

    Promise(const_iterator _beg, const_iterator _end) : b(_beg), e(_end) {
	check_type<input_iterator_tag>(iterator_traits<const_iterator>::iterator_category());
    }
    const_iterator begin() const { return b; }
    const_iterator end() const { return e; }
private:
    const_iterator b, e;
};

template <class _ITER>
class Promise_out
{
public:
    typedef _ITER iterator;
    typedef iterator_traits<iterator>::value_type value_type;


    Promise_out(iterator _beg, iterator _end) : b(_beg), e(_end) {
	check_type<output_iterator_tag>(iterator_traits<iterator>::iterator_category());
    }
    iterator begin()  { return b; }
    iterator end()  { return e; }
private:
    iterator b, e;
};


template <class _ITER>
class MatrixPromise : public Promise<_ITER>
{
public:
    MatrixPromise(const_iterator beg, const_iterator end,
		  int _nrows, int _ncols)
	: Promise<const_iterator>(beg,end), nrows_(_nrows), ncols_(_ncols) {}
    int ncols() const { return ncols_; }
    int Width() const { return ncols_; }
    int nrows() const { return nrows_; }
    int Height() const { return nrows_; }
private:
    int nrows_, ncols_;
};


}


namespace NTPM {

using namespace NTPMai;

// Makes a generic promise from a container.
template <class T_G>
Promise<typename T_G::const_iterator>
inline make_promise(const T_G &m)
{
    return Promise<typename T_G::const_iterator>(m.begin(), m.end());
}

// Makes a generic promise from iterators.
template <class T_G_IT>
Promise<T_G_IT>
inline make_promise(T_G_IT begin, T_G_IT end)
{
    return Promise<T_G_IT>(begin,end);
}



// Makes an output promise from a container.
template <class T_G>
Promise<typename T_G::iterator>
inline make_promise_out(const T_G &m)
{
    return Promise_out<typename T_G::iterator>(m.begin(), m.end());
}

// Makes an output promise from iterators.
template <class T_G_IT>
Promise_out<T_G_IT>
inline make_promise_out(T_G_IT begin, T_G_IT end)
{
    return Promise_out<T_G_IT>(begin,end);
}



// Makes a matrix promise from iteratators.
template <class T_M_IT>
MatrixPromise<T_M_IT>
inline make_matrix_promise(T_M_IT begin, T_M_IT end, int nrows, int ncols)
{
    return MatrixPromise<T_M_IT>(begin, end, nrows, ncols);
}

// Makes a matrix promise from a matrix (a container with ncols() method).
template <class T_M>
MatrixPromise<typename T_M::const_iterator>
inline make_matrix_promise(const T_M &m)
{
    return MatrixPromise<typename T_M::const_iterator>(m.begin(), m.end(),
						       m.nrows(), m.ncols());
}

// Makes a matrix promise from a non-matrix container.
template <class T_C>
MatrixPromise<typename T_C::const_iterator>
inline make_matrix_promise(const T_C &m, int nrows, int ncols)
{
    return MatrixPromise<typename T_C::const_iterator>(m.begin(), m.end(),
						       nrows, ncols);
}


}


namespace NTPMai {
    // XXX get rid of this entire naemspace with these t2wo fuctnions..
template <class T_G>
Promise<typename T_G::const_iterator>
inline promise(const T_G &m)
{
    return make_promise(m);
}

// Makes a generic promise from iterators.
template <class T_G_IT>
Promise<T_G_IT>
inline promise(T_G_IT begin, T_G_IT end)
{
    return make_promise(begin,end);
}

}


#include <arithmetic_iterators/ai_add.h>
#include <arithmetic_iterators/ai_multiply.h>
#include <arithmetic_iterators/ai_weight.h>
#include <arithmetic_iterators/ai_constant.h>
#include <arithmetic_iterators/ai_relops.h>
#include <arithmetic_iterators/ai_cast.h>
#include <arithmetic_iterators/ai_negate.h>

#endif // _NTPM_ARITHIT_H
