// ---------------------------------------------------------------------------
// - Object.hpp                                                              -
// - standard object library - base object declaration                       -
// ---------------------------------------------------------------------------
// - This program is free software;  you can redistribute it  and/or  modify -
// - it provided that this copyright notice is kept intact.                  -
// -                                                                         -
// - This program  is  distributed in  the hope  that it will be useful, but -
// - without  any  warranty;  without  even   the   implied    warranty   of -
// - merchantability or fitness for a particular purpose.  In no event shall -
// - the copyright holder be liable for any  direct, indirect, incidental or -
// - special damages arising in any way out of the use of this software.     -
// ---------------------------------------------------------------------------
// - copyright (c) 1999-2003 amaury darsch                                   -
// ---------------------------------------------------------------------------

#ifndef  ALEPH_OBJECT_HPP
#define  ALEPH_OBJECT_HPP

#ifndef  ALEPH_CCNF_HPP
#include "ccnf.hpp"
#endif

namespace aleph {

  /// The Object class is the foundation of the standard object library .
  /// The object class defines only a reference count field which is used
  /// to control the life of a particular object. When an object is created,
  /// the reference count is set to 0. Such object is said to be transient.
  /// The "iref" static method increment the reference count. The "dref"
  /// method decrement and eventually destroy the object. The "cref" method
  /// eventually destroy an object if its reference count is nulll. The object
  /// class is an abstract class. For each derived object, the repr method
  /// is defined to return the class name. Additionally, the object class
  /// defines a set of methods which are used by the runnable to virtually
  /// modify or evaluate an object. There are two sets of methods. The first
  /// set operates directly on the object. The second set operates by name
  /// on the object. Working by name is equivalent to access a member of a
  /// a particular object. The "cdef" method create or set a constant object
  /// to the calling object. The "vdef" method create or set an object to the
  /// calling object. The "eval" method evaluates an object in the current
  /// runnable nameset. The "apply" method evaluates a set of arguments
  /// and apply them to the calling object. It is somehow equivalent to a 
  /// function call. When called by name, it is equivalent to a method call.
  /// @author amaury darsch

  class Object {
  public:
    enum t_oper {ADD, SUB, MUL, DIV, MINUS, EQL, NEQ, GEQ, LEQ, GTH, LTH};

  private:
    /// object reference count
    long d_rcount;

  protected:
    /// the shared object structure
    struct s_shared* p_shared;

  public:
    /// create a new object
    Object (void);

    /// destroy this object.
    virtual ~Object (void);

    /// @return the class name
    virtual class String repr (void) const =0;

    /// @return an object class name or nil
    static const class String repr (Object* object);
      
    /// @return a clone of this object
    virtual Object* clone (void) const;

    /// make this object shared
    virtual void mksho (void);

    /// get a read lock for this object
    virtual void rdlock (void) const;

    /// get a write lock for this object
    virtual void wrlock (void) const;

    /// unlock this object
    virtual void unlock (void) const;

    /// @return true if the object is shared
    bool issho (void) {
      return (p_shared != nilp);
    }

    /// clear and lock the finalizer
    static void clrfnl (void);

    /// increment the object reference count
    /// @param object the object to process
    static Object* iref (Object* object);

    /// decrement the reference count and destroy the object if null
    /// @param object the object to process
    static void dref (Object* object);

    /// clean this object if the reference count is null
    /// @param object the object to process
    static void cref (Object* object);

    /// decrement the object reference count but do not detroy if null
    /// @param object the object to process
    static void tref (Object* object);

    /// return true if the object has a reference count of 0 or 1
    /// @param object the object to process
    static bool uref (Object* object);

    /// operate this object with another one
    /// @param robj   the current runnable
    /// @param type   the operator type
    /// @param object the operand object
    virtual Object* oper (class Runnable* robj, t_oper type, Object* object);

    /// set an object as a const object
    /// @param robj   the current runnable
    /// @param nset   the current nameset
    /// @param object the object to set
    virtual Object* cdef (class Runnable* robj, class Nameset* nset, 
			  Object* object);

    /// set an object as a const object by quark
    /// @param robj   the current runnable
    /// @param nset   the current nameset
    /// @param quark  the quark to define as const
    /// @param object the object to set
    virtual Object* cdef (class Runnable* robj, class Nameset* nset, 
			  const long quark, Object* object);

    /// set an object to this object
    /// @param robj   the current runnable
    /// @param nset   the current nameset
    /// @param object the object to set
    virtual Object* vdef (class Runnable* robj, class Nameset* nset, 
			  Object* object);

    /// set an object to this object by quark
    /// @param robj   the current runnable
    /// @param nset   the current nameset
    /// @param quark  the quark to set this object
    /// @param object the object to set
    virtual Object* vdef (class Runnable* robj, class Nameset* nset, 
			  const long quark, Object* object);

    /// evaluate an object in the current nameset
    /// @param robj   the current runnable
    /// @param nset   the current nameset
    virtual Object* eval (class Runnable* robj, class Nameset* nset);

    /// evaluate an object in the current nameset by quark
    /// @param robj   the current runnable
    /// @param nset   the current nameset
    /// @param quark  the quark to evaluate in this object
    virtual Object* eval (class Runnable* robj, class Nameset* nset, 
			  const long quark);

    /// apply an object with a set of arguments
    /// @param robj   the current runnable
    /// @param nset   the current nameset 
    /// @param args   the arguments to apply
    virtual Object* apply (class Runnable* robj, class Nameset* nset, 
			   class Cons* args);

    /// apply an object by quark with a set of arguments
    /// @param robj   the current runnable
    /// @param nset   the current nameset    
    /// @param quark  the quark to apply this arguments
    /// @param args   the arguments to apply
    virtual Object* apply (class Runnable* robj, class Nameset* nset, 
			   const long quark, class Cons* args);

    /// apply an object by object with a set of arguments
    /// @param robj   the current runnable
    /// @param nset   the current nameset    
    /// @param object the object to apply this arguments
    /// @param args   the arguments to apply
    virtual Object* apply (class Runnable* robj, class Nameset* nset, 
			   Object* object, class Cons* args);

    /// apply an object with a vector of arguments by quark
    /// @param robj   the current runnable
    /// @param nset   the current nameset    
    /// @param quark  the quark to apply these arguments
    /// @param argv   the vector arguments to apply
    virtual Object* apply (class Runnable* robj, class Nameset* nset, 
			   const long quark, class Vector* argv);

  public:
    // the memory allocation
    void* operator new       (const t_size size);
    void* operator new    [] (const t_size size);
    void  operator delete    (void* handle);
    void  operator delete [] (void* handle);
  };
}

#endif
