/*
	Copyright (C) 2000 Nicolas Brodu, nicolas.brodu@free.fr
	                   Stefan Westerfeld, stefan@space.twc.de

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.
  
    This library 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
    Library General Public License for more details.
   
    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/

/*
 * BC - Status (2002-03-08): Reference, SubClass, Object, DynamicCast.
 *
 * Part of the public API. Must be kept binary compatible by NOT TOUCHING
 * AT ALL. Interaction with generated and written code.
 */


#ifndef MCOP_REFERENCE_H
#define MCOP_REFERENCE_H

#include "common.h"
#include <string>
#include <vector>

#include "arts_export.h"

namespace Arts {

// Acts as a string or ObjectReference, but enables a different constructor
class ARTS_EXPORT Reference {
private:
	ObjectReference myref;
	std::string mys;
	bool strMode;
public:
	
	inline explicit Reference(const ObjectReference& ref) {
		myref=ref;
		strMode=false;
	}

	inline explicit Reference(const std::string& s) {
		mys=s;
		strMode=true;
	}
	
	inline explicit Reference(const char* c) {
		mys=c;
		strMode=true;
	}
	inline Reference& operator=(const std::string& s) {
		mys=s;
		strMode=true;
		return *this;
	}
	inline Reference& operator=(const char*c) {
		mys=c;
		strMode=true;
		return *this;
	}
	inline bool isString() const {return strMode;}
//	inline operator const std::string() const {return mys;}
	inline const std::string& string() const {return mys;}
//	inline operator const ObjectReference() const {return myref;}
	inline const ObjectReference& reference() const {return myref;}
};

// Acts as a string, but enables a different constructor
class ARTS_EXPORT SubClass {
private:
	std::string mys;
public:

	inline explicit SubClass(const std::string& s) : mys(s) {}
	inline explicit SubClass(const char* c) : mys(c) {}
	inline SubClass& operator=(const std::string& s) {mys=s; return *this;}
	inline SubClass& operator=(const char*c) {mys=c; return *this;}
//	inline operator const std::string() const {return mys;}
	inline const std::string& string() const {return mys;}
};


class ScheduleNode;
class FlowSystem;

// Object has _no_ virtual, and must not have. That way, all the
// wrappers can be passed as argument or return type, and there is also
// no virtual table bloat.
// Moreover, the virtual mechanism still works correctly thanks to the
// _pool->base redirection.
class ARTS_EXPORT Object {
protected:
	// Pool of common variables for a bunch a wrappers
	class Pool {
		friend class Object;
		Object_base* (*creator)();
		bool created;
		int count;
	public:
		Object_base* base;
		inline Pool(Object_base* b)
			: creator(0), created(true), count(1), base(b) {}
		inline Pool(Object_base* (*cor)())
			: creator(cor), created(false), count(1), base(0) {}
		inline void Inc() {count++;}
		inline void Dec() {
			if (--count==0) {
				if(base) base->_release();
				delete this;
			}
		}
		inline void checkcreate() {
			if (!created) {base = creator(); created=true;}
		}
	} *_pool;

	inline Object(Object_base* (*cor)()) {
		_pool = new Pool(cor);
	}
	inline Object(Pool* p) : _pool(p) {
		_pool->Inc();
	}
	inline Object(Pool& p) : _pool(&p) {
		_pool->Inc();
	}
	inline Object(Object_base* b) {
		_pool = new Pool(b);
	}
public:
	typedef Object_base _base_class;

	// Dynamic cast constructor of inherited classes needs to access the _pool
	// of a generic object if casting successful. But it could not without this
	inline Pool* _get_pool() const {return _pool;}
	
	inline ~Object() {
		_pool->Dec();
	}
	
	// Those constructors are public, since we don't need an actual creator.
	// They enable generic object creation (like from a subclass defined at
	// run-time!)
	inline Object(const SubClass& s) {
		_pool = new Pool(Object_base::_create(s.string()));
	}
	inline Object(const Reference &r) {
		_pool = new Pool(r.isString()?(Object_base::_fromString(r.string())):(Object_base::_fromReference(r.reference(),true)));
	}
	inline Object(const Object& target) : _pool(target._pool) {
		_pool->Inc();
	}
	inline Object() { // creates a null object
		_pool = new Pool((Object_base*)0);
	}
	inline Object& operator=(const Object& target) {
		if (_pool == target._pool) return *this;
		_pool->Dec();
		_pool = target._pool;
		_pool->Inc();
		return *this;
	}
	// No problem for the creator, this class has protected constructors.
	// So creator should give back an actual implementation
	inline Object_base* _base() const {
		_pool->checkcreate();
		return _pool->base;
	}

	// null, error?
	inline bool isNull() const {
		_pool->checkcreate();
		return !(_pool->base);
	}
	inline bool error() const {
		_pool->checkcreate();
    	return _pool->base && _pool->base->_error();
	}
	
	// Comparision
	inline bool _isEqual(const Object& other) const {
		if(isNull() != other.isNull()) return false;

		// we can assume that things are created here, as we've
		// called isNull of both wrappers once
		if(!isNull())
			return _pool->base->_isEqual(other._pool->base);

		// both null references
		return true;
	}


// Object_base wrappers

	// Custom messaging - see Object_base for comments
	inline Buffer *_allocCustomMessage(long handlerID) const {
		_pool->checkcreate();
		assert(_pool->base);
		return _pool->base->_allocCustomMessage(handlerID);
	}

	inline void _sendCustomMessage(Buffer *data) const {
		_pool->checkcreate();
		assert(_pool->base);
		_pool->base->_sendCustomMessage(data);
	}
	
	// generic capabilities, which allow find out what you can do with an
	// object even if you don't know it's interface
	inline long _lookupMethod(const MethodDef& methodDef) const {
		_pool->checkcreate();
		assert(_pool->base);
		return _pool->base->_lookupMethod(methodDef);
	}
	inline std::string _interfaceName() const {
		_pool->checkcreate();
		assert(_pool->base);
		return _pool->base->_interfaceName();
	}
	inline InterfaceDef _queryInterface(const std::string& name) const {
		_pool->checkcreate();
		assert(_pool->base);
		return _pool->base->_queryInterface(name);
	}
	inline TypeDef _queryType(const std::string& name) const {
		_pool->checkcreate();
		assert(_pool->base);
		return _pool->base->_queryType(name);
	}
	inline EnumDef _queryEnum(const std::string& name) const {
		_pool->checkcreate();
		assert(_pool->base);
		return _pool->base->_queryEnum(name);
	}
	// Stringification
	inline std::string _toString() const {
		_pool->checkcreate();
		assert(_pool->base);
		return _pool->base->_toString();
	}
	inline std::string toString() const {return _toString();}

	// stuff for streaming (put in a seperate interface?)
	inline void calculateBlock(unsigned long cycles) const {
		_pool->checkcreate();
		assert(_pool->base);
		_pool->base->calculateBlock(cycles);
	}
	// Node info
	inline ScheduleNode *_node() const {
		_pool->checkcreate();
		assert(_pool->base);
		return _pool->base->_node();
	}
	
	// Ah! Flowsystem is not defined yet, so cannot be returned inline.
	FlowSystem _flowSystem() const;
	
	inline void _copyRemote() const {
		_pool->checkcreate();
		assert(_pool->base);
		_pool->base->_copyRemote();
	}
	inline void _useRemote() const {
		_pool->checkcreate();
		assert(_pool->base);
		_pool->base->_useRemote();
	}
	inline void _releaseRemote() const {
		_pool->checkcreate();
		assert(_pool->base);
		_pool->base->_releaseRemote();
	}
	
	// Default I/O info
	inline std::vector<std::string> _defaultPortsIn() const {
		_pool->checkcreate();
		assert(_pool->base);
		return _pool->base->_defaultPortsIn();
	}
	inline std::vector<std::string> _defaultPortsOut() const {
		_pool->checkcreate();
		assert(_pool->base);
		return _pool->base->_defaultPortsOut();
	}
	
	// aggregation
	inline std::string _addChild(Arts::Object child, const std::string& name) const {
		_pool->checkcreate();
		assert(_pool->base);
		return _pool->base->_addChild(child, name);
	}
	inline bool _removeChild(const std::string& name) const {
		_pool->checkcreate();
		assert(_pool->base);
		return _pool->base->_removeChild(name);
	}
	inline Arts::Object _getChild(const std::string& name) const {
		_pool->checkcreate();
		assert(_pool->base);
		return _pool->base->_getChild(name);
	}
	inline std::vector<std::string> * _queryChildren() const {
		_pool->checkcreate();
		assert(_pool->base);
		return _pool->base->_queryChildren();
	}
	// Do we really need those in the Wrapper?
	// And would it really be sensible to make _cast wrappers?
/*	inline void _release() const {
		_pool->checkcreate();
		assert(_pool->base);
		return _pool->base->_release();
	}
	inline Object_base *_copy() const {
		_poo->checkcreate();
		assert(_pool->base);
		return _pool->base->_copy();
	}
*/

	// Object::null() returns a null object (and not just a reference to one)
	inline static Object null() {return Object((Object_base*)0);}
	inline static Object _from_base(Object_base* b) {return Object(b);}
};

// Enables a different constructor, that should do the cast
class ARTS_EXPORT DynamicCast {
private:
	Object obj;
public:
	inline explicit DynamicCast(const Object& o) : obj(o) {}
	inline const Object& object() const {return obj;}
};

}

#endif
