#ifndef TABLE_H
#define TABLE_H 1047

# ifndef BLOCK_H
#  include <Block.h>
# endif
# ifndef RANGE_H
#  include <Range.h>
# endif
# ifndef DOUBLET_HXX
#  include <doublet.h>
# endif
# ifndef ARBFUNC_H
#  include <arbfunc.h>
# endif

class table_iterator;

class abstract_table_c: public arbfunc	{
	nRange<double> covered_range;
	TBOOL upok, dnok;

	virtual double x(int i) C = 0;
	virtual double y(int i) C = 0;
	friend class table_iterator;

	protected:
	float upval, dnval;

	BOOL within_data(double x) C	{return x==covered_range;}
	double out_of_range(double x) C;
	abstract_table_c(C nRange<double>& r, BOOL u_o, BOOL d_o);
	abstract_table_c(BOOL u_o, BOOL d_o);
	abstract_table_c() : covered_range(), upok(FALSE), dnok(FALSE)	{}
	virtual ~abstract_table_c()	{}
	void set_cr(C nRange<double>& r)	{covered_range=r;}

	public:
	nRange<double> valid_range() C;
	C nRange<double>& data_range() C	{return covered_range;}
	virtual int size() C	 = 0;
	};

class table_iterator	{
	int i;
	C abstract_table_c *p;
	table_iterator();

	public:
	table_iterator(C abstract_table_c& x) : i(0), p(&x)	{}
	operator int() C	{return i;}
	void next()	{i++;}
	void previous()	{i--;}
	BOOL valid() C	{return i<p->size() && i>=0;}
	void reset()	{i=0;}
	void end()	{i=p->size()-1;}
	double x()	{return p->x(i);}
	double y()	{return p->y(i);}
	};

struct tdata_s {float tslope, tintercept;};
class table_c : public abstract_table_c {
	double off, ratio;
	Block<tdata_s> data;
	double x(int i) C	{return off+i*ratio;}
	double y(int i) C	{return data[i].tintercept;}
	virtual BOOL check_is_ok(double func_result, double check_value) C;

	public:
	double operator()(double x) C;	// use the table here
	int size() C	{return data.size()-1;}

	table_c();
	table_c(C nRange<double>& rr, int n,
					double (*f)(double x, C void *p), C void *p=0,
					BOOL up_ok=FALSE, BOOL dn_ok=FALSE);
		// These constructors are for equally spaced data:
	table_c(C nRange<double>& rr, C Block<double>& x,
					BOOL up_ok=FALSE, BOOL dn_ok=FALSE);
	table_c(C nRange<double>& rr, C Block<float>& x,
					BOOL up_ok=FALSE, BOOL dn_ok=FALSE);
	table_c(C nRange<double>& rr, int n, C float *x,
					BOOL up_ok=FALSE, BOOL dn_ok=FALSE);

	C char *id() C;
	C char *id_check() C;

	char *parse(C char *line);
	BOOL write(FILE *fp) C;

	BOOL all_set() C;	/* Function is ready to be used. */
	BOOL partial_set() C;	/* typ: partly read in from data file*/
	void unset();
	};


typedef doublet<float> table_ddoublet;
class ntable_c : public abstract_table_c {
	double initratio, initoff;
	Block<table_ddoublet> data;
	double x(int i) C	{return data[i].x();}
	double y(int i) C	{return data[i].y();}
	virtual BOOL check_is_ok(double func_result, double check_value) C;

	public:
	double operator()(double x) C;	// use the table here
	int size() C	{return data.size();}

	ntable_c();
	// These constructors are for arbitrarily spaced data:
	ntable_c(C Block<table_ddoublet>& x,
					BOOL up_ok=FALSE, BOOL dn_ok=FALSE);

	C char *id() C;
	C char *id_check() C;

	char *parse(C char *line);
	BOOL write(FILE *fp) C;

	BOOL all_set() C;	/* Function is ready to be used. */
	BOOL partial_set() C;	/* typ: partly read in from data file*/
	void unset();
	};

ntable_c operator+(C abstract_table_c& a, C abstract_table_c& b);
ntable_c operator*(C abstract_table_c& a, C abstract_table_c& b);
ntable_c operator+(C abstract_table_c& a, double b);
ntable_c operator*(C abstract_table_c& a, double b);
ntable_c apply(C abstract_table_c& a, double (*f)(double));
inline ntable_c operator+(double b, C abstract_table_c& a) {return a+b;}
inline ntable_c operator*(double b, C abstract_table_c& a)	{return a*b;}

table_c operator+(C table_c& a, double b);
table_c operator*(C table_c& a, double b);
inline table_c operator+(double b, C table_c& a) {return a+b;}
inline table_c operator*(double b, C table_c& a)	{return a*b;}
#endif
