#ifndef GELIB_IMPL_STRUCTURES_H_
#define GELIB_IMPL_STRUCTURES_H_

#include <vector>
#include "Algorithm.h"
#include <iostream>

namespace gelib_impl
{

	namespace Structure
	{

		struct Domain_1d
		{

			static double ERROR_PRECISION()
			{
				return 1e-15;
			}

			void set_lower(double val);

			void set_upper(double val);

			/*
			* return lower bound of domain
			*/
			double lower() const;

			/*
			* return upper bound of domain
			*/
			double upper() const;

			/*
			 * return true if x is in this domain
			 */
			virtual bool is_inside(double x) const;

			/*
			 * Construct a domain with default [-infty, infty] boundaries
			 */
			Domain_1d();

			/*
			 * Construct a domain with given boundaries
			 */
			Domain_1d(double lower, double upper);

			/*
			 * Construct a new domain by expanding an existing domain
			 * infinite boundaries are unchanged
			 */
			Domain_1d(const Domain_1d& d, double expansion);

			/*
			 * Expand this domain on both lower and upper boundaries
			 * infinite boundaries are unchanged
			 */
			void expand(double expansion);

			/*
			 * domain equality check
			 */
			bool operator==(const Domain_1d& d) const;

			/*
			 * clone the domain, allocating memory on the heap, ensure pointer manually deleted
			 */
			virtual Domain_1d* new_clone() const;

			/*
			 * copy constructor
			 */
			Domain_1d(const Domain_1d& domain);

			/*
			 * assignment operator
			 */
			Domain_1d& operator=(const Domain_1d& domain);

			~Domain_1d();

		protected:

			/*
			 * lower and upper bound of domain
			 */
			double* m_boundaries;

			/*
			 * store value of upper bound of domain - lower bound
			 */
			double m_length;
		};

		/*
		 * A Domain_1d with strictly finite boundaries
		 * Undefined behavior if non-finite boundaries set
		 */
		struct Finite_Domain_1d : public Domain_1d
		{

			/*
			 * Construct a domain with given boundaries
			 */
			Finite_Domain_1d(double lower, double upper);

			/*
			 * Construct a new domain by expanding an existing domain
			 * infinite boundaries are unchanged
			 */
			Finite_Domain_1d(const Finite_Domain_1d& d, double expansion);

			bool is_inside(double x) const override;

			/*
			 * clone the domain, allocating memory on the heap, ensure pointer manually deleted
			 */
			Finite_Domain_1d* new_clone() const override;

		private:

			/*
			 * private default constructor
			 */
			Finite_Domain_1d();

		};
	}

}

#endif /* STRUCTURES_H_ */
