/******************************************** 
  copyright 1999 McMillan Enterprises, Inc.
  www.mcmillan-inc.com
*********************************************/
// PWOBase.h: interface for the PWOBase class.

#if !defined(PWOBASE_H_INCLUDED_)
#define PWOBASE_H_INCLUDED_

#include <Python.h>
#include <limits.h>

// Dummy, minimal exception thrown when a Python exception is generated
// (after PyErr_Format, PyErr_SetString, etc.)
class PWDException
{
 public:
  PWDException() {}
} extern const& PWDPyException;

// functions throw PWDPyException
void Fail(PyObject*, const char* msg);
void FailIfPyErr();

class PWOBase  
{
protected:
  PyObject* _obj;

    // incref new owner, decref old owner, and adjust to new owner
  void GrabRef(PyObject* newObj);
    // decrease reference count without destroying the object
  static PyObject* LoseRef(PyObject* o)
    { if (o != 0) --(o->ob_refcnt); return o; }

private:
  PyObject* _own; // set to _obj if we "own" a reference to _obj, else zero

public:
  PWOBase()
    : _obj (0), _own (0) { }
  PWOBase(const PWOBase& other)
    : _obj (0), _own (0) { GrabRef(other); }
  PWOBase(PyObject* obj)
    : _obj (0), _own (0) { GrabRef(obj); }

  virtual ~PWOBase()
    { Py_XDECREF(_own); }
  
  PWOBase& operator=(const PWOBase& other) {
    GrabRef(other);
    return *this;
  };
  operator PyObject* () const {
    return _obj;
  };
  int print(FILE *f, int flags) const {
    return PyObject_Print(_obj, f, flags);
  };
  bool hasAttr(const char* nm) const {
    return PyObject_HasAttrString(_obj, (char*) nm) == 1;
  };
  //bool hasAttr(PyObject* nm) const {
  //      return PyObject_HasAttr(_obj, nm);
  //};
  PyObject* getAttr(const char* nm) const {
    return LoseRef(PyObject_GetAttrString(_obj, (char*) nm));
  };
  PyObject* getAttr(const PWOBase& nm) const {
    return LoseRef(PyObject_GetAttr(_obj, nm));
  };
  int setAttr(const char* nm, PWOBase& val) {
    return PyObject_SetAttrString(_obj, (char*) nm, val);
  };
  int setAttr(PyObject* nm, PWOBase& val) {
    return PyObject_SetAttr(_obj, nm, val);
  };
  int delAttr(const char* nm) {
    return PyObject_DelAttrString(_obj, (char*) nm);
  };
  int delAttr(const PWOBase& nm) {
    return PyObject_DelAttr(_obj, nm);
  };
  int cmp(const PWOBase& other) const {
    int rslt = 0;
    int rc = PyObject_Cmp(_obj, other, &rslt);
    if (rc == -1)
      Fail(PyExc_TypeError, "cannot make the comparison");
    return rslt;
  };
  bool operator == (const PWOBase& other) const {
    return cmp(other) == 0;
  };
  bool operator != (const PWOBase& other) const {
    return cmp(other) != 0;
  };
  bool operator > (const PWOBase& other) const {
    return cmp(other) > 0;
  };
  bool operator < (const PWOBase& other) const {
    return cmp(other) < 0;
  };
  bool operator >= (const PWOBase& other) const {
    return cmp(other) >= 0;
  };
  bool operator <= (const PWOBase& other) const {
    return cmp(other) <= 0;
  };
      
  PyObject* repr() const {
    return LoseRef(PyObject_Repr(_obj));
  };
  PyObject* str() const {
    return LoseRef(PyObject_Str(_obj));
  };
  bool isCallable() const {
    return PyCallable_Check(_obj) == 1;
  };
  int hash() const {
    return PyObject_Hash(_obj);
  };
  bool isTrue() const {
    return PyObject_IsTrue(_obj) == 1;
  };
  PyObject* type() const {
    return LoseRef(PyObject_Type(_obj));
  };
  PyObject* disOwn() {
    _own = 0;
    return _obj;
  };
};

#endif // !defined(PWOBASE_H_INCLUDED_)
