/***************************** LICENSE START ***********************************

 Copyright 2012 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#pragma once

#include <iostream>
#include <map>
#include <string>
#include <vector>

#include "date.h"
#include "arith.h"
/* #define USEMARS */

// Define needed on Solaris
#define vtype _vtype

// GNU 2.96: type clash!
// typedef argtype _vtype; // from mars.h
typedef int _vtype;

class Value;

//=============================================================================

class Notify
{
public:
    Notify() {}
    ~Notify() {}

    virtual void trigger(void*) = 0;
};

class Reference
{
    int count;
    Notify* notify;

    void suicide()
    {
        if (notify)
            notify->trigger(this);
        delete this;
    }

public:
    int RefCount(void) { return count; }
    Reference()
    {
        count = 0;
        notify = 0;
    }
    void Attach(void) { count++; }
    void Detach(void)
    {
        if (--count <= 0)
            suicide();
    }
    void SetNotify(Notify* n) { notify = n; }
    virtual ~Reference() = default;

    //============================================================================
    void* operator new(size_t s) { return fast_new(s, transient_mem); }
    void operator delete(void* p) { fast_delete(p, transient_mem); }
};

//=============================================================================

class CNil;
class CList;
class CGrib;
class CImage;
class CMatrix;
class CVector;
class CBufr;
class CGeopts;
class CGeoptSet;
class CFile;
class Image;
class CNetCDF;
class CTable;
class CObject;
class CError;
#ifdef METVIEW_ODB
class COdb;
#endif

class Content : public Reference
{
    // No copy
    Content(const Content&);
    void operator=(const Content&);

    const char* TypeName(void);
    vtype type;

    void Fail(const char* s);

protected:
    // Utility
    static int CopyFile(const char* fname, FILE* to);

public:
    static int Error(const char* fmt, ...);
    static void Perl(request*);

    virtual void Sync(Value*) {}

    Content(vtype t) :
        type(t) {}


    virtual int Write(FILE*);
    virtual vtype GetType(const char** n)
    {
        if (n)
            *n = TypeName();
        return type;
    }
    //	virtual void Print(void)       { std::cout << form("<%s>",TypeName());};
    virtual void Print(void) { std::cout << TypeName(); }
    virtual Content* Clone(void)
    {
        Fail("Clone");
        return this;
    }

    virtual void ToNumber(double& x)
    {
        Fail("double");
        x = 0;
    }
    virtual void ToDate(Date& x)
    {
        Fail("date");
        x = 0.0;
    }
    virtual void ToString(const char*& x)
    {
        Fail("string");
        x = 0;
    }
    virtual void ToRequest(request*& x)
    {
        Fail("request");
        x = 0;
    }
    virtual void ToFieldset(fieldset*& x)
    {
        Fail("fieldset");
        x = 0;
    }
    virtual void ToList(CList*& x)
    {
        Fail("list");
        x = 0;
    }
    virtual void ToGrib(CGrib*& x)
    {
        Fail("grib");
        x = 0;
    }
    virtual void ToBufr(CBufr*& x)
    {
        Fail("bufr");
        x = 0;
    }
    virtual void ToGeopts(CGeopts*& x)
    {
        Fail("geopoints");
        x = 0;
    }
    virtual void ToGeoptSet(CGeoptSet*& x)
    {
        Fail("geopointset");
        x = 0;
    }
    virtual void ToImage(Image*& x)
    {
        Fail("image");
        x = 0;
    }
    virtual void ToMatrix(CMatrix*& x)
    {
        Fail("matrix");
        x = 0;
    }
    virtual void ToVector(CVector*& x)
    {
        Fail("vector");
        x = 0;
    }
    virtual void ToFile(CFile*& x)
    {
        Fail("file");
        x = 0;
    }
    virtual void ToNetCDF(CNetCDF*& x)
    {
        Fail("netcdf");
        x = 0;
    }
    virtual void ToTable(CTable*& x)
    {
        Fail("table");
        x = 0;
    }
    virtual void ToObject(CObject*& x)
    {
        Fail("object");
        x = 0;
    }
    virtual void ToError(CError*& x)
    {
        Fail("error");
        x = 0;
    }
#ifdef METVIEW_ODB
    virtual void ToOdb(COdb*& x)
    {
        Fail("odb");
        x = 0;
    }
#endif
    virtual void Dump(int);
    virtual void Dump1()
    {
        Print();
    }
    virtual void Dump2()
    {
        Print();
    }

    int Check(int, Value&, int, Value*, vtype, int, ...);
    virtual void SetSubValue(Value&, int, Value*)
    {
        Fail("Index");
    }
    //
};

//=============================================================================
// Classes that are in pool, like grib or other

class InPool : public Content
{
protected:
    boolean isIcon;  // If it is an icon form MetviewUI
    char* iconName;

public:
    InPool(vtype t, request* r);
    InPool(vtype t, const char* n = nullptr);
    ~InPool();

    // SetName(char *n);
    const char* GetName(void) { return iconName; }
    boolean IsIcon() { return isIcon; }
    void IsIcon(boolean n) { isIcon = n; }
};

//=============================================================================
class CNumber : public Content
{
    double number;
    static long sPrec;
    static long sDefaultPrec;
    virtual void ToRequest(request*&);
    virtual void ToString(const char*&);
    virtual void ToNumber(double& x) { x = number; }
    //	virtual void Print(void)  { std::cout << form("%g",number); };
    virtual void Print(void);  //  { std::cout << number;            };
    virtual int Write(FILE*);

public:
    CNumber(double d) :
        Content(tnumber) { number = d; }
    static void SetPrecision(long p) { sPrec = p; }
    static long GetPrecision() { return sPrec; }
    static long GetDefaultPrecision() { return sDefaultPrec; }
};
//=============================================================================
class CDate : public Content
{
    Date date;
    virtual void ToNumber(double&);
    virtual void ToString(const char*&);
    virtual void ToDate(Date& x) { x = date; }
    virtual void Dump2();
    virtual void Print(void) { date.Print(); }

public:
    CDate(Date d) :
        Content(tdate) { date = d; }
};
//=============================================================================
class CString : public Content
{
    char* string;
    virtual void ToRequest(request*&);
    virtual void ToString(const char*& x) { x = string; }
    virtual void Print(void) { std::cout << string; }
    virtual void Dump1();
    virtual void Dump2();
    virtual int Write(FILE*);

public:
    CString(const char* s) :
        Content(tstring) { string = strcache(s); }
    ~CString() { strfree(string); }
};

//=============================================================================
// Should maybe be a InPool

class CRequest : public Content
{
    request* r;
    virtual void ToRequest(request*& x) { x = r; }
    virtual void Print(void);
    virtual void Dump2(void);
    virtual Content* Clone(void) { return new CRequest(r); }
    virtual void SetSubValue(Value&, int, Value*);
    virtual int Write(FILE*);

public:
    void SetRequest(request* s)
    {
        free_all_requests(r);
        r = clone_all_requests(s);
    }
    request* GetRequest(void) { return r; }
    CRequest(request* s) :
        Content(trequest) { r = clone_all_requests(s); }
    ~CRequest() { free_all_requests(r); }
};

// exposed for the Python interface
void SetValue(request* r, const char* param, Value& val, bool attachData = true);

//=============================================================================
class CError : public Content
{
    err error;
    char* msg;

    virtual void Print(void);
    virtual void ToRequest(request*& x);
    virtual void ToError(CError*& x) { x = this; }

public:
    CError(err e, const char* m) :
        Content(terror)
    {
        error = e;
        msg = strcache(m);
    }
    ~CError() { strfree(msg); }
    const char* Message() { return msg; }
};

//=============================================================================
class CNil : public Content
{
    virtual void ToRequest(request*& x) { x = nullptr; }
    virtual void Dump2();

public:
    CNil() :
        Content(tnil) {}
};

//=============================================================================

class CGrib : public InPool
{
    fieldset* fs;
    hypercube* cube;
    std::string path_;  // It stores an absolute path. This is important
                        // specially if request parameter PATH contains
                        // a relative path.
    bool from_filter_;  // Indicates if the grib data was a result of a
                        // Mars filter or a subset of a fieldset generated
                        // with []

    virtual void ToFieldset(fieldset*& x)
    {
        x = fs;
    }

    virtual void ToRequest(request*&);
    virtual void ToGrib(CGrib*& x)
    {
        x = this;
    }

    virtual void Print(void);
    virtual int Write(FILE*);
    virtual Content* Clone(void);
    virtual void SetSubValue(Value&, int, Value*);
    virtual void Dump2();
    void DestroyContent();

public:
    CGrib(const char*, bool = false);
    CGrib(request*);
    CGrib(fieldset*, bool = false);

    ~CGrib();

    fieldset* GetFieldset(void)
    {
        return fs;
    }

    void SetFileTempFlag(boolean);
    hypercube* get_cube();
    bool fromFilter() { return from_filter_; }
};


//=============================================================================

class Image;
class CImage : public InPool
{
    /*
    int   temp;
    const char *path;
    char *buffer;
    long length;
    long offset;
    long size;
    long width;
    long height;
    */
    Image* image;
    virtual void ToRequest(request*&);
    // virtual void ToImage(CImage* &x)   { x = this; };
    virtual void ToImage(Image*& x) { x = image; }
    virtual int Write(FILE*);

public:
    // CImage(CImage*);
    CImage(Image*);
    CImage(request* r);
    ~CImage();
};

//=============================================================================

class ASync : public CRequest
{
    friend class Value;

    static void Input(svcid*, request*, void*);
    static void Reply(svcid*, request*, void*);
    static void Definition(svcid*, request*, void*);
    static void Progress(svcid*, request*, void*);

    boolean Ready;
    virtual void Sync(Value*);
    void Print(void) { std::cout << "<waiting>"; }

public:
    static svc* Svc;
    static int RequestMax;
    static int RequestCnt;
    static char* Name;

    static void Connect(void);
    static void IconStatus(const char*, const char*, const char* = nullptr);
    static void Disconnect(void)
    {
        if (Svc)
            destroy_service(Svc);
        Svc = nullptr;
    }
    static void Store(const char* name, request* r);
    static request* Fetch(const char* name);

    ASync(const char* n, request* s);
    ~ASync();

    request* Wait(void);
    void SetAttachedContent(std::vector<Content*> v) { attachedContent = v; }
    void AvoidDuplication(Content* c);

    virtual void ToRequest(request*& x) { x = Wait(); }

private:
    // asynchronous requests require a bit more effort for cleaning up any
    // temporary files that they use; if data is passed to another module,
    // Macro should not delete the underlying data until it knows that the
    // module has finished with it, ie the module has finished. So for each
    // asynchronous request, we store a list of data (Content *) which has been
    // passed to it; this can then be destroyed (or at least have its reference
    // counter decremented) when the module returns. GRIB presents an additional
    // problem because the GRIB filter module can return data which is itself
    // dependent on the input data - we still do not deal with this correctly,
    // so we simply allow that data to remain.

    std::vector<Content*> attachedContent;
};

//=============================================================================

class CList;

//=============================================================================

class Value
{
    Content* c;

    void CleanUp(void);
    void Copy(const Value&);

    void _s(void) { c->Sync(this); }

    static struct NilValue
    {
        CNil nil;
        NilValue()
        {
            nil.Attach();
            nil.Attach();
        }  // ensure never deleted, even on termination
    } * nilvalue;

public:
    Value()
    {
        if (!nilvalue)
            nilvalue = new NilValue();
        c = &nilvalue->nil;
        c->Attach();
    }
    Value(double x)
    {
        c = new CNumber(x);
        c->Attach();
    }
    Value(const Date& d)
    {
        c = new CDate(d);
        c->Attach();
    }
    Value(request* r)
    {
        c = new CRequest(r);
        c->Attach();
    }
    Value(fieldset* v, bool grib_filter = false)
    {
        c = new CGrib(v, grib_filter);
        c->Attach();
    }
    Value(const char* p)
    {
        c = new CString(p);
        c->Attach();
    }
    Value(Content* x)
    {
        c = x;
        c->Attach();
    }
    Value(err e, const char* m)
    {
        c = new CError(e, m);
        c->Attach();
    }

    Value(const char*, request*);
    Value(const char*, request*, std::vector<Content*>);
    Value(const Value&);
    void SetContent(Content* x);
    void SetContent(request* r);
    void SetContentRequest(request* r);
    Content* GetContent(void) { return c; }

    void Write(void)
    {
        if (c->RefCount() > 1)
            SetContent(c->Clone());
    }

    ~Value();
    void Destroy() { delete this; }

    void Sync() { _s(); }

    Value& operator=(const Value&);
    void SetSubValue(Value& a, int b, Value* v)
    {
        Write();
        c->SetSubValue(a, b, v);
    }
    vtype GetType(const char** name = nullptr)
    {
        _s();
        return c->GetType(name);
    }

    void GetValue(int& x)
    {
        double d;
        c->ToNumber(d);
        x = (int)d;
    }
    void GetValue(long& x)
    {
        double d;
        c->ToNumber(d);
        x = (long)d;
    }
    void GetValue(double& x) { c->ToNumber(x); }
    void GetValue(Date& x) { c->ToDate(x); }
    void GetValue(const char*& x) { c->ToString(x); }
    void GetValue(request*& x) { c->ToRequest(x); }
    void GetValue(fieldset*& x) { c->ToFieldset(x); }
    void GetValue(CList*& x) { c->ToList(x); }
    void GetValue(CGrib*& x) { c->ToGrib(x); }
    void GetValue(CBufr*& x) { c->ToBufr(x); }
    void GetValue(CGeopts*& x) { c->ToGeopts(x); }
    void GetValue(CGeoptSet*& x) { c->ToGeoptSet(x); }
    void GetValue(CMatrix*& x) { c->ToMatrix(x); }
    void GetValue(CNetCDF*& x) { c->ToNetCDF(x); }
    void GetValue(CTable*& x) { c->ToTable(x); }
    void GetValue(CObject*& x) { c->ToObject(x); }
    void GetValue(CVector*& x) { c->ToVector(x); }
    void GetValue(Image*& x) { c->ToImage(x); }
    void GetValue(CFile*& x) { c->ToFile(x); }
    void GetValue(CError*& x) { c->ToError(x); }
#ifdef METVIEW_ODB
    void GetValue(COdb*& x)
    {
        c->ToOdb(x);
    }
#endif
    void Print(void)
    {
        c->Print();
    }
    void Dump(int trace)
    {
        c->Dump(trace);
    }
    int Write(FILE* f)
    {
        return c->Write(f);
    }

    static const char* TypeName(vtype);
    static vtype NameType(const char*);
};

//============================================================================

class CList : public Content
{
    int count;
    Value* values;

    void Copy(const CList&);
    void CleanUp(void)
    {
        delete[] values;
        values = nullptr;
    }
    virtual void ToList(CList*& x) { x = this; }
    virtual void ToRequest(request*&);
    virtual int Write(FILE*);
    virtual Content* Clone(void);
    virtual void SetSubValue(Value&, int, Value*);

    int capacity;
    static constexpr int CHUNK = 64;  // must be a power of 2

    static constexpr int calcCapacity(const int n)
    {
        return (n + (CHUNK - 1)) & ~(CHUNK - 1);
    }

    void Move(CList&&);

public:
    CList(const CList&);
    CList& operator=(const CList&);

    CList(CList&&);
    CList& operator=(CList&&);

    CList(int n) :
        Content(tlist),
        count(n),
        capacity(calcCapacity(n)) { values = new Value[capacity]; }
    virtual ~CList() { CleanUp(); }
    Value& operator[](int n) { return values[n]; }

    int Count(void) { return count; }
    Value* Values(void) { return values; }
    void Add(const Value& v);

    void Print(void);
    void Dump2(void);
};

//============================================================================

// A note about VECTOR_MISSING_VALUE: this is currently set to
// mars.grib_missing_value so that we can efficiently copy field values
// directly to a vector without having to do any conversion on the missing
// values. The macro functions gridvals() and set_gridvals() make this
// assumption; therefore, if VECTOR_MISSING_VALUE is changed, then we would
// need to revise these functions so that they consider missing values
// more carefully. Functions that convert geopoints values into vectors
// already have to do a conversion.

#define VECTOR_MISSING_VALUE mars.grib_missing_value


// ...and now we need one that's storable in float32s!

// XXXXX consider: change the value of mars.grib_missing_value to 3.0E+38
// so that we don't need to worry about conversions....
// otherwise we need to look at functions that translate between GRIB and vector

#define VECTOR_F32_MISSING_VALUE 3.0E+38f


// -------------------------------------------------------------------
// CArray - a helper class that stores an array of different types
// - we don't use templates because we want to override the behaviour
//   in different ways

class CArray
{
public:
    enum ValuesType
    {
        VALUES_F64,
        VALUES_F32,
        VALUES_INVALID = 99
    };

    CArray() :
        size(0) {}
    CArray(ValuesType type) :
        size(0),
        valtype(type) {}
    int count() { return size; }
    CArray::ValuesType type() { return valtype; }
    void copyValues(int targetIndex, CArray* source, int sourceIndex, int numValues);
    void setSize(int newSize) { size = newSize; }  // only sets the counter
    virtual void allocateMemory(int numElements) = 0;
    virtual void setValuesToConstant(double c) = 0;
    virtual void memorycopy(int targetIndex, const double* srcVals, int numVals) = 0;
    virtual void memorycopy(int targetIndex, const float* srcVals, int numVals) = 0;
    virtual double* asDoubles(int i) = 0;
    virtual float* asFloat32s(int i) = 0;
    virtual void setIndexedValue(int i, double v) = 0;
    virtual void setIndexedValueToMissing(int i) = 0;
    virtual bool isIndexedValueMissing(int i) = 0;
    virtual double getIndexedValue(int i) = 0;
    virtual double getMissingValueIndicator() = 0;
    virtual size_t writeValuesToFile(FILE* fp) = 0;
    virtual size_t readValuesFromFile(FILE* fp, int n) = 0;
    virtual void clean() = 0;
    virtual void resize(int newSize) = 0;
    virtual void applyNumBinProc(binproc f, double other, bool otherFirst) = 0;
    virtual void applyVectorBinProc(binproc f, CArray* v1, CArray* v2) = 0;
    virtual void applyVectorUniProc(uniproc f, CArray* v) = 0;

    // virtual double& operator[](int n) = 0;

    static CArray::ValuesType valuesTypeFromString(const std::string& s);
    static std::string stringFromValuesType(CArray::ValuesType type);
    static std::map<std::string, CArray::ValuesType> valtypes;

protected:
    int size;
    ValuesType valtype;
};


class CArrayF64 : public CArray
{
public:
    CArrayF64() :
        CArray(CArray::VALUES_F64),
        values(nullptr) {}

    void allocateMemory(int numElements);
    void setValuesToConstant(double c);
    void memorycopy(int targetIndex, const double* srcVals, int numVals);
    void memorycopy(int targetIndex, const float* srcVals, int numVals);
    double* asDoubles(int i) { return &(values[i]); }
    float* asFloat32s(int) { return nullptr; }
    void setIndexedValue(int i, double v) { values[i] = v; }
    void setIndexedValueToMissing(int i) { values[i] = VECTOR_MISSING_VALUE; }
    bool isIndexedValueMissing(int i) { return (values[i] == VECTOR_MISSING_VALUE); }
    double getIndexedValue(int i) { return values[i]; }
    double getMissingValueIndicator() { return VECTOR_MISSING_VALUE; }
    size_t writeValuesToFile(FILE* fp);
    size_t readValuesFromFile(FILE* fp, int n);
    void clean();
    void resize(int newSize);
    void applyNumBinProc(binproc f, double other, bool otherFirst);
    void applyVectorBinProc(binproc f, CArray* v1, CArray* v2);
    void applyVectorUniProc(uniproc f, CArray* v);

private:
    double* values;
    // double& operator[](int n)   { return values[n]; };
};

class CArrayF32 : public CArray
{
public:
    CArrayF32() :
        CArray(CArray::VALUES_F32),
        values(nullptr) {}

    void allocateMemory(int numElements);
    void setValuesToConstant(double c);
    void memorycopy(int targetIndex, const double* srcVals, int numVals);
    void memorycopy(int targetIndex, const float* srcVals, int numVals);
    double* asDoubles(int) { return nullptr; }
    float* asFloat32s(int i) { return &(values[i]); }
    void setIndexedValue(int i, double v) { values[i] = v; }
    void setIndexedValueToMissing(int i) { values[i] = VECTOR_F32_MISSING_VALUE; }
    bool isIndexedValueMissing(int i) { return (values[i] == VECTOR_F32_MISSING_VALUE); }
    double getIndexedValue(int i) { return values[i]; }
    double getMissingValueIndicator() { return VECTOR_F32_MISSING_VALUE; }
    size_t writeValuesToFile(FILE* fp);
    size_t readValuesFromFile(FILE* fp, int n);
    void clean();
    void resize(int newSize);
    void applyNumBinProc(binproc f, double other, bool otherFirst);
    void applyVectorBinProc(binproc f, CArray* v1, CArray* v2);
    void applyVectorUniProc(uniproc f, CArray* v);

private:
    float* values;
    // float& operator[](int n)   { return values[n]; };
};


class CVector : public Content
{
    void Copy(const CVector&);
    void CleanUp(void)
    {
        if (values)
            values->clean();
    }

    int Write(FILE*);
    bool Read(const char* filename);
    void Dump(int);
    void Print(void);
    void ToRequest(request*&);
    void ToVector(CVector*& x) { x = this; }
    Content* Clone(void) { return new CVector(*this); }
    void SetSubValue(Value&, int, Value*);

public:
    enum PercentileInterpolationType
    {
        PERCENTILE_NEAREST
    };

    CVector(int n, bool zeroValues = false);
    CVector(std::vector<double>& v);
    CVector(double* v, int n, CArray::ValuesType dtype = CArray::VALUES_INVALID);
    CVector(float* v, int n, CArray::ValuesType dtype = CArray::VALUES_INVALID);
    CVector(request* r);
    CVector(const char* filename);
    ~CVector() { CleanUp(); }
    CVector(const CVector& x) :
        Content(tvector),
        values(0) { Copy(x); }
    CVector& operator=(const CVector& x)
    {
        CleanUp();
        Copy(x);
        return *this;
    }
    void init(CArray::ValuesType type);
    void CopyValues(int targetIndex, const CVector& source, int sourceIndex, int numValues);
    void CopyValuesFromDoubleArray(int targetIndex, const double* source, int sourceIndex, int numValues);
    int IndexOfFirstValidValue();
    void Resize(int newSize);
    void Sort(char op);
    void SortIndices(char op);
    void Percentile(CVector& percs, PercentileInterpolationType interp, CVector& result);
    void Replace(double dold, double dnew);
    void Replace(float dold, float dnew);
    void setIndexedValue(int i, double v) { values->setIndexedValue(i, v); }
    // void setIndexedValueToMissing(int i);
    bool isIndexedValueMissing(int i) { return values->isIndexedValueMissing(i); }
    double getIndexedValue(int i) { return values->getIndexedValue(i); }
    void setIndexedValueToMissing(int i) { values->setIndexedValueToMissing(i); }

    double* ValuesAsDoubles(int i) { return values->asDoubles(i); }
    float* ValuesAsFloat32s(int i) { return values->asFloat32s(i); }
    double operator[](int i) { return values->getIndexedValue(i); }
    int Count(void) const { return values->count(); }
    double MissingValueIndicator(void) const { return values->getMissingValueIndicator(); }
    void SetValues(double* values, int size);
    CArray::ValuesType valuesType() const { return values->type(); }

    CArray* values;
    static CArray::ValuesType defaultValtype;
};

//============================================================================

class CMatrix : public Content
{
    int row;
    int col;
    double* values;

    void Copy(const CMatrix& x);
    void CleanUp(void) { delete[] values; }
    virtual void ToMatrix(CMatrix*& x) { x = this; }

    virtual Content* Clone(void) { return new CMatrix(*this); }
    virtual void SetSubValue(Value&, int, Value*);

public:
    virtual void Print(void);
    virtual void Dump(int);
    CMatrix(int r, int c);
    CMatrix(const CMatrix& x) :
        Content(tmatrix) { Copy(x); }
    CMatrix& operator=(const CMatrix& x)
    {
        CleanUp();
        Copy(x);
        return *this;
    }
    ~CMatrix() { CleanUp(); }

#if 0
	double&  operator()(int r,int c)    { return values[r+c*row]; };
#else
    double& operator()(int r, int c)
    {
        if (r < 0 || r >= row) {
            marslog(LOG_INFO, "Bad row %d", r);
            abort();
        }
        if (c < 0 || c >= col) {
            marslog(LOG_INFO, "Bad col %d", c);
            abort();
        }
        int x = r + c * row;
        if (x < 0 || x >= row * col) {
            marslog(LOG_INFO, "Bad x %d", x);
            abort();
        }
        return values[r + c * row];
    }
#endif
    int Row(void)
    {
        return row;
    }
    int Col(void)
    {
        return col;
    }
    virtual int Write(FILE*);
};

//=============================================================================

class Context;
class CObject : public Content
{
    char* name;
    Context* context;

    Value members;
    Value defaults;
    Value super();
    Context* code() { return context; }


    void SetContext(CObject*);
    void GetContext();

    // virtual void ToRequest(request* &);
    virtual void Print(void);
    virtual Content* Clone(void);
    // virtual void Dump2();

    virtual void ToObject(CObject*& x) { x = this; }

public:
    CObject(const char*, Context*);
    ~CObject();

    CObject(const CObject&);
    CObject& operator=(const CObject&);

    Value Method(const char*, int, Value*);

    void GetInheritance(Context**, int& count);
};

// VALUE_H__
