#ifndef DPUSERTYPE_H
#define DPUSERTYPE_H

/*
 * Definition of class dpuserType:
 * this is a superclass which includes the following DPUSER variable types:
 *   - integer     (lvalue)
 *   - double      (dvalue)
 *   - complex     (*cvalue)   [pointer]
 *   - string      (*svalue)   [pointer]
 *   - stringarray (*arrvalue) [pointer]
 *   - fits        (*fvalue)   [pointer]
 *   - fitsfile    (*ffvalue)  [pointer]
 *
 * This class throws the dpuserTypeException if some operation can't be performed
 */

#include <vector>

#include "dpstring.h"
#include "../dpuser.h"

// BEGIN PARSE FOR DPUSER2C

class dpuserTypeException {
public:
	dpuserTypeException(char *why);
	const char *reason();
private:
	dpString cause;
};

class dpuserType {
public:
	dpuserType();
	dpuserType(const dpuserType &);
	dpuserType(const conValue &);
	dpuserType(const int &);
	dpuserType(const char *);
	dpuserType(const double &);
//    ~dpuserType();    // don't implement this!
                        // dpuserType often contains shallow copies of conValues etc..!!!!

	conValue toConValue();
	dpuserType &fromConValue(const conValue &);

	void initialize();
	void copy(const dpuserType &);
    bool deep_copy(const dpuserType &);
	void clone(const dpuserType &);
	
	double toDouble() const;
	float toFloat();
	long toInt() const;
	dpString toString();
	bool isReal() const;
	bool isInt() const;

    nodeEnum       type;
    long           lvalue;
    double         dvalue;
    dpComplex      *cvalue;
    dpString       *svalue;
    dpStringList   *arrvalue;
    Fits           *fvalue;
    dpString       *ffvalue;
    dpuserTypeList *dparrvalue;


	dpuserType &operator=(const int &i);
	dpuserType &operator=(const long &l);
	dpuserType &operator=(const double &d);
	dpuserType &operator=(const dpComplex &c);
	dpuserType &operator=(const Fits &f);
	dpuserType &operator=(const dpString &s);
	dpuserType &operator=(const dpStringList &a);
	dpuserType &operator=(const dpuserType &a);
	dpuserType &operator=(const conValue &v);

	dpuserType &operator+();
	dpuserType operator-();

	dpuserType operator++(int);
	dpuserType &operator++();
	dpuserType operator--(int);
	dpuserType &operator--();

	dpuserType &operator +=(const dpuserType &arg);
	dpuserType &operator -=(const dpuserType &arg);
	dpuserType &operator *=(const dpuserType &arg);
	dpuserType &operator /=(const dpuserType &arg);

	dpuserType operator+(const dpuserType &arg);
	dpuserType operator-(const dpuserType &arg);
	dpuserType operator*(const dpuserType &arg);
	dpuserType operator/(const dpuserType &arg);
	
	friend dpuserType operator+(const int d, const dpuserType &arg) { dpuserType rv(d); rv += arg; return rv; }
	friend dpuserType operator-(const int d, const dpuserType &arg) { dpuserType rv(d); rv -= arg; return rv; }
	friend dpuserType operator*(const int d, const dpuserType &arg) { dpuserType rv(d); rv *= arg; return rv; }
	friend dpuserType operator/(const int d, const dpuserType &arg) { dpuserType rv(d); rv /= arg; return rv; }
	friend dpuserType operator+(const double d, const dpuserType &arg) { dpuserType rv(d); rv += arg; return rv; }
	friend dpuserType operator-(const double d, const dpuserType &arg) { dpuserType rv(d); rv -= arg; return rv; }
	friend dpuserType operator*(const double d, const dpuserType &arg) { dpuserType rv(d); rv *= arg; return rv; }
	friend dpuserType operator/(const double d, const dpuserType &arg) { dpuserType rv(d); rv /= arg; return rv; }
	
	bool operator<(const dpuserType arg);
	bool operator<=(const dpuserType arg);
	bool operator>(const dpuserType arg);
	bool operator>=(const dpuserType arg);
	bool operator==(const dpuserType arg);
	bool operator!=(const dpuserType arg);

	void append(const dpuserType *v);
	void initappend(const dpuserType *v);	
// 	void append(const double &v);
// 	void initappend(const double &v);
	
	void setrange(const dpuserType &x, const dpuserType &value);
    void setrange(const dpuserType &x1, const dpuserType &x2, const dpuserType &value);
    void setrange(const dpuserType &x1, const dpuserType &x2, const dpuserType &y1, const dpuserType &y2, const dpuserType &value);
    void setrange(const dpuserType &x1, const dpuserType &x2, const dpuserType &y1, const dpuserType &y2, const dpuserType &z1, const dpuserType &z2, const dpuserType &value);

	void addrange(const dpuserType &x, const dpuserType &y, const dpuserType &value);
	void addrange(const dpuserType &x1, const dpuserType &x2, const dpuserType &y1, const dpuserType &y2, const dpuserType &value);
	void addrange(const dpuserType &x1, const dpuserType &x2, const dpuserType &y1, const dpuserType &y2, const dpuserType &z1, const dpuserType &z2, const dpuserType &value);
	void subrange(const dpuserType &x, const dpuserType &y, const dpuserType &value);
	void subrange(const dpuserType &x1, const dpuserType &x2, const dpuserType &y1, const dpuserType &y2, const dpuserType &value);
	void subrange(const dpuserType &x1, const dpuserType &x2, const dpuserType &y1, const dpuserType &y2, const dpuserType &z1, const dpuserType &z2, const dpuserType &value);
	void mulrange(const dpuserType &x, const dpuserType &y, const dpuserType &value);
	void mulrange(const dpuserType &x1, const dpuserType &x2, const dpuserType &y1, const dpuserType &y2, const dpuserType &value);
	void mulrange(const dpuserType &x1, const dpuserType &x2, const dpuserType &y1, const dpuserType &y2, const dpuserType &z1, const dpuserType &z2, const dpuserType &value);
	void divrange(const dpuserType &x, const dpuserType &y, const dpuserType &value);
	void divrange(const dpuserType &x1, const dpuserType &x2, const dpuserType &y1, const dpuserType &y2, const dpuserType &value);
	void divrange(const dpuserType &x1, const dpuserType &x2, const dpuserType &y1, const dpuserType &y2, const dpuserType &z1, const dpuserType &z2, const dpuserType &value);

    const char *getFileName(void) const;
    const char* getColumnName() const;
    bool showAsTable();
};

dpuserType extractrange(const dpuserType &arg, const dpuserType &x1, const dpuserType &x2);
dpuserType extractrange(const dpuserType &arg, const dpuserType &x1, const dpuserType &x2, const dpuserType &y1, const dpuserType &y2);
dpuserType extractrange(const dpuserType &arg, const dpuserType &x1, const dpuserType &x2, const dpuserType &y1, const dpuserType &y2, const dpuserType &z1, const dpuserType &z2);
dpuserType createrange(const dpuserType &start, const dpuserType &end);
dpuserType CREATE(int nops, ...);

class dpuserTypeList : public std::vector<dpuserType*> {
public:
    dpuserTypeList() {}
    dpuserTypeList(const dpuserTypeList &);
    ~dpuserTypeList();
//	void operator +=(const dpStringList &);
//	void operator +=(const char *);
//	dpString first();
    bool ReadFITS(const dpString &);
    bool showAsTable();
//    void makeEmpty();
};

// END PARSE FOR DPUSER2C

#endif /* DPUSERTYPE_H */
