// Public interface to almost all of AtlasObject.
// (See AtlasObjectText for the rest of it).
//
// Tries to include as few headers as possible, to minimise its impact
// on compile times.

#ifndef ATLASOBJECT_H__
#define ATLASOBJECT_H__

#include <wchar.h> // for wchar_t

//////////////////////////////////////////////////////////////////////////
// Mostly-private bits:

// Simple reference-counted pointer. class T must contain a reference count,
// initialised to 0. An external implementation (in AtlasObjectImpl.cpp)
// provides the inc_ref and dec_ref methods, so that this header file doesn't
// need to know their implementations.
template<class T> class AtSmartPtr
{
public:
	// Constructors
	AtSmartPtr() : ptr(NULL) {}
	explicit AtSmartPtr(T* p) : ptr(p) { inc_ref(); }
	// Copy constructor
	AtSmartPtr(const AtSmartPtr<T>& r) : ptr(r.ptr) { inc_ref(); }
	// Assignment operators
	AtSmartPtr<T>& operator=(T* p) { dec_ref(); ptr = p; inc_ref(); return *this; }
	AtSmartPtr<T>& operator=(const AtSmartPtr<T>& r) { if (&r != this) { dec_ref(); ptr = r.ptr; inc_ref(); } return *this; }
	// Destructor
	~AtSmartPtr() { dec_ref(); }
	// Allow conversion from non-const T* to const T*
	operator AtSmartPtr<const T> () { return AtSmartPtr<const T>(ptr); }
	// Override ->
	T* operator->() const { return ptr; }
	// Test whether the pointer is pointing to anything
	operator bool() const { return ptr!=NULL; }
	bool operator!() const { return ptr==NULL; }
private:
	void inc_ref();
	void dec_ref();
	T* ptr;
};

// A few required declarations
class AtObj;
class AtNode;
class AtIterImpl;


//////////////////////////////////////////////////////////////////////////
// Public bits:


// AtIter is an iterator over AtObjs - use it like:
//
//     for (AtIter thing = whatever["thing"]; thing.defined(); ++thing)
//         DoStuff(thing);
//
// to handle XML data like:
//
//   <whatever>
//     <thing>Stuff 1</thing>
//     <thing>Stuff 2</thing>
//   </whatever>

class AtIter
{
public:
	// Increment the iterator; or make it undefined, if there weren't any
	// AtObjs left to iterate over
	AtIter& operator ++ ();
	// Return whether this iterator has an AtObj to point to
	bool defined() const;
	// Return whether this iterator is pointing to a non-contentless AtObj
	bool hasContent() const;

	// Return an iterator to the children matching 'key'. (That is, children
	// of the AtObj currently pointed to by this iterator)
	const AtIter operator [] (const char* key) const;

	// Return the AtObj currently pointed to by this iterator
	operator const AtObj () const;

	// Return the string value of the AtObj currently pointed to by this iterator
	operator const wchar_t* () const;

#ifdef __WXWINDOWS__
	// Wrapper function around 'operator wchar_t*', for convenience in wx programs
	operator const wxString () const { return (const wchar_t*)*this; }
#endif

	// Private implementation. (But not 'private:', because it's a waste of time
	// adding loads of friend functions)
	AtSmartPtr<AtIterImpl> p;
};


class AtObj
{
public:
	AtObj() {}
	AtObj(const AtObj& r) : p(r.p) {}

	// Return an iterator to the children matching 'key'
	const AtIter operator [] (const char* key) const;

	// Return the string value of this object
	operator const wchar_t* () const;

	// Check whether the object contains anything (even if those things are empty)
	bool defined() const { return (bool)p; }
	
	// Check recursively whether there's actually any non-empty data in the object
	bool hasContent() const;

	// Add or set a child. The wchar_t* versions create a new AtObj with
	// the appropriate string value, then use that as the child.
	//
	// These alter the AtObj's internal pointer, and the pointed-to data is
	// never actually altered. Copies of this AtObj (including copies stored
	// inside other AtObjs) will not be affected.
	void add(const char* key, const wchar_t* value);
	void add(const char* key, AtObj& data);
	void set(const char* key, const wchar_t* value);
	void set(const char* key, AtObj& data);
	void setString(const wchar_t* value);

	AtSmartPtr<const AtNode> p;
};


// Miscellaneous utility functions:
namespace AtlasObject
{
	// Returns AtObj() on failure - test with AtObj::defined()
	AtObj LoadFromXML(const wchar_t* filename);

	// Returns false on failure
	bool SaveToXML(AtObj& obj, const wchar_t* filename);

	AtObj TrimEmptyChildren(AtObj& obj);
};

#endif // ATLASOBJECT_H__
