// Copyright (C) 1999-2005 Open Source Telecom Corporation.
// Copyright (C) 2006-2008 David Sugar, Tycho Softworks.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// 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.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// As a special exception, you may use this file as part of a free software
// library without restriction.  Specifically, if other files instantiate
// templates or use macros or inline functions from this file, or you compile
// this file and link it with other files to produce an executable, this
// file does not by itself cause the resulting executable to be covered by
// the GNU General Public License.  This exception does not however
// invalidate any other reasons why the executable file might be covered by
// the GNU General Public License.
//
// This exception applies only to the code released under the name GNU
// Common C++.  If you copy code from other releases into a copy of GNU
// Common C++, as the General Public License permits, the exception does
// not apply to the code that you add in this way.  To avoid misleading
// anyone as to the status of such modified files, you must delete
// this exception notice from them.
//
// If you write modifications of your own for GNU Common C++, it is your choice
// whether to permit this exception to apply to your modifications.
// If you do not wish that, delete this exception notice.
//

/**
 * @file object.h
 * @short Some object manipulation classes for smart pointers, linked lists,
 * etc.
 **/

#ifndef	CCXX_OBJECT_H_
#define	CCXX_OBJECT_H_

#ifndef CCXX_MISSING_H_
#include <cc++/missing.h>
#endif

#ifdef	CCXX_NAMESPACES
namespace ost {
#endif

class __EXPORT MapObject;
class __EXPORT MapIndex;

/**
 * A reference countable object.  This is used in association with smart
 * pointers (RefPointer).
 *
 * @author David Sugar <dyfet@gnutelephony.org>
 * @short Object managed by smart pointer reference count.
 */
class __EXPORT RefObject
{
protected:
	friend class RefPointer;

	unsigned refCount;

	/**
	 * The constructor simply initializes the count.
	 */
	inline RefObject()
		{refCount = 0;};

	/**
	 * The destructor is called when the reference count returns
	 * to zero.  This is done through a virtual destructor.
	 */
	virtual ~RefObject();

public:
	/**
	 * The actual object being managed can be returned by this
	 * method as a void and then recast to the actual type.  This
	 * removes the need to dynamic cast from RefObject and the
	 * dependence on rtti this implies.
	 *
	 * @return underlying object being referenced.
	 */
	virtual void *getObject(void) = 0;
};

/**
 * Pointer to reference counted objects.  This is a non-template form
 * of a reference count smart pointer, and so uses common code.  This
 * can be subclassed to return explicit object types.
 *
 * @author David Sugar <dyfet@gnutelephony.org>
 * @short Pointer to reference count managed objects.
 */
class __EXPORT RefPointer
{
protected:
	RefObject *ref;

	/**
	 * Detach current object, for example, when changing pointer.
	 */
	void detach(void);

	/**
	 * Patch point for mutex in derived class.  This may often
	 * be a single static mutex shared by a managed type.
	 */
	virtual void enterLock(void);

	/**
	 * Patch point for a mutex in derived class.  This may often
	 * be a single static mutex shared by a managed type.
	 */
	virtual void leaveLock(void);

public:
	/**
	 * Create an unattached pointer.
	 */
	inline RefPointer()
		{ref = NULL;};

	/**
	 * Create a pointer attached to a reference counted object.
	 *
	 * Object being referenced.
	 */
	RefPointer(RefObject *obj);

	/**
	 * A copy constructor.
	 *
	 * Pointer being copied.
	 */
	RefPointer(const RefPointer &ptr);

	virtual ~RefPointer();

	RefPointer& operator=(const RefObject &ref);

	inline void *operator*() const
		{return getObject();};

	inline void *operator->() const
		{return getObject();};

	void *getObject(void) const;

	bool operator!() const;
};

/**
 * Self managed single linked list object chain.  This is used for
 * accumulating lists by using as a base class for a derived subclass.
 *
 * @author David Sugar <dyfet@gnutelephony.org>
 * @short Accumulating single linked list.
 */
class __EXPORT LinkedSingle
{
protected:
	LinkedSingle *nextObject;

	inline LinkedSingle()
		{nextObject = NULL;};

	virtual ~LinkedSingle();

public:
	/**
	 * Get first linked object in list.  This may be dynamically
	 * recast, and may refer to a master static bookmark pointer
	 * in a derived class.  Otherwise it simply returns the current
	 * object.  In a "free" list, this may not only return the first
	 * object, but also set the first to next.
	 *
	 * @return pointer to first object in list.
	 */
	virtual LinkedSingle *getFirst(void);

	/**
	 * Gets the last object in the list.  This normally follows the
	 * links to the end.  This is a virtual because derived class
	 * may include a static member bookmark for the current end.
	 *
	 * @return pointer to last object in list.
	 */
	virtual LinkedSingle *getLast(void);

	/**
	 * Get next object, for convenience.  Derived class may use
	 * this with a dynamic cast.
	 *
	 * @return next object in list.
	 */
	inline LinkedSingle *getNext(void)
		{return nextObject;};

	/**
	 * Insert object into chain.  This is a virtual because
	 * derived class may choose instead to perform an insert
	 * at head or tail, may manage bookmarks, and may add mutex lock.
	 *
	 * @param object being inserted.
	 */
	virtual void insert(LinkedSingle& obj);

	LinkedSingle &operator+=(LinkedSingle &obj);
};

/**
 * Self managed double linked list object chain.  This is used for
 * accumulating lists by using as a base class for a derived subclass.
 *
 * @author David Sugar <dyfet@gnutelephony.org>
 * @short Accumulating double linked list.
 */
class __EXPORT LinkedDouble
{
protected:
	LinkedDouble *nextObject, *prevObject;

	inline LinkedDouble()
		{nextObject = prevObject = NULL;};

	virtual ~LinkedDouble();

	virtual void enterLock(void);

	virtual void leaveLock(void);

public:

  /**
   * Requested in overloaded insert() method to indicate how to insert
   * data into list
   */
  enum InsertMode
  {
    modeAtFirst,  /**< insert at first position in list pointed by current object */
    modeAtLast,   /**< insert at last position in list pointed by current object */
    modeBefore,   /**< insert in list before current object */
    modeAfter     /**< insert in list after current object */
  };

	/**
	 * Get first linked object in list.  This may be dynamically
	 * recast, and may refer to a master static bookmark pointer
	 * in a derived class.  Otherwise it follows list to front.
	 *
	 * @return pointer to first object in list.
	 */
	virtual LinkedDouble *getFirst(void);

	/**
	 * Gets the last object in the list.  This normally follows the
	 * links to the end.  This is a virtual because derived class
	 * may include a static member bookmark for the current end.
	 *
	 * @return pointer to last object in list.
	 */
	virtual LinkedDouble *getLast(void);

	/**
	 * Virtual to get the insert point to use when adding new members.  This
	 * may be current, or always head or always tail.  As a virtual, this allows
	 * derived class to establish "policy".
	 *
	 * @return pointer to insertion point in list.
	 */
	virtual LinkedDouble *getInsert(void);

	/**
	 * Get next object, for convenience.  Derived class may use
	 * this with a dynamic cast.
	 *
	 * @return next object in list.
	 */
	inline LinkedDouble *getNext(void)
		{return nextObject;};

	/**
	 * Get prev object in the list.
	 *
	 * @return pointer to previous object.
	 */
	inline LinkedDouble *getPrev(void)
		{return prevObject;};

  /**
   * Insert object into chain at given position, as indicated by \ref InsertMode;
   * If no position is given, it defaults to \ref modeAtLast, inserting element
   * at list's end.
   *
   * @param object being inserted.
   * @param position where object is inserted.
   */
  virtual void insert(LinkedDouble& obj, InsertMode position = modeAtLast);

	/**
	 * Remove object from chain.
	 */
	virtual void detach(void);

	LinkedDouble &operator+=(LinkedDouble &obj);

	LinkedDouble &operator--();
};

/**
 * A map table allows for entities to be mapped (hash index) onto it.
 * Unlike with Assoc, This form of map table also allows objects to be
 * removed from the table.  This table also includes a mutex lock for
 * thread safety.  A free list is also optionally maintained for reusable
 * maps.
 *
 * @author David Sugar <dyfet@gnutelephony.org>
 * @short Table to hold hash indexed objects.
 */
class __EXPORT MapTable : public Mutex
{
protected:
	friend class MapObject;
	friend class MapIndex;
	unsigned range;
  unsigned count;
	MapObject **map;

	void cleanup(void);

public:
	/**
	 * Create a map table with a specified number of slots.
	 *
	 * @param number of slots.
	 */
	MapTable(unsigned size);

	/**
	 * Destroy the table, calls cleanup.
	 */
	virtual ~MapTable();

	/**
	 * Get index value from id string.  This function can be changed
	 * as needed to provide better collision avoidence for specific
	 * tables.
	 *
	 * @param id string
	 * @return index slot in table.
	 */
	virtual unsigned getIndex(const char *id);

	/**
	 * Return range of this table.
	 *
	 * @return table range.
	 */
	inline unsigned getRange(void)
		{return range;};

	/**
	 * Return the number of object stored in this table.
	 *
	 * @return table size.
	 */
	inline unsigned getSize(void)
		{return count;};

	/**
	 * Lookup an object by id key.  It is returned as void * for
	 * easy re-cast.
	 *
	 * @param key to find.
	 * @return pointer to found object or NULL.
	 */
	void *getObject(const char *id);

	/**
	 * Map an object to our table.  If it is in another table
	 * already, it is removed there first.
	 *
	 * @param object to map.
	 */
	void addObject(MapObject &obj);
	/**
	 * Get the first element into table, it is returned as void * for
	 * easy re-cast.
	 *
	 * @return pointer to found object or NULL.
	 */
	void *getFirst();

	/**
	 * Get the last element into table, it is returned as void * for
	 * easy re-cast.
	 *
	 * @return pointer to found object or NULL.
	 */
	void *getLast();

	/**
	 * Get table's end, useful for cycle control; it is returned as void * for
	 * easy re-cast.
	 *
	 * @return pointer to found object or NULL.
	 */
	void *getEnd()
		{	return NULL;	};

	/**
	 * Get next object from managed free list.  This returns as a
	 * void so it can be recast into the actual type being used in
	 * derived MapObject's.  A derived version of MapTable may well
	 * offer an explicit type version of this.  Some derived
	 * MapObject's may override new to use managed list.
	 *
	 * @return next object on free list.
	 */
	void *getFree(void);

	/**
	 * Add an object to the managed free list.  Some MapObject's
	 * may override delete operator to detach and do this.
	 *
	 * @param object to add.
	 */
	void addFree(MapObject *obj);

	/**
	 * An operator to map an object to the table.
	 *
	 * @return table being used.
	 * @param object being mapped.
	 */
	MapTable &operator+=(MapObject &obj);

	/**
	 * This operator is virtual in case it must also add the object to a
	 * managed free list.
	 *
	 * @return current table.
	 * @param object entity to remove.
	 */
	virtual MapTable &operator-=(MapObject &obj);
};

/**
 * The MapIndex allows linear access into a MapTable, that otherwise could have 
 * its elements being retrieved only by key.
 * It can be increased, checked and dereferenced like a pointer, by means of
 * suitable operators.
 *
 * @author Sergio Repetto <s.repetto@pentaengineering.it>
 * @short Index object to access MapTable elements
 */
class __EXPORT MapIndex
{
	MapObject*	thisObject;

public :

	/**
	 * Creates an empty map index (pointing to nothing).
	 */
	MapIndex() : thisObject(NULL)
	{};

	/**
	 * Creates a map index pointing to a specific map object
	 *
	 * @param the indexed object
	 */
	MapIndex(MapObject* theObject) : thisObject(theObject)
	{};

	/**
	 * Creates a copy of a given map index
	 *
	 * @param the source index object
	 */
	MapIndex(const MapIndex& theIndex) : thisObject(theIndex.thisObject)
	{};

	/**
	 * Dereference operator: the pointed object it is returned as void * for
	 * easy re-cast.
	 *
	 * @return pointer to indexed object.
	 */
  void* operator*() const 
  {	return (void*)thisObject;	}

	/**
	 * Assignment operator to avoid implicit cast.
	 *
	 * @return the object itself, as changed.
	 */
	MapIndex& operator=(MapObject *theObject);

	/**
	 * Prefix increment operator, to be used in loops and such.
	 *
	 * @return the object itself, as changed.
	 */
  MapIndex& operator++();			// prefix

	/**
	 * Postfix increment operator, to be used in loops and such.
	 *
	 * @return the object itself, as changed.
	 */
  MapIndex  operator++(int) 	// postfix
	{	return this->operator++();	}

	/**
	 * Comparison operator, between two MapIndex's.
	 *
	 * @return the object itself, as changed.
	 */
	bool operator==(const MapIndex& theIndex) const
	{	return thisObject == theIndex.thisObject;	};

	bool operator!=(const MapIndex& theIndex) const
	{	return !(*this == theIndex);	};

	/**
	 * Comparison operator, between the MapIndex and a MapObject, useful to avoid
   * casts for sake of clearness.
	 *
	 * @return the object itself, as changed.
	 */
	bool operator==(const MapObject* theObject) const
	{	return thisObject == theObject;	};

	bool operator!=(const MapObject* theObject) const
	{	return !(*this == theObject);	};
};

/**
 * The MapObject is a base class which can be used to make a derived
 * class operate on a MapTable.  Derived classes may override new and
 * delete operators to use managed free list from a MapTable.
 *
 * @author David Sugar <dyfet@gnutelephony.org>
 * @short Mappable object.
 */
class __EXPORT MapObject
{
protected:
	friend class MapTable;
	friend class MapIndex;
	MapObject *nextObject;
	const char *idObject;
	MapTable *table;

public:

	/**
	 * Remove the object from it's current table.
	 */
	void detach(void);

	/**
	 * Save id, mark as not using any table.
	 *
	 * @param id string for this object.
	 */
	MapObject(const char *id);
};

#ifdef	CCXX_NAMESPACES
}
#endif

#endif

/** EMACS **
 * Local variables:
 * mode: c++
 * c-basic-offset: 8
 * End:
 */
