#ifndef FUZZY_LIB_H
#define FUZZY_LIB_H

#include <iostream>

#include "interval_lib.h"

template<class T, int N> class fuzzy
{
	public:
		fuzzy();
		fuzzy(T const & v);
		fuzzy(T const * l, T const * u);

		fuzzy<T, N> & operator+=(fuzzy<T, N> const & x);

		interval<T> const & get_cut(int const & a) const;
		void set_cut(int const & a, interval<T> const & i);    

	private:
		interval<T> cut[N];
};

// Constructors
template<class T, int N> inline
fuzzy<T, N>::fuzzy()
{
}

template<class T, int N> inline
fuzzy<T, N>::fuzzy(T const * l, T const * u)
{
	for (int i = 0; i < N; i++)
		cut[i] = interval<T>(l[i], u[i]);
}

template<class T, int N> inline
fuzzy<T, N>::fuzzy(T const & v)
{
	for (int i = 0; i < N; i++)
		cut[i] = interval<T>(v);
}

// Member functions

template<class T, int N> inline
interval<T> const & fuzzy<T, N>::get_cut(int const & a) const
{
	return cut[a];
}

template<class T, int N> inline
void fuzzy<T, N>::set_cut(int const & a, interval<T> const & i)
{
	cut[a] = i;
}

// Stream operator
template<class T, int N> inline
std::ostream & operator<<(std::ostream & out, fuzzy<T, N> const & y)
{
	for(int i = 0; i < N - 1; i++)
		out << "[" << y.get_cut(i).lower() << " , " << y.get_cut(i).upper() << "] -- ";
	out << "[" << y.get_cut(N - 1).lower() << " , " << y.get_cut(N - 1).upper() << "]";
	return out;
}

// Arithmetic operations

// Unary operators
template<class T, int N> inline
fuzzy<T, N> const & operator+(fuzzy<T, N> const & x)
{
	return x;
}

template<class T, int N> inline
fuzzy<T, N> operator-(fuzzy<T, N> const & x)
{
	fuzzy<T, N> temp;
	for (int i = 0; i < N; i++)
		temp.set_cut(i, -x.get_cut(i));
	return temp;
}

// Binary operators
template<class T, int N> inline
fuzzy<T, N> operator+(fuzzy<T, N> const & x, fuzzy<T, N> const & y)
{
	fuzzy<T, N> temp;
	for (int i = 0; i < N; i++)
		temp.set_cut(i, x.get_cut(i) + y.get_cut(i));
	return temp;
}

template<class T, int N> inline
fuzzy<T, N> & fuzzy<T, N>::operator+=(fuzzy<T, N> const & x)
{
	for (int i = 0; i < N; i++)
		this->set_cut(i, this->get_cut(i) + x.get_cut(i));
	return *this;
}

template<class T, int N> inline
fuzzy<T, N> operator-(fuzzy<T, N> const & x, fuzzy<T, N> const & y)
{
	fuzzy<T, N> temp;
	for (int i = 0; i < N; i++)
		temp.set_cut(i, x.get_cut(i) - y.get_cut(i));
	return temp;
}

template<class T, int N> inline
fuzzy<T, N> operator*(fuzzy<T, N> const & x, fuzzy<T, N> const & y)
{
	fuzzy<T, N> temp;
	for (int i = 0; i < N; i++)
		temp.set_cut(i, x.get_cut(i) * y.get_cut(i));
	return temp;
}

#endif
