#ifdef WIN
#pragma warning (disable: 4018) // disable warning for comparing signed and unsigned
#endif /* WIN */

#include <dpstring.h>
#include <dpstringlist.h>
#include <fits.h>

#include "dpuserType.h"
#include "../dpuser_utils.h"
#include "utils.h"
#include "functions.h"

dpuserTypeException::dpuserTypeException(char *why) {
    cause = why;
}

const char* dpuserTypeException::reason() {
    return cause.c_str();
}

dpuserType::dpuserType() {
    initialize();
}

dpuserType::dpuserType(const dpuserType &v) {
    copy(v);
}

dpuserType::dpuserType(const conValue &v) {
    type = v.type;

    lvalue = v.lvalue;
    dvalue = v.dvalue;
    cvalue = v.cvalue;
    svalue = v.svalue;
    arrvalue = v.arrvalue;
    fvalue = v.fvalue;
    ffvalue = v.ffvalue;
    dparrvalue = v.dparrvalue;
}

dpuserType::dpuserType(const int &l) {
    initialize();
    type = typeCon;
    lvalue = l;
}

dpuserType::dpuserType(const char *s) {
    initialize();
    type = typeStr;
    svalue = CreateString(s);
}

dpuserType::dpuserType(const double &d) {
    initialize();
    type = typeDbl;
    dvalue = d;
}

conValue dpuserType::toConValue() {
    conValue rv;
    rv.type = type;
    rv.lvalue = lvalue;
    rv.dvalue = dvalue;
    rv.cvalue = cvalue;
    rv.svalue = svalue;
    rv.arrvalue = arrvalue;
    rv.fvalue = fvalue;
    rv.ffvalue = ffvalue;
    rv.dparrvalue = dparrvalue;

    return rv;
}

dpuserType &dpuserType::fromConValue(const conValue &v) {
    type = v.type;

    lvalue = v.lvalue;
    dvalue = v.dvalue;
    cvalue = v.cvalue;
    svalue = v.svalue;
    arrvalue = v.arrvalue;
    fvalue = v.fvalue;
    ffvalue = v.ffvalue;
    dparrvalue = v.dparrvalue;

    return *this;
}

void dpuserType::initialize() {
    type = typeUnknown;

    lvalue = 0;
    dvalue = 0.0;
    cvalue = NULL;
    svalue = NULL;
    arrvalue = NULL;
    fvalue = NULL;
    ffvalue = NULL;
    dparrvalue = NULL;
}

void dpuserType::copy(const dpuserType &value) {
    type = value.type;

    lvalue = value.lvalue;
    dvalue = value.dvalue;
    cvalue = value.cvalue;
    svalue = value.svalue;
    arrvalue = value.arrvalue;
    fvalue = value.fvalue;
    ffvalue = value.ffvalue;
    dparrvalue = value.dparrvalue;

/*
    initialize();
    type = value.type;
    switch (value.type) {
        case typeCon: lvalue = value.lvalue; break;
        case typeDbl: dvalue = value.dvalue; break;
        case typeFitsFile: ffvalue = value.ffvalue; break;
        case typeStr:
            svalue = CreateString(*value.svalue);
            break;
        case typeFits:
            fvalue = CreateFits();
            if (!fvalue->copy(*value.fvalue)) type = typeUnknown;
            break;
        case typeCom:
            cvalue = CreateComplex(*value.cvalue);
            break;
        case typeStrarr:
            arrvalue = CreateStringArray(*value.arrvalue);
            break;
//        case typeFitsarr:
//            dparrvalue = CreateDpList(*value.dparrvalue);
//            break;
        default: break;
    }
*/
}

bool dpuserType::deep_copy(const dpuserType &value) {
    initialize();
    type = value.type;

    switch (value.type) {
        case typeCon: lvalue = value.lvalue; break;
        case typeDbl: dvalue = value.dvalue; break;
        case typeFitsFile:
            ffvalue = new dpString(*value.ffvalue);
            break;
        case typeStr:
            svalue = new dpString(*value.svalue);
            break;
        case typeFits:
            fvalue = new Fits();
            if (!fvalue->copy(*value.fvalue)) type = typeUnknown;
            break;
        case typeCom:
            cvalue = new dpComplex(*value.cvalue);
            break;
        case typeStrarr:
            arrvalue = new dpStringList(*value.arrvalue);
            break;
        case typeDpArr:
            dparrvalue = new dpuserTypeList(*value.dparrvalue);
            break;
        default:
            type = typeUnknown;
            break;
    }
    if (type == typeUnknown) return FALSE;
    return TRUE;
}

void dpuserType::clone(const dpuserType &value) {
    copy(value);
/*
    initialize();
    type = value.type;
    switch (value.type) {
        case typeCon: lvalue = value.lvalue; break;
        case typeDbl: dvalue = value.dvalue; break;
        case typeFitsFile: ffvalue = value.ffvalue; break;
        case typeStr:
            if (isVariable(value.svalue))
                svalue = CreateString(*value.svalue);
            else
                svalue = value.svalue;
            break;
        case typeFits:
            if (isVariable(value.fvalue) == 1) {
                fvalue = CreateFits();
                if (!fvalue->copy(*value.fvalue)) type = typeUnknown;
            } else
                fvalue = value.fvalue;
            break;
        case typeCom:
            if (isVariable(value.cvalue))
                cvalue = CreateComplex(*value.cvalue);
            else
                cvalue = value.cvalue;
            break;
        case typeStrarr:
            if (isVariable(value.arrvalue))
                arrvalue = CreateStringArray(*value.arrvalue);
            else
                arrvalue = value.arrvalue;
            break;
        default: break;
    }
*/
}

double dpuserType::toDouble() const {
    switch (type) {
        case typeCon: return (double)lvalue; break;
        case typeDbl: return dvalue; break;
        default: return 0.0;
    }
    return 0.0;
}

float dpuserType::toFloat() {
    switch (type) {
        case typeCon: return (float)lvalue; break;
        case typeDbl: return (float)dvalue; break;
        default: return 0.0;
    }
    return 0.0;
}

long dpuserType::toInt() const {
    switch (type) {
        case typeCon: return lvalue; break;
        case typeDbl: return (long)dvalue; break;
        default: return 0;
    }
    return 0;
}

dpString dpuserType::toString() {
    if (type == typeStr) return *svalue;
    else return dpString("");
}

bool dpuserType::isReal() const {
    return (type == typeCon || type == typeDbl);
}

bool dpuserType::isInt() const {
    if (type == typeCon) return TRUE;
    if (type == typeDbl && dvalue == (int)dvalue) return TRUE;
    return FALSE;
}

dpuserType &dpuserType::operator =(const int &i) {
    type = typeCon;
    lvalue = i;
    return *this;
}

dpuserType &dpuserType::operator =(const long &l) {
    type = typeCon;
    lvalue = l;
    return *this;
}

dpuserType &dpuserType::operator =(const double &d) {
    type = typeDbl;
    dvalue = d;
    return *this;
}

dpuserType &dpuserType::operator =(const dpComplex &c) {
    type = typeCom;
    cvalue = CreateComplex(c);
    return *this;
}

dpuserType &dpuserType::operator =(const Fits &f) {
    type = typeFits;
    fvalue = CreateFits();
    fvalue->copy(f);
    return *this;
}

dpuserType &dpuserType::operator =(const dpString &s) {
    type = typeStr;
    svalue = CreateString(s);
    return *this;
}

dpuserType &dpuserType::operator =(const dpStringList &a) {
    type = typeStr;
    arrvalue = CreateStringArray(a);
    return *this;
}

dpuserType &dpuserType::operator =(const dpuserType &a) {
    copy(a);
    return *this;
}

dpuserType &dpuserType::operator =(const conValue &v) {
    type = v.type;

    lvalue = v.lvalue;
    dvalue = v.dvalue;
    cvalue = v.cvalue;
    svalue = v.svalue;
    arrvalue = v.arrvalue;
    fvalue = v.fvalue;
    ffvalue = v.ffvalue;
    dparrvalue = v.dparrvalue;

    return *this;
}

dpuserType &dpuserType::operator +() {
    return *this;
}

dpuserType dpuserType::operator -() {
    dpuserType result(*this);

    switch (type) {
        case typeCon:
            result.lvalue *= -1;
            break;
        case typeDbl:
            result.dvalue *= -1.0;
            break;
        case typeCom:
            *result.cvalue *= -1.0;
            break;
        case typeFitsFile:
            result.type = typeFits;
            result.fvalue = CreateFits();
            if (!result.fvalue->ReadFITS(ffvalue->c_str())) {
//				success = 0;
                break;
            }
        case typeFits:
            *result.fvalue *= -1.0; break;
    }
    return result;
}

dpuserType dpuserType::operator ++(int) {
    dpuserType result(*this);

    switch (type) {
        case typeCon: lvalue++; break;
        case typeDbl: dvalue++; break;
        case typeCom: *cvalue += 1.0; break;
        case typeFits: *fvalue += 1.0; break;
        default: throw dpuserTypeException("Cannot increment this type of variable\n"); break;
    }

    return result;
}

dpuserType &dpuserType::operator ++() {
    switch (type) {
        case typeCon: lvalue++; break;
        case typeDbl: dvalue++; break;
        case typeCom: *cvalue += 1.0; break;
        case typeFits: *fvalue += 1.0; break;
        default: throw dpuserTypeException("Cannot increment this type of variable\n"); break;
    }

    return *this;
}

dpuserType dpuserType::operator --(int) {
    dpuserType result(*this);

    switch (type) {
        case typeCon: lvalue--; break;
        case typeDbl: dvalue--; break;
        case typeCom: *cvalue -= 1.0; break;
        case typeFits: *fvalue -= 1.0; break;
        default: throw dpuserTypeException("Cannot decrement this type of variable\n"); break;
    }

    return result;
}

dpuserType &dpuserType::operator --() {
    switch (type) {
        case typeCon: lvalue--; break;
        case typeDbl: dvalue--; break;
        case typeCom: *cvalue -= 1.0; break;
        case typeFits: *fvalue -= 1.0; break;
        default: throw dpuserTypeException("Cannot decrement this type of variable\n"); break;
    }

    return *this;
}

dpuserType &dpuserType::operator +=(const dpuserType &arg) {
    int n;
    double d;
    dpString *s;

    switch (type) {
        case typeCon: switch(arg.type) {
            case typeCon:
                type = typeCon;
                lvalue = lvalue + arg.lvalue;
                break;
            case typeDbl:
                type = typeDbl;
                dvalue = lvalue + arg.dvalue;
                break;
            case typeCom:
                d = (double)lvalue;
                copy(arg);
                *cvalue += d;
                break;
            case typeStr:
                type = typeStr;
                svalue = CreateString(lvalue);
                *svalue += *arg.svalue;
                break;
            case typeFits:
                d = (double)lvalue;
                copy(arg);
                *fvalue += d;
                break;
            case typeFitsFile:
                type = typeFits;
                fvalue = CreateFits();
                if (!fvalue->ReadFITS(arg.ffvalue->c_str())) type = typeUnknown;
                else *fvalue += (double)arg.lvalue;
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot add a string array to a number\n");
                break;
            default:
                throw dpuserTypeException("The arguments do not match\n");
                break;
        }
    break;

        case typeDbl: switch(arg.type) {
            case typeCon:
                type = typeDbl;
                dvalue = dvalue + arg.lvalue;
                break;
            case typeDbl:
                type = typeDbl;
                dvalue = dvalue + arg.dvalue;
                break;
            case typeCom:
                d = dvalue;
                copy(arg);
                *cvalue += d;
                break;
            case typeStr:
                type = typeStr;
                svalue = CreateString(dvalue);
                *svalue += *arg.svalue;
                break;
            case typeFits:
                d = dvalue;
                copy(arg);
                *fvalue += d;
                break;
            case typeFitsFile:
                type = typeFits;
                fvalue = CreateFits();
                if (!fvalue->ReadFITS(arg.ffvalue->c_str())) type = typeUnknown;
                else *fvalue += dvalue;
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot add a string array to a real number\n");
                break;
            default:
                throw dpuserTypeException("Cannot add this type to a real number\n");
                break;
        }
    break;

        case typeCom: switch(arg.type) {
            case typeCon:
                *cvalue += arg.lvalue;
                break;
            case typeDbl:
                *cvalue += arg.dvalue;
                break;
            case typeCom:
                *cvalue += *arg.cvalue;
                break;
            case typeStr:
                type = typeStr;
                svalue = CreateString(*cvalue);
                *svalue += *arg.svalue;
                break;
            case typeFits:
//					CloneValue(*arg2, result);
//					*result.fvalue += *arg1->cvalue;
                dp_output("Cannot add a matrix to a complex number\n");
                break;
            case typeFitsFile:
//					result.type = typeFits;
//					result.fvalue = new Fits();
//					result.fvalue->ReadFITS(arg2->ffvalue->c_str());
//					*result.fvalue += *arg1->cvalue;
                throw dpuserTypeException("Cannot add a FITS file to a complex number\n");
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot add a string array to a complex number\n");
                break;
            default:
                throw dpuserTypeException("Cannot add this type to a complex number\n");
                break;
        }
    break;

        case typeStr: switch(arg.type) {
            case typeCon:
                *svalue += *CreateString(arg.lvalue);
                break;
            case typeDbl:
                *svalue += *CreateString(arg.dvalue);
                break;
            case typeCom:
                *svalue += FormatComplexQString(*arg.cvalue);
                break;
            case typeStr:
                *svalue += *arg.svalue;
                break;
            case typeFits:
//					CloneValue(*arg2, result);
//					*result.fvalue += *arg1->cvalue;
                throw dpuserTypeException("Cannot add a matrix to a string\n");
                break;
            case typeFitsFile:
//					result.type = typeFits;
//					result.fvalue = new Fits();
//					result.fvalue->ReadFITS(arg2->ffvalue->c_str());
//					*result.fvalue += *arg1->cvalue;
                throw dpuserTypeException("Cannot add a FITS file to a string\n");
                break;
            case typeStrarr:
                s = svalue;
                copy(arg);
                arrvalue->prepend(*s);
                break;
            default:
                throw dpuserTypeException("Cannot add this type to a string\n");
                break;
        }
    break;

        case typeFits: switch(arg.type) {
            case typeCon:
                *fvalue += (double)arg.lvalue;
                break;
            case typeDbl:
                *fvalue += arg.dvalue;
                break;
            case typeCom:
                throw dpuserTypeException("Cannot add a complex number to a matrix\n");
//					CloneValue(*arg1, &result);
//					*result.fvalue += *arg2->cvalue;
                break;
            case typeStr:
                throw dpuserTypeException("Cannot add a string to a matrix\n");
                break;
            case typeFits:
                *fvalue += *arg.fvalue;
                break;
            case typeFitsFile: {
                Fits a;
                if (!a.ReadFITS(arg.ffvalue->c_str())) type = typeUnknown;
                else *fvalue += a;
            }
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot add a string array to a matrix\n");
                break;
            default:
                throw dpuserTypeException("Cannot add this type to a matrix\n");
                break;
        }
    break;

        case typeStrarr: switch(arg.type) {
            case typeCon:
                throw dpuserTypeException("Cannot add an integer number to a string array\n");
                break;
            case typeDbl:
                throw dpuserTypeException("Cannot add a real number to a string array\n");
                break;
            case typeCom:
                throw dpuserTypeException("Cannot add a complex number to a string array\n");
                break;
            case typeStr:
                arrvalue->append(*arg.svalue);
                break;
            case typeFits:
                throw dpuserTypeException("Cannot add a matrix to a string array\n");
                break;
            case typeFitsFile:
                throw dpuserTypeException("Cannot add a FITS file to a string array\n");
                break;
            case typeStrarr:
                for (n = 0; n < arg.arrvalue->count(); n++) arrvalue->append((*arg.arrvalue)[n]);
                break;
            default:
                throw dpuserTypeException("Cannot add this type to a string array\n");
                break;
        }
    break;

        default:
            throw dpuserTypeException("Invalid arguments to operator '+='\n");
            break;
    }
    return *this;
}

dpuserType &dpuserType::operator -=(const dpuserType &arg) {
    double d;
//	dpString *s;

    switch (type) {
        case typeCon: switch(arg.type) {
            case typeCon:
                type = typeCon;
                lvalue = lvalue - arg.lvalue;
                break;
            case typeDbl:
                type = typeDbl;
                dvalue = lvalue - arg.dvalue;
                break;
            case typeCom:
                d = (double)lvalue;
                copy(arg);
                *cvalue *= -1.;
                *cvalue += d;
                break;
            case typeStr:
                throw dpuserTypeException("Cannot subtract a string from an integer number\n");
                break;
            case typeFits:
                d = (double)lvalue;
                copy(arg);
                *fvalue *= -1.;
                *fvalue += d;
                break;
            case typeFitsFile:
                type = typeFits;
                fvalue = CreateFits();
                if (!fvalue->ReadFITS(arg.ffvalue->c_str())) type = typeUnknown;
                else {
                    *fvalue *= -1.;
                    *fvalue += (double)lvalue;
                }
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot subtract a string array from an integer number\n");
                break;
            default:
                throw dpuserTypeException("Cannot subtract this type from an integer number\n");
                break;
        }
            break;
        case typeDbl: switch(arg.type) {
            case typeCon:
                type = typeDbl;
                dvalue = dvalue - arg.lvalue;
                break;
            case typeDbl:
                type = typeDbl;
                dvalue = dvalue - arg.dvalue;
                break;
            case typeCom:
                d = dvalue;
                copy(arg);
                *cvalue *= -1.;
                *cvalue += d;
                break;
            case typeStr:
                throw dpuserTypeException("Cannot subtract a string from a real number\n");
                break;
            case typeFits:
                d = dvalue;
                copy(arg);
                *fvalue *= -1.;
                *fvalue += dvalue;
                break;
            case typeFitsFile:
                type = typeFits;
                fvalue = CreateFits();
                if (!fvalue->ReadFITS(arg.ffvalue->c_str())) type = typeUnknown;
                else {
                    *fvalue *= -1.;
                    *fvalue += dvalue;
                }
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot subtract a string array from a real number\n");
                break;
            default:
                throw dpuserTypeException("Cannot subtract this type from a real number\n");
                break;
        }
            break;
        case typeCom: switch(arg.type) {
            case typeCon:
                *cvalue -= arg.lvalue;
                break;
            case typeDbl:
                *cvalue -= arg.dvalue;
                break;
            case typeCom:
                *cvalue -= *arg.cvalue;
                break;
            case typeStr:
                throw dpuserTypeException("Cannot subtract a string from a complex number\n");
                break;
            case typeFits:
//					CloneValue(*arg2, result);
//					*result.fvalue += -*arg1->cvalue;
                throw dpuserTypeException("Cannot subtract a matrix from a complex number\n");
                break;
            case typeFitsFile:
//					result.type = typeFits;
//					result.fvalue = new Fits();
//					result.fvalue->ReadFITS(arg2->ffvalue->c_str());
//					*result.fvalue += -*arg1->cvalue;
                throw dpuserTypeException("Cannot subtract a FITS file from a complex number\n");
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot subtract a string array from a complex number\n");
                break;
            default:
                throw dpuserTypeException("Cannot subtract this type from a complex number\n");
                break;
        }
            break;
        case typeStr:
            throw dpuserTypeException("Cannot subtract anything from a string\n");
            break;
        case typeFits: switch(arg.type) {
            case typeCon:
                *fvalue -= (double)arg.lvalue;
                break;
            case typeDbl:
                *fvalue -= arg.dvalue;
                break;
            case typeCom:
                throw dpuserTypeException("Cannot subtract a complex number from a matrix\n");
//					CloneValue(*arg1, &result);
//					*result.fvalue -= *arg2->cvalue;
                break;
            case typeStr:
                throw dpuserTypeException("Cannot subtract a string from a matrix\n");
                break;
            case typeFits:
                *fvalue -= *arg.fvalue;
                break;
            case typeFitsFile: {
                Fits a;
                if (!a.ReadFITS(arg.ffvalue->c_str())) type = typeUnknown;
                else *fvalue -= a;
            }
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot subtract a string array from a matrix\n");
                break;
            default:
                throw dpuserTypeException("Cannot subtract this type from a matrix\n");
                break;
        }
            break;
        case typeStrarr:
            throw dpuserTypeException("Cannot subtract anything from a string array\n");
            break;
        default:
            throw dpuserTypeException("Invalid arguments to operator '-='\n");
            break;
    }

    return *this;
}

dpuserType &dpuserType::operator *=(const dpuserType &arg) {
    double d;

    switch (type) {
        case typeCon: switch(arg.type) {
            case typeCon:
                type = typeCon;
                lvalue = lvalue * arg.lvalue;
                break;
            case typeDbl:
                type = typeDbl;
                dvalue = lvalue * arg.dvalue;
                break;
            case typeCom:
                d = (double)lvalue;
                copy(arg);
                *cvalue *= d;
                break;
            case typeStr:
                throw dpuserTypeException("Cannot multiply a string to an integer number\n");
                break;
            case typeFits:
                d = (double)lvalue;
                copy(arg);
                *fvalue *= d;
                break;
            case typeFitsFile:
                type = typeFits;
                fvalue = CreateFits();
                if (!fvalue->ReadFITS(arg.ffvalue->c_str())) type = typeUnknown;
                else *fvalue *= (double)lvalue;
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot multiply a string array to an integer number\n");
                break;
            default:
                throw dpuserTypeException("Cannot multiply this type to an integer number\n");
                break;
        }
            break;
        case typeDbl: switch(arg.type) {
            case typeCon:
                type = typeDbl;
                dvalue = dvalue * arg.lvalue;
                break;
            case typeDbl:
                type = typeDbl;
                dvalue = dvalue * arg.dvalue;
                break;
            case typeCom:
                d = dvalue;
                copy(arg);
                *cvalue *= dvalue;
                break;
            case typeStr:
                throw dpuserTypeException("Cannot multiply a string to a real number\n");
                break;
            case typeFits:
                d = dvalue;
                copy(arg);
                *fvalue *= d;
                break;
            case typeFitsFile:
                type = typeFits;
                fvalue = CreateFits();
                if (!fvalue->ReadFITS(arg.ffvalue->c_str())) type = typeUnknown;
                else *fvalue *= dvalue;
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot multiply a string array to a real number\n");
                break;
            default:
                throw dpuserTypeException("Cannot multiply this type to a real number\n");
                break;
        }
            break;
        case typeCom: switch(arg.type) {
            case typeCon:
                *cvalue *= arg.lvalue;
                break;
            case typeDbl:
                *cvalue *= arg.dvalue;
                break;
            case typeCom:
                *cvalue *= *arg.cvalue;
                break;
            case typeStr:
                throw dpuserTypeException("Cannot multiply a string to a complex number\n");
                break;
            case typeFits:
//					CloneValue(*arg2, result);
//					*result.fvalue *= *arg1->cvalue;
                throw dpuserTypeException("Cannot multiply a matrix to a complex number\n");
                break;
            case typeFitsFile:
//					result.type = typeFits;
//					result.fvalue = new Fits();
//					result.fvalue->ReadFITS(arg2->ffvalue->c_str());
//					*result.fvalue *= *arg1->cvalue;
                throw dpuserTypeException("Cannot multiply a FITS file to a complex number\n");
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot multiply a string array to a complex number\n");
                break;
            default:
                throw dpuserTypeException("Cannot multiply this type to a complex number\n");
                break;
        }
            break;
        case typeStr:
            throw dpuserTypeException("Cannot multiply anything to a string\n");
            break;
        case typeFits: switch(arg.type) {
            case typeCon:
                *fvalue *= (double)arg.lvalue;
                break;
            case typeDbl:
                *fvalue *= arg.dvalue;
                break;
            case typeCom:
                throw dpuserTypeException("Cannot multiply a complex number to a matrix\n");
//					CloneValue(*arg1, &result);
//					*result.fvalue *= *arg2->cvalue;
                break;
            case typeStr:
                throw dpuserTypeException("Cannot multiply a string to a matrix\n");
                break;
            case typeFits:
                *fvalue *= *arg.fvalue;
                break;
            case typeFitsFile: {
                Fits a;
                if (!a.ReadFITS(arg.ffvalue->c_str())) type = typeUnknown;
                else *fvalue *= a;
            }
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot multiply a string array to a matrix\n");
                break;
            default:
                throw dpuserTypeException("Cannot multiply this type to a matrix\n");
                break;
        }
            break;
        case typeStrarr:
            throw dpuserTypeException("Cannot multiply anything to a string array\n");
            break;
        default:
            throw dpuserTypeException("Invalid arguments to operator '*='\n");
            break;
    }
    return *this;
}

dpuserType &dpuserType::operator /=(const dpuserType &arg) {
    double d;

    switch (type) {
        case typeCon: switch(arg.type) {
            case typeCon:
                type = typeDbl;
                dvalue = (double)lvalue / (double)arg.lvalue;
                break;
            case typeDbl:
                type = typeDbl;
                dvalue = lvalue / arg.dvalue;
                break;
            case typeCom:
                type = typeCom;
                cvalue = CreateComplex();
                *cvalue = lvalue / *arg.cvalue;
                break;
            case typeStr:
                throw dpuserTypeException("Cannot divide an integer number by a string\n");
                break;
            case typeFits:
                d = dvalue;
                copy(arg);
                fvalue->invert();
                *fvalue *= d;
                break;
            case typeFitsFile:
                type = typeFits;
                fvalue = CreateFits();
                if (!fvalue->ReadFITS(arg.ffvalue->c_str())) type = typeUnknown;
                else {
                    fvalue->invert();
                    *fvalue *= (double)lvalue;
                }
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot divide an integer number by a string array\n");
                break;
            default:
                throw dpuserTypeException("Cannot divide an integer number by this type\n");
                break;
        }
            break;
        case typeDbl: switch(arg.type) {
            case typeCon:
                type = typeDbl;
                dvalue = dvalue / arg.lvalue;
                break;
            case typeDbl:
                type = typeDbl;
                dvalue = dvalue / arg.dvalue;
                break;
            case typeCom:
                d = dvalue;
                copy(arg);
                *cvalue = d / *arg.cvalue;
                break;
            case typeStr:
                throw dpuserTypeException("Cannot divide a real number by a string\n");
                break;
            case typeFits:
                d = dvalue;
                copy(arg);
                fvalue->invert();
                *fvalue *= d;
                break;
            case typeFitsFile:
                type = typeFits;
                fvalue = CreateFits();
                if (!fvalue->ReadFITS(arg.ffvalue->c_str())) type = typeUnknown;
                else {
                    fvalue->invert();
                    *fvalue *= dvalue;
                }
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot divide a real number by a string array\n");
                break;
            default:
                throw dpuserTypeException("Cannot divide a real number by this type\n");
                break;
        }
            break;
        case typeCom: switch(arg.type) {
            case typeCon:
                *cvalue /= arg.lvalue;
                break;
            case typeDbl:
                *cvalue /= arg.dvalue;
                break;
            case typeCom:
                *cvalue /= *arg.cvalue;
                break;
            case typeStr:
                throw dpuserTypeException("Cannot divide a complex number by a string\n");
                break;
            case typeFits:
//					CloneValue(*arg2, result);
//					result.fvalue->invert();
//					*result.fvalue *= *arg1->cvalue;
                throw dpuserTypeException("Cannot divide a complex number by a matrix\n");
                break;
            case typeFitsFile:
//					result.type = typeFits;
//					result.fvalue = new Fits();
//					result.fvalue->ReadFITS(arg2->ffvalue->c_str());
//					*result.fvalue += -*arg1->cvalue;
                throw dpuserTypeException("Cannot divide a complex number by a FITS file\n");
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot divide a complex number by a string array\n");
                break;
            default:
                throw dpuserTypeException("Cannot divide a complex number by this type\n");
                break;
        }
            break;
        case typeStr:
            throw dpuserTypeException("Cannot divide a string by anything\n");
            break;
        case typeFits: switch(arg.type) {
            case typeCon:
                *fvalue /= (double)arg.lvalue;
                break;
            case typeDbl:
                *fvalue /= arg.dvalue;
                break;
            case typeCom:
                throw dpuserTypeException("Cannot divide a matrix by a complex number\n");
//					CloneValue(*arg1, &result);
//					*result.fvalue /= *arg2->cvalue;
                break;
            case typeStr:
                throw dpuserTypeException("Cannot divide a matrix by a string\n");
                break;
            case typeFits:
                *fvalue += *arg.fvalue;
                break;
            case typeFitsFile: {
                Fits a;
                if (a.ReadFITS(arg.ffvalue->c_str())) type = typeUnknown;
                else *fvalue /= a;
            }
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot divide a matrix by a string array\n");
                break;
            default:
                throw dpuserTypeException("Cannot divide a matrix by this type\n");
                break;
        }
            break;
        case typeStrarr:
            throw dpuserTypeException("Cannot divide a string array by anything\n");
            break;
        default:
            throw dpuserTypeException("Invalid arguments to operator '/='\n");
            break;
    }
    return *this;
}

dpuserType dpuserType::operator +(const dpuserType &arg) {
    dpuserType result;
    int n;

    switch (type) {
        case typeCon: switch(arg.type) {
            case typeCon:
                result.type = typeCon;
                result.lvalue = lvalue + arg.lvalue;
                break;
            case typeDbl:
                result.type = typeDbl;
                result.dvalue = lvalue + arg.dvalue;
                break;
            case typeCom:
                result.copy(arg);
                *result.cvalue += lvalue;
                break;
            case typeStr:
                result.type = typeStr;
                result.svalue = CreateString(lvalue);
                *result.svalue += *arg.svalue;
                break;
            case typeFits:
                result.copy(arg);
                *result.fvalue += (double)lvalue;
                break;
            case typeFitsFile:
                result.type = typeFits;
                result.fvalue = CreateFits();
                if (!result.fvalue->ReadFITS(arg.ffvalue->c_str())) result.type = typeUnknown;
                else *result.fvalue += (double)arg.lvalue;
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot add a string array to a number\n");
                break;
            default:
                throw dpuserTypeException("The arguments do not match\n");
                break;
        }
    break;

        case typeDbl: switch(arg.type) {
            case typeCon:
                result.type = typeDbl;
                result.dvalue = dvalue + arg.lvalue;
                break;
            case typeDbl:
                result.type = typeDbl;
                result.dvalue = dvalue + arg.dvalue;
                break;
            case typeCom:
                result.copy(arg);
                *result.cvalue += dvalue;
                break;
            case typeStr:
                result.type = typeStr;
                result.svalue = CreateString(dvalue);
                *result.svalue += *arg.svalue;
                break;
            case typeFits:
                result.copy(arg);
                *result.fvalue += dvalue;
                break;
            case typeFitsFile:
                result.type = typeFits;
                result.fvalue = CreateFits();
                if (!result.fvalue->ReadFITS(arg.ffvalue->c_str())) result.type = typeUnknown;
                else *result.fvalue += dvalue;
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot add a string array to a real number\n");
                break;
            default:
                throw dpuserTypeException("Cannot add this type to a real number\n");
                break;
        }
    break;

        case typeCom: switch(arg.type) {
            case typeCon:
                result.copy(*this);
                *result.cvalue += arg.lvalue;
                break;
            case typeDbl:
                result.copy(*this);
                *result.cvalue += arg.dvalue;
                break;
            case typeCom:
                result.copy(*this);
                *result.cvalue += *arg.cvalue;
                break;
            case typeStr:
                result.type = typeStr;
                result.svalue = CreateString(*cvalue);
                *result.svalue += *arg.svalue;
                break;
            case typeFits:
//					CloneValue(*arg2, result);
//					*result.fvalue += *arg1->cvalue;
                dp_output("Cannot add a matrix to a complex number\n");
                break;
            case typeFitsFile:
//					result.type = typeFits;
//					result.fvalue = new Fits();
//					result.fvalue->ReadFITS(arg2->ffvalue->c_str());
//					*result.fvalue += *arg1->cvalue;
                throw dpuserTypeException("Cannot add a FITS file to a complex number\n");
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot add a string array to a complex number\n");
                break;
            default:
                throw dpuserTypeException("Cannot add this type to a complex number\n");
                break;
        }
    break;

        case typeStr: switch(arg.type) {
            case typeCon:
                result.copy(*this);
                *result.svalue += *CreateString(arg.lvalue);
                break;
            case typeDbl:
                result.copy(*this);
                *result.svalue += *CreateString(arg.dvalue);
                break;
            case typeCom:
                result.copy(*this);
                *result.svalue += FormatComplexQString(*arg.cvalue);
                break;
            case typeStr:
                result.copy(*this);
                *result.svalue += *arg.svalue;
                break;
            case typeFits:
//					CloneValue(*arg2, result);
//					*result.fvalue += *arg1->cvalue;
                throw dpuserTypeException("Cannot add a matrix to a string\n");
                break;
            case typeFitsFile:
//					result.type = typeFits;
//					result.fvalue = new Fits();
//					result.fvalue->ReadFITS(arg2->ffvalue->c_str());
//					*result.fvalue += *arg1->cvalue;
                throw dpuserTypeException("Cannot add a FITS file to a string\n");
                break;
            case typeStrarr:
                result.copy(arg);
                result.arrvalue->prepend(*svalue);
                break;
            default:
                throw dpuserTypeException("Cannot add this type to a string\n");
                break;
        }
    break;

        case typeFits: switch(arg.type) {
            case typeCon:
                result.copy(*this);
                *result.fvalue += (double)arg.lvalue;
                break;
            case typeDbl:
                result.copy(*this);
                *result.fvalue += arg.dvalue;
                break;
            case typeCom:
                throw dpuserTypeException("Cannot add a complex number to a matrix\n");
//					CloneValue(*arg1, &result);
//					*result.fvalue += *arg2->cvalue;
                break;
            case typeStr:
                throw dpuserTypeException("Cannot add a string to a matrix\n");
                break;
            case typeFits:
                result.copy(*this);
                *result.fvalue += *arg.fvalue;
                break;
            case typeFitsFile: {
                Fits a;
                result.type = typeFits;
                result.copy(*this);
                if (!a.ReadFITS(arg.ffvalue->c_str())) result.type = typeUnknown;
                else *result.fvalue += a;
            }
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot add a string array to a matrix\n");
                break;
            default:
                throw dpuserTypeException("Cannot add this type to a matrix\n");
                break;
        }
    break;

        case typeFitsFile: switch(arg.type) {
            case typeCon:
                result.type = typeFits;
                result.fvalue = CreateFits();
                if (!result.fvalue->ReadFITS(ffvalue->c_str())) result.type = typeUnknown;
                else *result.fvalue += (double)arg.lvalue;
                break;
            case typeDbl:
                result.type = typeFits;
                result.fvalue = CreateFits();
                if (!result.fvalue->ReadFITS(ffvalue->c_str())) result.type = typeUnknown;
                else *result.fvalue += arg.dvalue;
                break;
            case typeCom:
                throw dpuserTypeException("Cannot add a complex number to a FITS file\n");
//					result.type = typeFits;
//					result.fvalue = new Fits();
//					if (!result.fvalue->ReadFITS(arg1->ffvalue->c_str())) result.type = typeUnknown;
//					else *result.fvalue += *arg2->cvalue;
                break;
            case typeStr:
                throw dpuserTypeException("Cannot add a string to a FITS file\n");
                break;
            case typeFits:
                result.type = typeFits;
                result.fvalue = CreateFits();
                if (!result.fvalue->ReadFITS(ffvalue->c_str())) result.type = typeUnknown;
                else *result.fvalue += *arg.fvalue;
                break;
            case typeFitsFile:
                result.type = typeFits;
                result.fvalue = CreateFits();
                if (!result.fvalue->ReadFITS(ffvalue->c_str())) result.type = typeUnknown;
                else {
                    Fits a;
                    if (!a.ReadFITS(arg.ffvalue->c_str())) result.type = typeUnknown;
                    else *result.fvalue += a;
                }
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot add a string array to a FITS file\n");
                break;
            default:
                throw dpuserTypeException("Cannot add this type to a FITS file\n");
                break;
        }
    break;

        case typeStrarr: switch(arg.type) {
            case typeCon:
                throw dpuserTypeException("Cannot add an integer number to a string array\n");
                break;
            case typeDbl:
                throw dpuserTypeException("Cannot add a real number to a string array\n");
                break;
            case typeCom:
                throw dpuserTypeException("Cannot add a complex number to a string array\n");
                break;
            case typeStr:
                result.copy(*this);
                result.arrvalue->append(*arg.svalue);
                break;
            case typeFits:
                throw dpuserTypeException("Cannot add a matrix to a string array\n");
                break;
            case typeFitsFile:
                throw dpuserTypeException("Cannot add a FITS file to a string array\n");
                break;
            case typeStrarr:
                result.copy(*this);
                for (n = 0; n < arg.arrvalue->count(); n++) result.arrvalue->append((*arg.arrvalue)[n]);
                break;
            default:
                throw dpuserTypeException("Cannot add this type to a string array\n");
                break;
        }
    break;

        default:
            throw dpuserTypeException("Invalid arguments to operator '+'\n");
            break;
    }
    return result;
}

dpuserType dpuserType::operator -(const dpuserType &arg) {
    dpuserType result;

    switch (type) {
        case typeCon: switch(arg.type) {
            case typeCon:
                result.type = typeCon;
                result.lvalue = lvalue - arg.lvalue;
                break;
            case typeDbl:
                result.type = typeDbl;
                result.dvalue = lvalue - arg.dvalue;
                break;
            case typeCom:
                result.copy(arg);
                *result.cvalue *= -1.;
                *result.cvalue += lvalue;
                break;
            case typeStr:
                throw dpuserTypeException("Cannot subtract a string from an integer number\n");
                break;
            case typeFits:
                result.copy(arg);
                *result.fvalue *= -1.;
                *result.fvalue += (double)lvalue;
                break;
            case typeFitsFile:
                result.type = typeFits;
                result.fvalue = CreateFits();
                if (!result.fvalue->ReadFITS(arg.ffvalue->c_str())) result.type = typeUnknown;
                else {
                    *result.fvalue *= -1.;
                    *result.fvalue += (double)lvalue;
                }
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot subtract a string array from an integer number\n");
                break;
            default:
                throw dpuserTypeException("Cannot subtract this type from an integer number\n");
                break;
        }
            break;
        case typeDbl: switch(arg.type) {
            case typeCon:
                result.type = typeDbl;
                result.dvalue = dvalue - arg.lvalue;
                break;
            case typeDbl:
                result.type = typeDbl;
                result.dvalue = dvalue - arg.dvalue;
                break;
            case typeCom:
                result.copy(arg);
                *result.cvalue *= -1.;
                *result.cvalue += dvalue;
                break;
            case typeStr:
                throw dpuserTypeException("Cannot subtract a string from a real number\n");
                break;
            case typeFits:
                result.copy(arg);
                *result.fvalue *= -1.;
                *result.fvalue += dvalue;
                break;
            case typeFitsFile:
                result.type = typeFits;
                result.fvalue = CreateFits();
                if (!result.fvalue->ReadFITS(arg.ffvalue->c_str())) result.type = typeUnknown;
                else {
                    *result.fvalue *= -1.;
                    *result.fvalue += dvalue;
                }
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot subtract a string array from a real number\n");
                break;
            default:
                throw dpuserTypeException("Cannot subtract this type from a real number\n");
                break;
        }
            break;
        case typeCom: switch(arg.type) {
            case typeCon:
                result.copy(*this);
                *result.cvalue -= arg.lvalue;
                break;
            case typeDbl:
                result.copy(*this);
                *result.cvalue -= arg.dvalue;
                break;
            case typeCom:
                result.copy(*this);
                *result.cvalue -= *arg.cvalue;
                break;
            case typeStr:
                throw dpuserTypeException("Cannot subtract a string from a complex number\n");
                break;
            case typeFits:
//					CloneValue(*arg2, result);
//					*result.fvalue += -*arg1->cvalue;
                throw dpuserTypeException("Cannot subtract a matrix from a complex number\n");
                break;
            case typeFitsFile:
//					result.type = typeFits;
//					result.fvalue = new Fits();
//					result.fvalue->ReadFITS(arg2->ffvalue->c_str());
//					*result.fvalue += -*arg1->cvalue;
                throw dpuserTypeException("Cannot subtract a FITS file from a complex number\n");
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot subtract a string array from a complex number\n");
                break;
            default:
                throw dpuserTypeException("Cannot subtract this type from a complex number\n");
                break;
        }
            break;
        case typeStr:
            throw dpuserTypeException("Cannot subtract anything from a string\n");
            break;
        case typeFits: switch(arg.type) {
            case typeCon:
                result.copy(*this);
                *result.fvalue -= (double)arg.lvalue;
                break;
            case typeDbl:
                result.copy(*this);
                *result.fvalue -= arg.dvalue;
                break;
            case typeCom:
                throw dpuserTypeException("Cannot subtract a complex number from a matrix\n");
//					CloneValue(*arg1, &result);
//					*result.fvalue -= *arg2->cvalue;
                break;
            case typeStr:
                throw dpuserTypeException("Cannot subtract a string from a matrix\n");
                break;
            case typeFits:
                result.copy(*this);
                *result.fvalue -= *arg.fvalue;
                break;
            case typeFitsFile: {
                Fits a;
                result.type = typeFits;
                result.copy(*this);
                if (!a.ReadFITS(arg.ffvalue->c_str())) result.type = typeUnknown;
                else *result.fvalue -= a;
            }
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot subtract a string array from a matrix\n");
                break;
            default:
                throw dpuserTypeException("Cannot subtract this type from a matrix\n");
                break;
        }
            break;
        case typeFitsFile: switch(arg.type) {
            case typeCon:
                result.type = typeFits;
                result.fvalue = CreateFits();
                if (!result.fvalue->ReadFITS(ffvalue->c_str())) result.type = typeUnknown;
                else *result.fvalue -= (double)arg.lvalue;
                break;
            case typeDbl:
                result.type = typeFits;
                result.fvalue = CreateFits();
                if (!result.fvalue->ReadFITS(ffvalue->c_str())) result.type = typeUnknown;
                else *result.fvalue -= arg.dvalue;
                break;
            case typeCom:
                throw dpuserTypeException("Cannot subtract a complex number from a FITS file\n");
//					result.type = typeFits;
//					result.fvalue = new Fits();
//					if (!result.fvalue->ReadFITS(arg1->ffvalue->c_str())) result.type = typeUnknown;
//					else *result.fvalue -= *arg2->cvalue;
                break;
            case typeStr:
                throw dpuserTypeException("Cannot subtract a string from a FITS file\n");
                break;
            case typeFits:
                result.type = typeFits;
                result.fvalue = CreateFits();
                if (!result.fvalue->ReadFITS(ffvalue->c_str())) result.type = typeUnknown;
                else *result.fvalue -= *arg.fvalue;
                break;
            case typeFitsFile:
                result.type = typeFits;
                result.fvalue = CreateFits();
                if (!result.fvalue->ReadFITS(ffvalue->c_str())) result.type = typeUnknown;
                else {
                    Fits a;
                    if (!a.ReadFITS(arg.ffvalue->c_str())) result.type = typeUnknown;
                    else *result.fvalue -= a;
                }
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot subtract a string array from a FITS file\n");
                break;
            default:
                throw dpuserTypeException("Cannot subtract this type from a FITS file\n");
                break;
        }
            break;
        case typeStrarr:
            throw dpuserTypeException("Cannot subtract anything from a string array\n");
            break;
        default:
            throw dpuserTypeException("Invalid arguments to operator '-'\n");
            break;
    }

    return result;
}

dpuserType dpuserType::operator *(const dpuserType &arg) {
    dpuserType result;

    switch (type) {
        case typeCon: switch(arg.type) {
            case typeCon:
                result.type = typeCon;
                result.lvalue = lvalue * arg.lvalue;
                break;
            case typeDbl:
                result.type = typeDbl;
                result.dvalue = lvalue * arg.dvalue;
                break;
            case typeCom:
                result.copy(arg);
                *result.cvalue *= lvalue;
                break;
            case typeStr:
                throw dpuserTypeException("Cannot multiply a string to an integer number\n");
                break;
            case typeFits:
                result.copy(arg);
                *result.fvalue *= (double)lvalue;
                break;
            case typeFitsFile:
                result.type = typeFits;
                result.fvalue = CreateFits();
                if (!result.fvalue->ReadFITS(arg.ffvalue->c_str())) result.type = typeUnknown;
                else *result.fvalue *= (double)lvalue;
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot multiply a string array to an integer number\n");
                break;
            default:
                throw dpuserTypeException("Cannot multiply this type to an integer number\n");
                break;
        }
            break;
        case typeDbl: switch(arg.type) {
            case typeCon:
                result.type = typeDbl;
                result.dvalue = dvalue * arg.lvalue;
                break;
            case typeDbl:
                result.type = typeDbl;
                result.dvalue = dvalue * arg.dvalue;
                break;
            case typeCom:
                result.copy(arg);
                *result.cvalue *= dvalue;
                break;
            case typeStr:
                throw dpuserTypeException("Cannot multiply a string to a real number\n");
                break;
            case typeFits:
                result.copy(arg);
                *result.fvalue *= dvalue;
                break;
            case typeFitsFile:
                result.type = typeFits;
                result.fvalue = CreateFits();
                if (!result.fvalue->ReadFITS(arg.ffvalue->c_str())) result.type = typeUnknown;
                else *result.fvalue *= dvalue;
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot multiply a string array to a real number\n");
                break;
            default:
                throw dpuserTypeException("Cannot multiply this type to a real number\n");
                break;
        }
            break;
        case typeCom: switch(arg.type) {
            case typeCon:
                result.copy(*this);
                *result.cvalue *= arg.lvalue;
                break;
            case typeDbl:
                result.copy(*this);
                *result.cvalue *= arg.dvalue;
                break;
            case typeCom:
                result.copy(*this);
                *result.cvalue *= *arg.cvalue;
                break;
            case typeStr:
                throw dpuserTypeException("Cannot multiply a string to a complex number\n");
                break;
            case typeFits:
//					CloneValue(*arg2, result);
//					*result.fvalue *= *arg1->cvalue;
                throw dpuserTypeException("Cannot multiply a matrix to a complex number\n");
                break;
            case typeFitsFile:
//					result.type = typeFits;
//					result.fvalue = new Fits();
//					result.fvalue->ReadFITS(arg2->ffvalue->c_str());
//					*result.fvalue *= *arg1->cvalue;
                throw dpuserTypeException("Cannot multiply a FITS file to a complex number\n");
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot multiply a string array to a complex number\n");
                break;
            default:
                throw dpuserTypeException("Cannot multiply this type to a complex number\n");
                break;
        }
            break;
        case typeStr:
            throw dpuserTypeException("Cannot multiply anything to a string\n");
            break;
        case typeFits: switch(arg.type) {
            case typeCon:
                result.copy(*this);
                *result.fvalue *= (double)arg.lvalue;
                break;
            case typeDbl:
                result.copy(*this);
                *result.fvalue *= arg.dvalue;
                break;
            case typeCom:
                throw dpuserTypeException("Cannot multiply a complex number to a matrix\n");
//					CloneValue(*arg1, &result);
//					*result.fvalue *= *arg2->cvalue;
                break;
            case typeStr:
                throw dpuserTypeException("Cannot multiply a string to a matrix\n");
                break;
            case typeFits:
                result.copy(*this);
                *result.fvalue *= *arg.fvalue;
                break;
            case typeFitsFile: {
                Fits a;
                result.type = typeFits;
                result.copy(*this);
                if (!a.ReadFITS(arg.ffvalue->c_str())) result.type = typeUnknown;
                else *result.fvalue *= a;
            }
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot multiply a string array to a matrix\n");
                break;
            default:
                throw dpuserTypeException("Cannot multiply this type to a matrix\n");
                break;
        }
            break;
        case typeFitsFile: switch(arg.type) {
            case typeCon:
                result.type = typeFits;
                result.fvalue = CreateFits();
                if (!result.fvalue->ReadFITS(ffvalue->c_str())) result.type = typeUnknown;
                else *result.fvalue *= (double)arg.lvalue;
                break;
            case typeDbl:
                result.type = typeFits;
                result.fvalue = CreateFits();
                if (!result.fvalue->ReadFITS(ffvalue->c_str())) result.type = typeUnknown;
                else *result.fvalue *= arg.dvalue;
                break;
            case typeCom:
                throw dpuserTypeException("Cannot multiply a complex number to a FITS file\n");
//					result.type = typeFits;
//					result.fvalue = new Fits();
//					if (!result.fvalue->ReadFITS(arg1->ffvalue->c_str())) result.type = typeUnknown;
//					else *result.fvalue *= *arg2->cvalue;
                break;
            case typeStr:
                throw dpuserTypeException("Cannot multiply a string to a FITS file\n");
                break;
            case typeFits:
                result.type = typeFits;
                result.fvalue = CreateFits();
                if (!result.fvalue->ReadFITS(ffvalue->c_str())) result.type = typeUnknown;
                else *result.fvalue *= *arg.fvalue;
                break;
            case typeFitsFile:
                result.type = typeFits;
                result.fvalue = CreateFits();
                if (!result.fvalue->ReadFITS(ffvalue->c_str())) result.type = typeUnknown;
                else {
                    Fits a;
                    if (!a.ReadFITS(arg.ffvalue->c_str())) result.type = typeUnknown;
                    else *result.fvalue *= a;
                }
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot multiply a string array to a FITS file\n");
                break;
            default:
                throw dpuserTypeException("Cannot multiply this type to a FITS file\n");
                break;
        }
            break;
        case typeStrarr:
            throw dpuserTypeException("Cannot multiply anything to a string array\n");
            break;
        default:
            throw dpuserTypeException("Invalid arguments to operator '*'\n");
            break;
    }
    return result;
}

dpuserType dpuserType::operator /(const dpuserType &arg) {
    dpuserType result;

    switch (type) {
        case typeCon: switch(arg.type) {
            case typeCon:
                result.type = typeDbl;
                result.dvalue = (double)lvalue / (double)arg.lvalue;
                break;
            case typeDbl:
                result.type = typeDbl;
                result.dvalue = lvalue / arg.dvalue;
                break;
            case typeCom:
                result.type = typeCom;
                result.cvalue = CreateComplex();
                *result.cvalue = lvalue / *arg.cvalue;
                break;
            case typeStr:
                throw dpuserTypeException("Cannot divide an integer number by a string\n");
                break;
            case typeFits:
                result.copy(arg);
                result.fvalue->invert();
                *result.fvalue *= (double)lvalue;
                break;
            case typeFitsFile:
                result.type = typeFits;
                result.fvalue = CreateFits();
                if (!result.fvalue->ReadFITS(arg.ffvalue->c_str())) result.type = typeUnknown;
                else {
                    result.fvalue->invert();
                    *result.fvalue *= (double)lvalue;
                }
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot divide an integer number by a string array\n");
                break;
            default:
                throw dpuserTypeException("Cannot divide an integer number by this type\n");
                break;
        }
            break;
        case typeDbl: switch(arg.type) {
            case typeCon:
                result.type = typeDbl;
                result.dvalue = dvalue / arg.lvalue;
                break;
            case typeDbl:
                result.type = typeDbl;
                result.dvalue = dvalue / arg.dvalue;
                break;
            case typeCom:
                result.copy(arg);
                *result.cvalue = dvalue / *arg.cvalue;
                break;
            case typeStr:
                throw dpuserTypeException("Cannot divide a real number by a string\n");
                break;
            case typeFits:
                result.copy(arg);
                result.fvalue->invert();
                *result.fvalue *= dvalue;
                break;
            case typeFitsFile:
                result.type = typeFits;
                result.fvalue = CreateFits();
                if (!result.fvalue->ReadFITS(arg.ffvalue->c_str())) result.type = typeUnknown;
                else {
                    result.fvalue->invert();
                    *result.fvalue *= dvalue;
                }
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot divide a real number by a string array\n");
                break;
            default:
                throw dpuserTypeException("Cannot divide a real number by this type\n");
                break;
        }
            break;
        case typeCom: switch(arg.type) {
            case typeCon:
                result.copy(*this);
                *result.cvalue /= arg.lvalue;
                break;
            case typeDbl:
                result.copy(*this);
                *result.cvalue /= arg.dvalue;
                break;
            case typeCom:
                result.copy(*this);
                *result.cvalue /= *arg.cvalue;
                break;
            case typeStr:
                throw dpuserTypeException("Cannot divide a complex number by a string\n");
                break;
            case typeFits:
//					CloneValue(*arg2, result);
//					result.fvalue->invert();
//					*result.fvalue *= *arg1->cvalue;
                throw dpuserTypeException("Cannot divide a complex number by a matrix\n");
                break;
            case typeFitsFile:
//					result.type = typeFits;
//					result.fvalue = new Fits();
//					result.fvalue->ReadFITS(arg2->ffvalue->c_str());
//					*result.fvalue += -*arg1->cvalue;
                throw dpuserTypeException("Cannot divide a complex number by a FITS file\n");
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot divide a complex number by a string array\n");
                break;
            default:
                throw dpuserTypeException("Cannot divide a complex number by this type\n");
                break;
        }
            break;
        case typeStr:
            throw dpuserTypeException("Cannot divide a string by anything\n");
            break;
        case typeFits: switch(arg.type) {
            case typeCon:
                result.copy(*this);
                *result.fvalue /= (double)arg.lvalue;
                break;
            case typeDbl:
                result.copy(*this);
                *result.fvalue /= arg.dvalue;
                break;
            case typeCom:
                throw dpuserTypeException("Cannot divide a matrix by a complex number\n");
//					CloneValue(*arg1, &result);
//					*result.fvalue /= *arg2->cvalue;
                break;
            case typeStr:
                throw dpuserTypeException("Cannot divide a matrix by a string\n");
                break;
            case typeFits:
                result.copy(*this);
                *result.fvalue /= *arg.fvalue;
                break;
            case typeFitsFile: {
                Fits a;
                result.type = typeFits;
                result.copy(*this);
                if (a.ReadFITS(arg.ffvalue->c_str())) result.type = typeUnknown;
                else *result.fvalue /= a;
            }
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot divide a matrix by a string array\n");
                break;
            default:
                throw dpuserTypeException("Cannot divide a matrix by this type\n");
                break;
        }
            break;
        case typeFitsFile: switch(arg.type) {
            case typeCon:
                result.type = typeFits;
                result.fvalue = CreateFits();
                if (!result.fvalue->ReadFITS(ffvalue->c_str())) result.type = typeUnknown;
                else *result.fvalue /= (double)arg.lvalue;
                break;
            case typeDbl:
                result.type = typeFits;
                result.fvalue = CreateFits();
                if (!result.fvalue->ReadFITS(ffvalue->c_str())) result.type = typeUnknown;
                else *result.fvalue /= arg.dvalue;
                break;
            case typeCom:
                throw dpuserTypeException("Cannot divide a FITS file by a complex number\n");
//					result.type = typeFits;
//					result.fvalue = new Fits();
//					if (!result.fvalue->ReadFITS(arg1->ffvalue->c_str())) result.type = typeUnknown;
//					else *result.fvalue /= *arg2->cvalue;
                break;
            case typeStr:
                throw dpuserTypeException("Cannot divide a FITS file by a string\n");
                break;
            case typeFits:
                result.type = typeFits;
                result.fvalue = CreateFits();
                if (!result.fvalue->ReadFITS(ffvalue->c_str())) result.type = typeUnknown;
                else *result.fvalue /= *arg.fvalue;
                break;
            case typeFitsFile:
                result.type = typeFits;
                result.fvalue = CreateFits();
                if (!result.fvalue->ReadFITS(ffvalue->c_str())) result.type = typeUnknown;
                else {
                    Fits a;
                    if (!a.ReadFITS(arg.ffvalue->c_str())) result.type = typeUnknown;
                    else *result.fvalue /= a;
                }
                break;
            case typeStrarr:
                throw dpuserTypeException("Cannot divide a FITS file by a string array\n");
                break;
            default:
                throw dpuserTypeException("Cannot divide a FITS file by this type\n");
                break;
        }
            break;
        case typeStrarr:
            throw dpuserTypeException("Cannot divide a string array by anything\n");
            break;
        default:
            throw dpuserTypeException("Invalid arguments to operator '/'\n");
            break;
    }
    return result;
}

bool dpuserType::operator<(dpuserType arg) {
    switch (type) {
        case typeCon:
            switch (arg.type) {
                case typeCon:
                    return lvalue < arg.lvalue;
                    break;
                case typeDbl:
                    return lvalue < arg.dvalue;
                    break;
                default:
                    return TRUE;
                    break;
            }

        case typeDbl:
            switch (arg.type) {
                case typeCon:
                    return dvalue < arg.lvalue;
                    break;
                case typeDbl:
                    return dvalue < arg.dvalue;
                    break;
                default:
                    return TRUE;
                    break;
            }
    }
    return FALSE;
}

bool dpuserType::operator<=(dpuserType arg) {
    switch (type) {
        case typeCon:
            switch (arg.type) {
                case typeCon:
                    return lvalue <= arg.lvalue;
                    break;
                case typeDbl:
                    return lvalue <= arg.dvalue;
                    break;
                default:
                    return TRUE;
                    break;
            }

        case typeDbl:
            switch (arg.type) {
                case typeCon:
                    return dvalue <= arg.lvalue;
                    break;
                case typeDbl:
                    return dvalue <= arg.dvalue;
                    break;
                default:
                    return TRUE;
                    break;
            }
    }
    return FALSE;
}

bool dpuserType::operator>(dpuserType arg) {
    switch (type) {
        case typeCon:
            switch (arg.type) {
                case typeCon:
                    return lvalue > arg.lvalue;
                    break;
                case typeDbl:
                    return lvalue > arg.dvalue;
                    break;
                default:
                    return TRUE;
                    break;
            }

        case typeDbl:
            switch (arg.type) {
                case typeCon:
                    return dvalue > arg.lvalue;
                    break;
                case typeDbl:
                    return dvalue > arg.dvalue;
                    break;
                default:
                    return TRUE;
                    break;
            }
    }
    return FALSE;
}

bool dpuserType::operator>=(dpuserType arg) {
    switch (type) {
        case typeCon:
            switch (arg.type) {
                case typeCon:
                    return lvalue >= arg.lvalue;
                    break;
                case typeDbl:
                    return lvalue >= arg.dvalue;
                    break;
                default:
                    return TRUE;
                    break;
            }

        case typeDbl:
            switch (arg.type) {
                case typeCon:
                    return dvalue >= arg.lvalue;
                    break;
                case typeDbl:
                    return dvalue >= arg.dvalue;
                    break;
                default:
                    return TRUE;
                    break;
            }
    }
    return FALSE;
}

bool dpuserType::operator==(dpuserType arg) {
    switch (type) {
        case typeCon:
            switch (arg.type) {
                case typeCon:
                    return lvalue == arg.lvalue;
                    break;
                case typeDbl:
                    return lvalue == arg.dvalue;
                    break;
                default:
                    return TRUE;
                    break;
            }

        case typeDbl:
            switch (arg.type) {
                case typeCon:
                    return dvalue == arg.lvalue;
                    break;
                case typeDbl:
                    return dvalue == arg.dvalue;
                    break;
                default:
                    return TRUE;
                    break;
            }
        default:
            throw dpuserTypeException("Wrong argument for '==' operator\n");
    }
}

bool dpuserType::operator!=(dpuserType arg) {
    switch (type) {
        case typeCon:
            switch (arg.type) {
                case typeCon:
                    return lvalue != arg.lvalue;
                    break;
                case typeDbl:
                    return lvalue != arg.dvalue;
                    break;
                default:
                    return TRUE;
                    break;
            }

        case typeDbl:
            switch (arg.type) {
                case typeCon:
                    return dvalue != arg.lvalue;
                    break;
                case typeDbl:
                    return dvalue != arg.dvalue;
                    break;
                default:
                    return TRUE;
                    break;
            }
    }
    return FALSE;
}

// used in function CREATE() in functions.ccp (dpuser2c.cpp)
// all numbers (int, float, double) are stored as typeDbl
void dpuserType::append(const dpuserType *v) {
    if (type == typeUnknown) {
        if (v->type == typeDbl) {
            fvalue = CreateFits();
            type = typeFits;
            fvalue->create(1, 1, R8);
            fvalue->r8data[0] = v->dvalue;
        }
        else if (v->type == typeCon) {
            fvalue = CreateFits();
            type = typeFits;
            fvalue->create(1, 1, R8);
            fvalue->r8data[0] = (double)v->lvalue;
        }
        else if (v->type == typeFits) {
            fvalue = CreateFits();
            type = typeFits;
            fvalue->create(v->fvalue->Naxis(1), v->fvalue->Naxis(2), v->fvalue->Naxis(3));
            fvalue->setRange(*v->fvalue, 1, v->fvalue->Naxis(1), 1, 1, 1, 1);
        }
        else if (v->type == typeStr) {
            arrvalue = CreateStringArray();
            type = typeStrarr;
            arrvalue->append(*v->svalue);
        }
     } else if (type == typeFits){
        if (v->type == typeDbl) {
            fvalue->resize(fvalue->Nelements() + 1);
            fvalue->r8data[fvalue->Nelements() - 1] = v->dvalue;
        }
        else if (v->type == typeCon) {
            fvalue->resize(fvalue->Nelements() + 1);
            fvalue->r8data[fvalue->Nelements() - 1] = (double)v->lvalue;
        }
        else if (v->type == typeFits)
        {
            // check sizes of actual fits and new fits to append
            int actualSize_x = fvalue->Naxis(1);
            int actualSize_y = fvalue->Naxis(2);
            int newSize_x = v->fvalue->Naxis(1);

            // resize actual fits accordingly
            if (newSize_x > actualSize_x)
                fvalue->resize(newSize_x, actualSize_y + 1);
            else
                fvalue->resize(actualSize_x, actualSize_y + 1);
            fvalue->setRange(*v->fvalue, 1, newSize_x, actualSize_y + 1, actualSize_y + 1, 1, 1);
        }
        else
            throw dpuserTypeException("First element of array/vector was a number. Can't append another type afterwards!\n");
    } else if (type ==  typeStrarr) {
        if (v->type == typeStr) {
            arrvalue->append(*v->svalue);
        }
        else
            throw dpuserTypeException("First element of array/vector was a string. Can't append another type afterwards!\n");
    }
}

void dpuserType::setrange(const dpuserType &x, const dpuserType &value) {
    setrange(x, x, value);
}

void dpuserType::setrange(const dpuserType &x1, const dpuserType &x2, const dpuserType &value) {
    if (type != typeFits)
        throw dpuserTypeException("Wrong argument for setting range.\n");

    if (!x1.isInt() && x1.type != typeFits)
        throw dpuserTypeException("Wrong argument for setting range.\n");
    if (!x2.isInt() && x2.type != typeFits)
        throw dpuserTypeException("Wrong argument for setting range.\n");

    if (x1.type == typeFits) {
        if (!value.isReal())
            throw dpuserTypeException("Wrong argument for setting range.\n");
        fvalue->setRawRange(value.toDouble(), *x1.fvalue);
    } else {
        if (x1.toInt() == x2.toInt()) {
            if (x1.toInt() == -1) {
                if (value.type == typeFits) fvalue->setRange(*value.fvalue, -1, -1, 1, 1, 1, 1);
                else fvalue->setRange(value.toDouble(), -1, -1, 1, 1, 1, 1);
            } else {
                if (!value.isReal())
                    throw dpuserTypeException("Wrong argument for setting range.\n");
                fvalue->setValue(value.toDouble(), x1.toInt(), 1);
            }
        } else {
            if (value.isReal()) {
                fvalue->setRawRange(value.toDouble(), x1.toInt(), x2.toInt());
            } else if (value.type == typeFits && value.fvalue->Nelements() == x2.toInt() - x1.toInt() + 1) {
                fvalue->setRange(*value.fvalue, x1.toInt(), x2.toInt(), 1, 1, 1, 1);
            } else {
                throw dpuserTypeException("Wrong argument for setting range.\n");
            }
        }
    }
}

void dpuserType::setrange(const dpuserType &x1, const dpuserType &x2, const dpuserType &y1, const dpuserType &y2, const dpuserType &value) {
    if (type != typeFits)
        throw dpuserTypeException("Wrong argument for setting range.\n");
    if (!x1.isInt() || !x2.isInt() || !y1.isInt() || !y2.isInt())
        throw dpuserTypeException("Wrong argument for setting range.\n");

    if (value.isReal()) {
        fvalue->setRange(value.toDouble(), x1.toInt(), x2.toInt(), y1.toInt(), y2.toInt(), 1, 1);
    } else if (value.type == typeFits) {
        fvalue->setRange(*value.fvalue, x1.toInt(), x2.toInt(), y1.toInt(), y2.toInt(), 1, 1);
    } else {
        throw dpuserTypeException("Wrong argument for setting range.\n");
    }
}

void dpuserType::setrange(const dpuserType &x1, const dpuserType &x2, const dpuserType &y1, const dpuserType &y2, const dpuserType &z1, const dpuserType &z2, const dpuserType &value) {
    if (type != typeFits)
        throw dpuserTypeException("Wrong argument for setting range.\n");
    if (!x1.isInt() || !x2.isInt() || !y1.isInt() || !y2.isInt() || !z1.isInt() || !z2.isInt())
        throw dpuserTypeException("Wrong argument for setting range.\n");

    if (value.isReal()) {
        fvalue->setRange(value.toDouble(), x1.toInt(), x2.toInt(), y1.toInt(), y2.toInt(), z1.toInt(), z2.toInt());
    } else if (value.type == typeFits) {
        fvalue->setRange(*value.fvalue, x1.toInt(), x2.toInt(), y1.toInt(), y2.toInt(), z1.toInt(), z2.toInt());
    } else {
        throw dpuserTypeException("Wrong argument for setting range.\n");
    }
}

void dpuserType::addrange(const dpuserType &x, const dpuserType &y, const dpuserType &value) {
    if (type != typeFits)
        throw dpuserTypeException("Wrong argument for adding range.\n");
    if (!x.isInt() || !y.isInt())
        throw dpuserTypeException("Wrong argument for adding range.\n");
    if (!value.isReal() && value.type != typeFits)
        throw dpuserTypeException("Wrong argument for adding range.\n");

    long n[2];
    n[0] = x.toInt();
    n[1] = y.toInt();

/* adjust index to indexBase */
    if (indexBase == 0) {
        for (int i = 0; i < 2; i++) n[i]++;
    }

    if (value.isReal()) {
        fvalue->addRange(value.toDouble(), 2, n);
    } else {
        fvalue->addRange(*value.fvalue, 2, n);
    }
}

void dpuserType::addrange(const dpuserType &x1, const dpuserType &x2, const dpuserType &y1, const dpuserType &y2, const dpuserType &value) {
    if (type != typeFits)
        throw dpuserTypeException("1Wrong argument for adding range.\n");
    if (!x1.isInt() || !y1.isInt() || !x2.isInt() || !y2.isInt())
        throw dpuserTypeException("2Wrong argument for adding range.\n");
    if (!value.isReal() && value.type != typeFits)
        throw dpuserTypeException("3Wrong argument for adding range.\n");

    long n[4];
    n[0] = x1.toInt();
    n[1] = x2.toInt();
    n[2] = y1.toInt();
    n[3] = y2.toInt();

/* adjust index to indexBase */
    if (indexBase == 0) {
        for (int i = 0; i < 4; i++) n[i]++;
    }

    if (value.isReal()) {
        fvalue->addRange(value.toDouble(), 4, n);
    } else {
        fvalue->addRange(*value.fvalue, 4, n);
    }
}

void dpuserType::addrange(const dpuserType &x1, const dpuserType &x2, const dpuserType &y1, const dpuserType &y2, const dpuserType &z1, const dpuserType &z2, const dpuserType &value) {
    if (type != typeFits)
        throw dpuserTypeException("1Wrong argument for adding range.\n");
    if (!x1.isInt() || !y1.isInt() || !z1.isInt() || !x2.isInt() || !y2.isInt() || !z2.isInt())
        throw dpuserTypeException("2Wrong argument for adding range.\n");
    if (!value.isReal() && value.type != typeFits)
        throw dpuserTypeException("3Wrong argument for adding range.\n");

    long n[6];
    n[0] = x1.toInt();
    n[1] = x2.toInt();
    n[2] = y1.toInt();
    n[3] = y2.toInt();
    n[4] = z1.toInt();
    n[5] = z2.toInt();

/* adjust index to indexBase */
    if (indexBase == 0) {
        for (int i = 0; i < 6; i++) n[i]++;
    }

    if (value.isReal()) {
        fvalue->addRange(value.toDouble(), 6, n);
    } else {
        fvalue->addRange(*value.fvalue, 6, n);
    }
}

void dpuserType::subrange(const dpuserType &x, const dpuserType &y, const dpuserType &value) {
    if (type != typeFits)
        throw dpuserTypeException("Wrong argument for adding range.\n");
    if (!x.isInt() || !y.isInt())
        throw dpuserTypeException("Wrong argument for adding range.\n");
    if (!value.isReal() && value.type != typeFits)
        throw dpuserTypeException("Wrong argument for adding range.\n");

    long n[2];
    n[0] = x.toInt();
    n[1] = y.toInt();

/* adjust index to indexBase */
    if (indexBase == 0) {
        for (int i = 0; i < 2; i++) n[i]++;
    }

    if (value.isReal()) {
        fvalue->subRange(value.toDouble(), 2, n);
    } else {
        fvalue->subRange(*value.fvalue, 2, n);
    }
}

void dpuserType::subrange(const dpuserType &x1, const dpuserType &x2, const dpuserType &y1, const dpuserType &y2, const dpuserType &value) {
    if (type != typeFits)
        throw dpuserTypeException("1Wrong argument for adding range.\n");
    if (!x1.isInt() || !y1.isInt() || !x2.isInt() || !y2.isInt())
        throw dpuserTypeException("2Wrong argument for adding range.\n");
    if (!value.isReal() && value.type != typeFits)
        throw dpuserTypeException("3Wrong argument for adding range.\n");

    long n[4];
    n[0] = x1.toInt();
    n[1] = x2.toInt();
    n[2] = y1.toInt();
    n[3] = y2.toInt();

/* adjust index to indexBase */
    if (indexBase == 0) {
        for (int i = 0; i < 4; i++) n[i]++;
    }

    if (value.isReal()) {
        fvalue->subRange(value.toDouble(), 4, n);
    } else {
        fvalue->subRange(*value.fvalue, 4, n);
    }
}

void dpuserType::subrange(const dpuserType &x1, const dpuserType &x2, const dpuserType &y1, const dpuserType &y2, const dpuserType &z1, const dpuserType &z2, const dpuserType &value) {
    if (type != typeFits)
        throw dpuserTypeException("1Wrong argument for adding range.\n");
    if (!x1.isInt() || !y1.isInt() || !z1.isInt() || !x2.isInt() || !y2.isInt() || !z2.isInt())
        throw dpuserTypeException("2Wrong argument for adding range.\n");
    if (!value.isReal() && value.type != typeFits)
        throw dpuserTypeException("3Wrong argument for adding range.\n");

    long n[6];
    n[0] = x1.toInt();
    n[1] = x2.toInt();
    n[2] = y1.toInt();
    n[3] = y2.toInt();
    n[4] = z1.toInt();
    n[5] = z2.toInt();

/* adjust index to indexBase */
    if (indexBase == 0) {
        for (int i = 0; i < 6; i++) n[i]++;
    }

    if (value.isReal()) {
        fvalue->subRange(value.toDouble(), 6, n);
    } else {
        fvalue->subRange(*value.fvalue, 6, n);
    }
}

void dpuserType::mulrange(const dpuserType &x, const dpuserType &y, const dpuserType &value) {
    if (type != typeFits)
        throw dpuserTypeException("Wrong argument for adding range.\n");
    if (!x.isInt() || !y.isInt())
        throw dpuserTypeException("Wrong argument for adding range.\n");
    if (!value.isReal() && value.type != typeFits)
        throw dpuserTypeException("Wrong argument for adding range.\n");

    long n[2];
    n[0] = x.toInt();
    n[1] = y.toInt();

/* adjust index to indexBase */
    if (indexBase == 0) {
        for (int i = 0; i < 2; i++) n[i]++;
    }

    if (value.isReal()) {
        fvalue->mulRange(value.toDouble(), 2, n);
    } else {
        fvalue->mulRange(*value.fvalue, 2, n);
    }
}

void dpuserType::mulrange(const dpuserType &x1, const dpuserType &x2, const dpuserType &y1, const dpuserType &y2, const dpuserType &value) {
    if (type != typeFits)
        throw dpuserTypeException("1Wrong argument for adding range.\n");
    if (!x1.isInt() || !y1.isInt() || !x2.isInt() || !y2.isInt())
        throw dpuserTypeException("2Wrong argument for adding range.\n");
    if (!value.isReal() && value.type != typeFits)
        throw dpuserTypeException("3Wrong argument for adding range.\n");

    long n[4];
    n[0] = x1.toInt();
    n[1] = x2.toInt();
    n[2] = y1.toInt();
    n[3] = y2.toInt();

/* adjust index to indexBase */
    if (indexBase == 0) {
        for (int i = 0; i < 4; i++) n[i]++;
    }

    if (value.isReal()) {
        fvalue->mulRange(value.toDouble(), 4, n);
    } else {
        fvalue->mulRange(*value.fvalue, 4, n);
    }
}

void dpuserType::mulrange(const dpuserType &x1, const dpuserType &x2, const dpuserType &y1, const dpuserType &y2, const dpuserType &z1, const dpuserType &z2, const dpuserType &value) {
    if (type != typeFits)
        throw dpuserTypeException("1Wrong argument for adding range.\n");
    if (!x1.isInt() || !y1.isInt() || !z1.isInt() || !x2.isInt() || !y2.isInt() || !z2.isInt())
        throw dpuserTypeException("2Wrong argument for adding range.\n");
    if (!value.isReal() && value.type != typeFits)
        throw dpuserTypeException("3Wrong argument for adding range.\n");

    long n[6];
    n[0] = x1.toInt();
    n[1] = x2.toInt();
    n[2] = y1.toInt();
    n[3] = y2.toInt();
    n[4] = z1.toInt();
    n[5] = z2.toInt();

/* adjust index to indexBase */
    if (indexBase == 0) {
        for (int i = 0; i < 6; i++) n[i]++;
    }

    if (value.isReal()) {
        fvalue->mulRange(value.toDouble(), 6, n);
    } else {
        fvalue->mulRange(*value.fvalue, 6, n);
    }
}

void dpuserType::divrange(const dpuserType &x, const dpuserType &y, const dpuserType &value) {
    if (type != typeFits)
        throw dpuserTypeException("Wrong argument for adding range.\n");
    if (!x.isInt() || !y.isInt())
        throw dpuserTypeException("Wrong argument for adding range.\n");
    if (!value.isReal() && value.type != typeFits)
        throw dpuserTypeException("Wrong argument for adding range.\n");

    long n[2];
    n[0] = x.toInt();
    n[1] = y.toInt();

/* adjust index to indexBase */
    if (indexBase == 0) {
        for (int i = 0; i < 2; i++) n[i]++;
    }

    if (value.isReal()) {
        fvalue->divRange(value.toDouble(), 2, n);
    } else {
        fvalue->divRange(*value.fvalue, 2, n);
    }
}

void dpuserType::divrange(const dpuserType &x1, const dpuserType &x2, const dpuserType &y1, const dpuserType &y2, const dpuserType &value) {
    if (type != typeFits)
        throw dpuserTypeException("1Wrong argument for adding range.\n");
    if (!x1.isInt() || !y1.isInt() || !x2.isInt() || !y2.isInt())
        throw dpuserTypeException("2Wrong argument for adding range.\n");
    if (!value.isReal() && value.type != typeFits)
        throw dpuserTypeException("3Wrong argument for adding range.\n");

    long n[4];
    n[0] = x1.toInt();
    n[1] = x2.toInt();
    n[2] = y1.toInt();
    n[3] = y2.toInt();

/* adjust index to indexBase */
    if (indexBase == 0) {
        for (int i = 0; i < 4; i++) n[i]++;
    }

    if (value.isReal()) {
        fvalue->divRange(value.toDouble(), 4, n);
    } else {
        fvalue->divRange(*value.fvalue, 4, n);
    }
}

void dpuserType::divrange(const dpuserType &x1, const dpuserType &x2, const dpuserType &y1, const dpuserType &y2, const dpuserType &z1, const dpuserType &z2, const dpuserType &value) {
    if (type != typeFits)
        throw dpuserTypeException("1Wrong argument for adding range.\n");
    if (!x1.isInt() || !y1.isInt() || !z1.isInt() || !x2.isInt() || !y2.isInt() || !z2.isInt())
        throw dpuserTypeException("2Wrong argument for adding range.\n");
    if (!value.isReal() && value.type != typeFits)
        throw dpuserTypeException("3Wrong argument for adding range.\n");

    long n[6];
    n[0] = x1.toInt();
    n[1] = x2.toInt();
    n[2] = y1.toInt();
    n[3] = y2.toInt();
    n[4] = z1.toInt();
    n[5] = z2.toInt();

/* adjust index to indexBase */
    if (indexBase == 0) {
        for (int i = 0; i < 6; i++) n[i]++;
    }

    if (value.isReal()) {
        fvalue->divRange(value.toDouble(), 6, n);
    } else {
        fvalue->divRange(*value.fvalue, 6, n);
    }
}

dpuserType extractrange(const dpuserType &arg, const dpuserType &x1, const dpuserType &x2) {
    dpuserType rv;
    long l1 = 0, l2 = 0, l;

    if (x1.type == typeCon) l1 = x1.lvalue;
    else if (x1.type == typeDbl) l1 = (long)(x1.dvalue + .5);
    if (x2.type == typeCon) l2 = x2.lvalue;
    else if (x2.type == typeDbl) l2 = (long)(x2.dvalue + .5);

    if (l1 > l2) {
        l = l1;
        l1 = l2;
        l2 = l;
    }

/* adjust index to indexBase */
    if (indexBase == 1) {
        l1--;
        l2--;
    }

    switch (arg.type) {
        case typeFits:
            if (x1.type == typeFits) {
                rv.type = typeFits;
                rv.fvalue = CreateFits();
                arg.fvalue->extractRange(*rv.fvalue, *x1.fvalue);
            } else if (l1 == l2 && l1 >= 0) {
                rv.type = typeDbl;
                rv.dvalue = arg.fvalue->ValueAt(l1);
            } else {
                rv.type = typeFits;
                rv.fvalue = CreateFits();
                arg.fvalue->extractRange(*rv.fvalue, l1+1, l2+1, 1, 1, 1, 1);
            }
        break;
        case typeStr:
            rv.type = typeStr;
            rv.svalue = CreateString();
            if (l1 < 0) *rv.svalue = *arg.svalue;
            else for (l = l1; l <= l2; l++) *rv.svalue += (*arg.svalue)[(int)l];
        break;
        case typeStrarr:
            if (l1 == l2 && l1 >= 0) {
                rv.type = typeStr;
                rv.svalue = CreateString();
                *rv.svalue = (*arg.arrvalue)[l1];
            } else if (l1 < 0) {
                rv.type = typeStrarr;
                rv.arrvalue = CreateStringArray();
                *rv.arrvalue = *arg.arrvalue;
            } else {
                rv.type = typeStrarr;
                rv.arrvalue = CreateStringArray();
                for (l = l1; l <= l2; l++) rv.arrvalue->push_back((*arg.arrvalue)[l]);
            }
        break;
        case typeDbl:
        case typeCon:
        case typeCom:
            if (l1 == 0 && l2 == 0) {
                rv = arg;
            } else {
                rv.type = typeUnknown;
            }
            break;
        default:
            rv.type = typeUnknown;
        break;
    }

    return rv;
}

dpuserType extractrange(const dpuserType &arg, const dpuserType &x1, const dpuserType &x2, const dpuserType &y1, const dpuserType &y2) {
    if (arg.type != typeFits)
        throw dpuserTypeException("extractrange: Wrong argument type.");

    dpuserType rv;
    long l1 = 0, l2 = 0, l3 = 0, l4 = 0, l;

    if (x1.type == typeCon) l1 = x1.lvalue;
    else if (x1.type == typeDbl) l1 = (long)(x1.dvalue + .5);
    if (x2.type == typeCon) l2 = x2.lvalue;
    else if (x2.type == typeDbl) l2 = (long)(x2.dvalue + .5);

    if (y1.type == typeCon) l3 = y1.lvalue;
    else if (y1.type == typeDbl) l3 = (long)(y1.dvalue + .5);
    if (y2.type == typeCon) l4 = y2.lvalue;
    else if (y2.type == typeDbl) l4 = (long)(y2.dvalue + .5);

    if (l1 > l2) {
        l = l1;
        l1 = l2;
        l2 = l;
    }
    if (l3 > l4) {
        l = l3;
        l3 = l4;
        l4 = l;
    }

/* adjust index to indexBase */
    if (indexBase == 1) {
        l1--;
        l2--;
        l3--;
        l4--;
    }

    if (l1 == l2 && l1 >= 0 && l3 == l4 && l3 >= 0) {
        rv.type = typeDbl;
        rv.dvalue = arg.fvalue->ValueAt(arg.fvalue->C_I(l1, l3));
    } else {
        rv.type = typeFits;
        rv.fvalue = CreateFits();
        arg.fvalue->extractRange(*rv.fvalue, l1+1, l2+1, l3+1, l4+1, 1, 1);
    }

    return rv;
}

dpuserType extractrange(const dpuserType &arg, const dpuserType &x1, const dpuserType &x2, const dpuserType &y1, const dpuserType &y2, const dpuserType &z1, const dpuserType &z2) {
    if (arg.type != typeFits)
        throw dpuserTypeException("extractrange: Wrong argument type.");

    dpuserType rv;
    long l1 = 0, l2 = 0, l3 = 0, l4 = 0, l5 = 0, l6 = 0, l;

    if (x1.type == typeCon) l1 = x1.lvalue;
    else if (x1.type == typeDbl) l1 = (long)(x1.dvalue + .5);
    if (x2.type == typeCon) l2 = x2.lvalue;
    else if (x2.type == typeDbl) l2 = (long)(x2.dvalue + .5);

    if (y1.type == typeCon) l3 = y1.lvalue;
    else if (y1.type == typeDbl) l3 = (long)(y1.dvalue + .5);
    if (y2.type == typeCon) l4 = y2.lvalue;
    else if (y2.type == typeDbl) l4 = (long)(y2.dvalue + .5);

    if (z1.type == typeCon) l5 = z1.lvalue;
    else if (z1.type == typeDbl) l5 = (long)(z1.dvalue + .5);
    if (z2.type == typeCon) l6 = z2.lvalue;
    else if (z2.type == typeDbl) l6 = (long)(z2.dvalue + .5);

    if (l1 > l2) {
        l = l1;
        l1 = l2;
        l2 = l;
    }
    if (l3 > l4) {
        l = l3;
        l3 = l4;
        l4 = l;
    }
    if (l5 > l6) {
        l = l5;
        l5 = l6;
        l6 = l;
    }

/* adjust index to indexBase */
    if (indexBase == 1) {
        l1--;
        l2--;
        l3--;
        l4--;
        l5--;
        l6--;
    }

    if (l1 == l2 && l1 >= 0 && l3 == l4 && l3 >= 0 && l5 == l6 && l5 >= 0) {
        rv.type = typeDbl;
        rv.dvalue = arg.fvalue->ValueAt(arg.fvalue->C_I(l1, l3, l5));
    } else {
        rv.type = typeFits;
        rv.fvalue = CreateFits();
        arg.fvalue->extractRange(*rv.fvalue, l1+1, l2+1, l3+1, l4+1, l5+1, l6+1);
    }

    return rv;
}

//Thomas
dpuserType createrange(const dpuserType &start, const dpuserType &end) {
    if (!start.isInt())
        throw dpuserTypeException("createrange: First argument must be integer.");
    if (!end.isInt())
        throw dpuserTypeException("createrange: Second argument must be integer.");

    int range;
    range = end.toInt() - start.toInt() + 1;
    if (range < 0) range = -range + 2;

    dpuserType rv;
    rv.type = typeFits;
    rv.fvalue = CreateFits();
    rv.fvalue->create(range, 1, I4);
    for (int i = 0; i < range; i++)
        rv.fvalue->i4data[i] = i + start.toInt();

    return rv;
}

const char *dpuserType::getFileName(void) const {
    if (type == typeFits) {
        return fvalue->getFileName();
    } else if (type == typeDpArr) {
        return dparrvalue->at(0)->getFileName();
    } else if (type == typeStrarr) {
        return arrvalue->getFileName();
    }
    return "";
}

const char* dpuserType::getColumnName() const {
    if (type == typeFits) {
        return fvalue->getColumnName();
    } else if (type == typeStrarr) {
        return arrvalue->getColumnName();
    }
    return NULL;
}

bool dpuserType::showAsTable() {
    if (type == typeFits) {
        switch (fvalue->extensionType) {
        case BINTABLE:
        case TABLE:
            return true;
            break;
        case UNKNOWN:
        case EMPTY:
        case IMAGE:
        case BINTABLEIMAGE:
        default:
            return false;
            break;
        }
    } else if (type == typeStrarr) {
        return true;
    } else if (type == typeDpArr) {
        bool ret = true;
        for (int i = 0; i < dparrvalue->size(); i++ ) {
            ret = ret && dparrvalue->at(i)->showAsTable();
            if (!ret) {
                break;
            }
        }
        return ret;
    } else {
        return false;
    }
}

// ////////////////////////////////////////////////////////////////////////////////
// dpuserTypeList
// ////////////////////////////////////////////////////////////////////////////////

dpuserTypeList::dpuserTypeList(const dpuserTypeList &source) {
    int i;
    dpuserType *f;

    for (i = 0; i < source.size(); i++) {
        f = new dpuserType;
        if (f->deep_copy(*(source[i]))) {
            push_back(f);
        } else {
            delete f;
        }
    }
}

dpuserTypeList::~dpuserTypeList() {
    for (int i = 0; i < size(); i++) {
        delete (*this)[i];
    }

}

bool dpuserTypeList::ReadFITS(const dpString &fname) {
    dpuserType* f = new dpuserType;

    f->type = typeFits;
    f->fvalue = new Fits;

    bool rv = f->fvalue->ReadFITS(fname.c_str());

    if (rv) {
        push_back(f);

        Fits _tmp;
        int count = _tmp.CountExtensions(fname.c_str());
         _tmp.OpenFITS(fname.c_str());

        for (int i = 1; i <= count; i++) {
            if (_tmp.ReadFitsExtensionHeader(i, true) > 0) {
                _tmp.getHeaderInformation();
//                char keyValue[81];
//                if (_tmp.GetStringKey("EXTNAME", keyValue)) {
                    switch (_tmp.extensionType) {
                    case TABLE:
                    case BINTABLE: {
                        dpuserType rrv, nn(fname.c_str());
                        rrv = dpuserFunction_readfitsbintable(nn, i, 0);
                        switch (rrv.type) {
                           case typeFits: deleteFromListOfFits(rrv.fvalue);
                            break;
                        case typeStrarr: deleteFromListOfdpStringArrays(rrv.arrvalue);
                            break;
                        case typeDpArr: deleteFromListOfDpLists(rrv.dparrvalue);
                            break;
                        default:
                            break;
                        }

                        push_back(new dpuserType(rrv));
                        }
                        break;
                    default:
                        // IMAGE
                        f = new dpuserType;
                        f->type = typeFits;
                        f->fvalue = new Fits;

                        rv = f->fvalue->ReadFITSExtension(fname.c_str(), i);
                        if (rv) {
                            push_back(f);
                        } else {
                            delete f;
                        }
                        break;
                    }
//                }
            }
        }
    } else {
        delete f;
        return FALSE;
    }
    return TRUE;
}

bool dpuserTypeList::showAsTable() {
    bool ret = true;
    for (int i = 0; i < size(); i++) {
        ret &= at(i)->showAsTable();
    }
    return ret;
}
