// Copyright (C) 1999-2005 Open Source Telecom Corporation.
//
// 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 misc.h
 * @short Memory management, configuration keydata objects and string
 * tokenizer.
 **/

#ifndef	CCXX_MISC_H_
#define	CCXX_MISC_H_

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

#ifndef CCXX_THREAD_H_
#include <cc++/thread.h>
#endif

#define	KEYDATA_INDEX_SIZE	97
#define	KEYDATA_PAGER_SIZE	512

#if defined(PATH_MAX)
#if PATH_MAX > 512
#define KEYDATA_PATH_SIZE	512
#else
#define	KEYDATA_PATH_SIZE	PATH_MAX
#endif
#else
#define	KEYDATA_PATH_SIZE	256
#endif

#ifdef	CCXX_NAMESPACES
namespace ost {
#endif

class __EXPORT Runlist;
class __EXPORT Runable;

/**
 * The memory pager is used to allocate cumulative memory pages for
 * storing object specific "persistant" data that is presumed to persist
 * during the life of a given derived object.  When the object is
 * destroyed, all accumulated data is automatically purged.
 * 
 * There are a number of odd and specialized utility classes found in Common
 * C++.  The most common of these is the "MemPager" class.  This is basically
 * a class to enable page-grouped "cumulative" memory allocation; all
 * accumulated allocations are dropped during the destructor.  This class has
 * found it's way in a lot of other utility classes in Common C++.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short Accumulative object memory allocator.
 */
class __EXPORT MemPager
{
private:
	friend class String;
	friend class MemPagerObject;

	size_t pagesize;
	unsigned int pages;

	struct _page
	{
		struct _page *next;
		size_t used;
	} *page;

protected:
	/**
	 * Allocate first workspace from paged memory.  This method
	 * scans all currently allocated blocks for available space
	 * before adding new pages and hence is both slower and more
	 * efficient.
	 *
	 * @param size size of memory to allocate.
	 * @return pointer to allocated memory.
	 */
	virtual void* first(size_t size);

	/**
	 * Allocate memory from either the currently active page, or
	 * allocate a new page for the object.
	 *
	 * @param size size of memory to allocate.
	 * @return pointer to allocated memory.
	 */
	virtual void* alloc(size_t size);

	/**
	 * Allocate a string from the memory pager pool and copy the
	 * string into it's new memory area.  This method allocates
	 * memory by first searching for an available page, and then
	 * allocating a new page if no space is found.
	 *
	 * @param str string to allocate and copy into paged memory pool.
	 * @return copy of string from allocated memory.
	 */
	char* first(char *str);

	/**
	 * Allocate a string from the memory pager pool and copy the
	 * string inti it's new memory area.  This checks only the
	 * last active page for available space before allocating a
	 * new page.
	 *
	 * @param str string to allocate and copy into paged memory pool.
	 * @return copy of string from allocated memory.
	 */
	char* alloc(const char *str);

	/**
	 * Create a paged memory pool for cumulative storage.  This
	 * pool allocates memory in fixed "pagesize" chunks.  Ideal
	 * performance is achived when the pool size matches the
	 * system page size.  This pool can only exist in derived
	 * objects.
	 *
	 * @param pagesize page size to allocate chunks.
	 */
	MemPager(size_t pagesize = 4096);

	/**
	 * purge the current memory pool.
	 */
	void purge(void);

	/**
	 * Delete the memory pool and all allocated memory.
	 */
	virtual ~MemPager();

public:
	/**
	 * Return the total number of pages that have been allocated
	 * for this memory pool.
	 *
	 * @return number of pages allocated.
	 */
	inline int getPages(void)
		{return pages;};
};

/**
 * The StackPager provides a repository to stash and retrieve working
 * data in last-in-first-out order.  The use of a mempager to support
 * it's operation allows storage of arbitrary sized objects with no
 * fixed limit.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short last in first out object pager.
 */
class __EXPORT StackPager : protected MemPager
{
private:
	typedef struct frame
	{
		struct frame *next;
		char data[1];
	}	frame_t;

	frame_t *stack;

public:
	/**
	 * Create a lifo pager as a mempager.
	 *
	 * @param page size for allocation
	 */
	StackPager(size_t pagesize);

	/**
	 * Push an arbitrary object onto the stack.
	 *
	 * @return stack memory location.
	 * @param pointer to data
	 * @param size of data.
	 */
	void *push(const void *object, size_t len);

	/**
	 * Push a string onto the stack.
	 *
	 * @return stack memory location.
	 * @param string pointer.
	 */
	void *push(const char *string);

	/**
	 * Retrieve next object from stack.
	 *
	 * @return object.
	 */
	void *pull(void);

	/**
	 * Purge the stack of all objects and memory allocations.
	 */
	void purge(void);
};

/**
 * The shared mempager uses a mutex to protect key access methods.
 * This class is used when a mempager will be shared by multiple
 * threads.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short mutex protected memory pager.
 */
class __EXPORT SharedMemPager : public MemPager, public Mutex
{
protected:
	/**
	 * Create a mempager mutex pool.
	 *
	 * @param pagesize page size for allocation.
	 * @param name a name for the pool.
	 */
	SharedMemPager(size_t pagesize = 4096, const char *name = NULL);

	/**
	 * Purge the memory pool while locked.
 	 */
	void purge(void);

	/**
	 * Get the first memory page after locking.
	 *
	 * @return allocated memory space.
	 * @param size of request.
	 */
	void* first(size_t size);

	/**
	 * Get the last memory page after locking.
	 *
	 * @return allocated memory space.
	 * @param size of request.
	 */
	void* alloc(size_t size);
};

/**
 * Keydata objects are used to load and hold "configuration" data for
 * a given application.
 *
 * This class is used to load and then hold "<code>keyword = value</code>" pairs parsed from a text
 * based "config" file that has been divided into "<code>[sections]</code>". The syntax is:
 *
 * <code><pre>
 * [section_name]
 * key1=value1
 * key2=value2</pre></code>
 *
 * Essentially, the "path" is a "keypath" into a theoretical namespace of key
 * pairs, hence one does not use "real" filepaths that may be OS dependent. The "<code>/</code>" path refers
 * to "<code>/etc</code>" prefixed (on UNIX) directories and this is processed within the constructor. It
 * could refer to the <code>/config</code> prefix on QNX, or even, gasp, a "<code>C:\WINDOWS</code>". Hence, a keypath of
 * "<code>/bayonne.d/vmhost/smtp</code>" actually resolves to a "<code>/etc/bayonne.d/vmhost.conf</code>" and loads key
 * value pairs from the <code>[smtp]</code> section of that <code>.conf</code> file. 
 *
 * Similarly, something like "<code>~bayonne/smtp</code>" path refers to a "<code>~/.bayonnerc</code>" and loads key pairs
 * from the <code>[smtp]</code> section. This coercion occurs before the name is passed to the open call. 
 *
 * I actually use derived keydata based classes as global initialized objects, and they hence
 * automatically load and parse config file entries even before "main" has started. 
 *
 * Keydata can hold multiple values for the same key pair.  This can
 * occur either from storing a "list" of data items in a config file,
 * or when overlaying multiple config sources (such as <code>/etc/....conf</code> and
 * <code>~/.confrc</code> segments) into a single object.  The keys are stored as
 * cumulative (read-only/replacable) config values under a hash index
 * system for quick retrieval.
 * 
 * Keydata can
 * also load a table of "initialization" values for keyword pairs that were
 * not found in the external file.
 *
 * One typically derives an application specific keydata class to load a
 * specific portion of a known config file and initialize it's values.  One
 * can then declare a global instance of these objects and have
 * configuration data initialized automatically as the executable is loaded.
 * 
 * Hence, if I have a "[paths]" section in a "<code>/etc/server.conf?</code>" file, I might
 * define something like:
 *
 * <code><pre>
 * class KeyPaths : public Keydata
 * {
 *   public:
 *     KeyPaths() : Keydata("/server/paths")
 *     {
 *       static Keydata::Define *defvalues = {
 * 	  {"datafiles", "/var/server"},
 * 	  {NULL, NULL}};
 * 
 *       // override with [paths] from "~/.serverrc" if avail.
 * 
 *       load("~server/paths");
 *       load(defvalues);
 *     }
 * };
 * 
 * KeyPaths keypaths;
 * </pre></code>
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short load text configuration files into keyword pairs.
 */
class __EXPORT Keydata : protected MemPager
{
public:
#if defined(__GNUC__) || !defined(__hpux)
#pragma pack(1)
#endif

	struct Keyval
	{
		Keyval *next;
		char val[1];
	};

	struct Keysym
	{
		Keysym *next;
		Keyval *data;
		const char **list;
		short count;
		char sym[1];
	};

	struct Define
	{
		char *keyword;
		char *value;
	};

#if defined(__GNUC__) || !defined(__hpux)
#pragma pack()
#endif

private:
	static std::ifstream *cfgFile;
	static char lastpath[KEYDATA_PATH_SIZE + 1];
	static int count;
	static int sequence;

	int link;

	Keysym *keys[KEYDATA_INDEX_SIZE];

	/**
	 * Compute a hash key signature id for a symbol name.
	 *
	 * @return key signature index path.
	 * @param sym symbol name.
	 */
	unsigned getIndex(const char *sym);

protected:
	Keysym* getSymbol(const char *sym, bool create);

public:
	/**
	 * Load additional key values into the currrent object from
	 * the specfied config source (a config file/section pair).
	 * These values will overlay the current keywords when matches
	 * are found.  This can be used typically in a derived config
	 * object class constructor to first load a <code>/etc</code> section, and
	 * then load a matching user specific entry from <code>~/.</code> to override
	 * default system values with user specific keyword values.
	 *
	 * @param keypath (filepath/section)
	 */ 
	void load(const char *keypath);

	/**
	 * Load additional key values into the currrent object from
	 * the specfied config source (a config file/section pair).
	 * These values will overlay the current keywords when matches
	 * are found.  This can be used typically in a derived config
	 * object class constructor to first load a <code>/etc</code> section, and
	 * then load a matching user specific entry from <code>~/.</code> to override
	 * default system values with user specific keyword values.
	 * This varient puts a prefix in front of the key name.
	 *
	 * @param prefix
	 * @param keypath (filepath/section)
	 */ 
	void loadPrefix(const char *prefix, const char *keypath);

	/**
	 * Load additional keys into the current object using a real
	 * filename that is directly passed rather than a computed key
	 * path.  This also uses a [keys] section as passed to the object.
	 *
	 * @param filename to load from
	 * @param key value set to parse, or NULL to parse from head
	 * @param optional key prefix
	 */
	void loadFile(const char *filepath, const char *keys = NULL, const char *pre = NULL);

	/**
	 * Load default keywords into the current object.  This only
	 * loads keyword entries which have not already been defined
	 * to reduce memory usage.  This form of Load is also commonly
	 * used in the constructor of a derived Keydata class.
	 *
	 * @param pairs list of NULL terminated default keyword/value pairs.
	 */
	void load(Define *pairs);
	
	/**
	 * Create an empty key data object.
	 */
	Keydata();

	/**
	 * Create a new key data object and use "Load" method to load an
	 * initial config file section into it.
	 *
	 * @param keypath (filepath/section)
	 * specifies the home path.
	 */
	Keydata(const char *keypath);

	/**
	 * Alternate constructor can take a define list and an optional
	 * pathfile to parse.
	 *
	 * @param define list
	 * @param keypath (filepath/section)
	 */
	Keydata(Define *pairs, const char *keypath = NULL);

	/**
	 * Destroy the keydata object and all allocated memory.  This
	 * may also clear the "cache" file stream if no other keydata
	 * objects currently reference it.
	 */
	virtual ~Keydata();

	/**
	 * Unlink the keydata object from the cache file stream.  This
	 * should be used if you plan to keepa Keydata object after it
	 * is loaded once all keydata objects have been loaded, otherwise
	 * the cfgFile stream will remain open.  You can also use
	 * endKeydata().
	 */
	void unlink(void);

	/**
	 * Get a count of the number of data "values" that is associated
	 * with a specific keyword.  Each value is from an accumulation of
	 * "<code>load()</code>" requests.
	 *
	 * @param sym keyword symbol name.
	 * @return count of values associated with keyword.
	 */
	int getCount(const char *sym);

	/**
	 * Get the first data value for a given keyword.  This will
	 * typically be the <code>/etc</code> set global default.
	 *
	 * @param sym keyword symbol name.
	 * @return first set value for this symbol.
	 */
	const char* getFirst(const char *sym);

	/**
	 * Get the last (most recently set) value for a given keyword.
	 * This is typically the value actually used.
	 *
	 * @param sym keywork symbol name.
	 * @return last set value for this symbol.
	 */
	const char* getLast(const char *sym);

	/**
	 * Get an index array of ALL keywords that are stored by the
	 * current keydata object.
	 *
	 * @return number of keywords found.
	 * @param data pointer of array to hold keyword strings.
	 * @param max number of entries the array can hold.
	 */
	unsigned getIndex(char **data, unsigned max);

	/**
	 * Get the count of keyword indexes that are actually available
	 * so one can allocate a table to receive getIndex.
	 *
	 * @return number of keywords found.
	 */
	unsigned getCount(void);

	/**
	 * Set (replace) the value of a given keyword.  This new value
	 * will become the value returned from getLast(), while the
	 * prior value will still be stored and found from <code>getList()</code>.
	 *
	 * @param sym keyword name to set.
	 * @param data string to store for the keyword.
	 */
	void setValue(const char *sym, const char *data);

	/**
	 * Return a list of all values set for the given keyword
	 * returned in order.
	 *
	 * @return list pointer of array holding all keyword values.
	 * @param sym keyword name to fetch.
	 */
	const char * const* getList(const char *sym);

	/**
	 * Clear all values associated with a given keyword.  This does
	 * not de-allocate the keyword from memory, however.
	 *
	 * @return keyword name to clear.
	 */
	void clrValue(const char *sym);

	/**
	 * A convient notation for accessing the keydata as an associative
	 * array of keyword/value pairs through the [] operator.
	 */
	inline const char *operator[](const char *keyword)
		{return getLast(keyword);};

	/**
	 * static member to end keydata i/o allocations.
	 */
	static void end(void);

	/**
	 * Shutdown the file stream cache.  This should be used before
	 * detaching a deamon, <code>exec()</code>, <code>fork()</code>, etc.
	 */
	friend inline void endKeydata(void)
		{Keydata::end();};
};

/**
 * This class is used to create derived classes which are constructed
 * within a memory pager pool.  
 *
 * @short create objects in a memory pager.
 * @author David Sugar <dyfet@ostel.com>
 */
class __EXPORT MemPagerObject
{
public:
	/**
	 * Allocate memory from a memory pager.
	 *
	 * @param size of new passed from operator.
	 * @param pager to allocate from.
	 */
	inline void *operator new(size_t size, MemPager &pager)
		{return pager.alloc(size);};

	/**
	 * Allocate array from a memory pager.
	 *
	 * @param size of new passed from operator.
	 * @param pager to allocate from.
	 */
	inline void *operator new[](size_t size, MemPager &pager)
		{return pager.alloc(size);};

	/**
	 * Mempager delete does nothing; the pool purges.
	 */
	inline void operator delete(void *) {};

	/**
	 * Array mempager delete does nothing; the pool purges.
	 */
	inline void operator delete[](void *) {};
};

/**
 * This class is used to associate (object) pointers with named strings.
 * A virtual is used to allocate memory which can be overriden in the
 * derived class.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short associate names with pointers.
 */
class __EXPORT Assoc
{
private:
	class __EXPORT entry
	{
	public:
		const char *id;
		entry *next;
		void *data;
	};

	entry *entries[KEYDATA_INDEX_SIZE];

protected:
	Assoc();

	void clear(void);

	virtual void *getMemory(size_t size) = 0;

public:
	void *getPointer(const char *id);
	void setPointer(const char *id, void *data);
};

/**
 * A runlist is used to restrict concurrent exection to a limited set
 * of concurrent sessions, much like a semaphore.  However, the runlist
 * differs in that it notifies objects when they become ready to run,
 * rather than requiring them to wait and "block" for the semaphore
 * count to become low enough to continue.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short list of runable objects.
 */
class __EXPORT Runlist : public Mutex
{
private:
	Runable *first, *last;

protected:
	unsigned limit, used;
	void check(void);

public:
	/**
	 * Create a new runlist with a specified limit.
	 *
	 * @param limit before wait queuing.
	 */
	Runlist(unsigned count = 1);
	
	/**
	 * Add a runable object to this runlist.  If the number of
	 * entries running is below the limit, then add returns true
	 * otherwise the entry is added to the list.
	 *
	 * @return true if immediately ready to run
	 * @param runable object.
	 */
	bool add(Runable *run);

	/**
	 * Remove a runable object from the wait list or notify when
	 * it is done running so that the used count can be decremented.
	 *
	 * @param runable object.
	 */
	void del(Runable *run);

	/**
	 * Set the limit.
	 *
	 * @param limit to use.
	 */
	void set(unsigned limit);
};

/**
 * A container for objects that can be queued against a runlist.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short runable object with notify when ready.
 */
class __EXPORT Runable
{
private:
	friend class __EXPORT Runlist;
	Runlist *list;
	Runable *next, *prev;

protected:
	Runable();
	virtual ~Runable();

	/**
	 * Method handler that is invoked when a wait-listed object
	 * becomes ready to run.
	 */
	virtual void ready(void) = 0;

public:
	/** 
	 * Start the object against a run list.
	 *
	 * @return true if immediately available to run.
	 * @param list to start under.
	 */
	bool starting(Runlist *list);
	
	/**
	 * Stop the object, called when stopping or ready completes.
	 * May also be used for a task that has not yet started to
	 * remove it from the wait list.
	 */
	void stoping(void);
};

#ifdef	CCXX_NAMESPACES
}
#endif

#endif

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