#ifndef INTERVALSAMPLET_HPP
#define INTERVALSAMPLET_HPP

#include <iostream>

#include <boost/type_traits.hpp>
#include <boost/utility/enable_if.hpp>


template <class T> class intervalsample {
	public:
	T inf;
	T sup;

	intervalsample() {
	}

	template <class C> intervalsample(const C& x, typename boost::enable_if< boost::is_convertible<C, T> >::type* =0) {
		inf = x;
		sup = x;
	}

	template <class C1, class C2> intervalsample(const C1& x, const C2& y, typename boost::enable_if_c< boost::is_convertible<C1, T>::value && boost::is_convertible<C2, T>::value >::type* =0) {
		inf = x;
		sup = y;
	}

	friend intervalsample operator+(const intervalsample& x, const intervalsample& y) {
		intervalsample r;

		r.inf = x.inf + y.inf;
		r.sup = x.sup + y.sup;

		return r;
	}

	template <class C> friend typename boost::enable_if< boost::is_convertible<C, T>, intervalsample >::type operator+(const intervalsample& x, const C& y) {
		intervalsample r;

		r.inf = x.inf + y;
		r.sup = x.sup + y;

		return r;
	}

	template <class C> friend typename boost::enable_if< boost::is_convertible<C, T>, intervalsample >::type operator+(const C& x, const intervalsample& y) {
		intervalsample r;

		r.inf = x + y.inf;
		r.sup = x + y.sup;

		return r;
	}

	friend intervalsample& operator+=(intervalsample& x, const intervalsample& y) {
		x = x + y;
		return x;
	}

	template <class C> friend typename boost::enable_if< boost::is_convertible<C, T>, intervalsample& >::type operator+=(intervalsample& x, const C& y) {
		x.inf += y;
		x.sup += y;
		return x;
	}

	friend intervalsample operator-(const intervalsample& x, const intervalsample& y) {
		intervalsample r;

		r.inf = x.inf - y.sup;
		r.sup = x.sup - y.inf;

		return r;
	}

	template <class C> friend typename boost::enable_if< boost::is_convertible<C, T>, intervalsample >::type operator-(const intervalsample& x, const C& y) {
		intervalsample r;

		r.inf = x.inf - y;
		r.sup = x.sup - y;

		return r;
	}

	template <class C> friend typename boost::enable_if< boost::is_convertible<C, T>, intervalsample >::type operator-(const C& x, const intervalsample& y) {
		intervalsample r;

		r.inf = x - y.sup;
		r.sup = x - y.inf;

		return r;
	}

	friend intervalsample& operator-=(intervalsample& x, const intervalsample& y) {
		x = x - y;
		return x;
	}

	template <class C> friend typename boost::enable_if< boost::is_convertible<C, T>, intervalsample& >::type operator-=(intervalsample& x, const C& y) {
		x.inf = x.inf - y;
		x.sup = x.sup - y;
		return x;
	}

	friend intervalsample operator-(const intervalsample& x) {
		intervalsample r;

		r.sup = - x.inf;
		r.inf = - x.sup;

		return r;
	}

	friend intervalsample operator*(const intervalsample& x, const intervalsample& y) {
		intervalsample r;
		T tmp;

		r.inf = r.sup = x.inf * y.inf;

		tmp = x.inf * y.sup;
		if (tmp < r.inf) r.inf = tmp; 
		if (tmp > r.sup) r.sup = tmp; 

		tmp = x.sup * y.inf;
		if (tmp < r.inf) r.inf = tmp; 
		if (tmp > r.sup) r.sup = tmp; 

		tmp = x.sup * y.sup;
		if (tmp < r.inf) r.inf = tmp; 
		if (tmp > r.sup) r.sup = tmp; 

		return r;
	}

	template <class C> friend typename boost::enable_if< boost::is_convertible<C, T>, intervalsample >::type operator*(const intervalsample& x, const C& y) {
		intervalsample r;
		T tmp;

		r.inf = r.sup = x.inf * y;

		tmp = x.sup * y;
		if (tmp < r.inf) r.inf = tmp; 
		if (tmp > r.sup) r.sup = tmp; 

		return r;
	}

	template <class C> friend typename boost::enable_if< boost::is_convertible<C, T>, intervalsample >::type operator*(const C& x, const intervalsample& y) {
		intervalsample r;
		T tmp;

		r.inf = r.sup = x * y.inf;

		tmp = x * y.sup;
		if (tmp < r.inf) r.inf = tmp; 
		if (tmp > r.sup) r.sup = tmp; 

		return r;
	}

	friend intervalsample& operator*=(intervalsample& x, const intervalsample& y) {
		x = x * y;
		return x;
	}

	template <class C> friend typename boost::enable_if< boost::is_convertible<C, T>, intervalsample& >::type operator*=(intervalsample& x, const C& y) {
		x = x * y;
		return x;
	}

	friend std::ostream& operator<<(std::ostream& s, const intervalsample& x) {
		s << '[' << x.inf << ',' << x.sup << "]";
		return s;
	}
};

#endif // INTERVALSAMPLET_HPP
