//------------------------------------------------------------------------------
// emContext.h
//
// Copyright (C) 2005-2008,2010,2016 Oliver Hamann.
//
// Homepage: http://eaglemode.sourceforge.net/
//
// This program is free software: you can redistribute it and/or modify it under
// the terms of the GNU General Public License version 3 as published by the
// Free Software Foundation.
//
// 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 version 3 for
// more details.
//
// You should have received a copy of the GNU General Public License version 3
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//------------------------------------------------------------------------------

#ifndef emContext_h
#define emContext_h

#ifndef emAvlTree_h
#include <emCore/emAvlTree.h>
#endif

#ifndef emCrossPtr_h
#include <emCore/emCrossPtr.h>
#endif

#ifndef emTimer_h
#include <emCore/emTimer.h>
#endif

class emModel;
class emRootContext;


//==============================================================================
//================================= emContext ==================================
//==============================================================================

class emContext : public emEngine {

public:

	// Class for a context of models (read comments on emModel). It manages
	// an AVL tree for quickly refinding common models.

	emContext(emContext & parentContext);
		// Construct a child context. For constructing a root context
		// please see emRootContext.

	virtual ~emContext();
		// Destructor. This even deletes all common models in this
		// context, in an order respecting references between the
		// models. Child contexts and private models are not deleted by
		// this. They must have been destructed before or they must be
		// managed by common models.

	void LinkCrossPtr(emCrossPtrPrivate & crossPtr);
		// This means emCrossPtr<emContext> is possible.

	emRootContext & GetRootContext() const;
		// Get the root context.

	emContext * GetParentContext() const;
		// Get the parent context. Returns NULL if this is the root
		// context.

	emContext * GetFirstChildContext() const;
	emContext * GetLastChildContext() const;
	emContext * GetPrevContext() const;
	emContext * GetNextContext() const;
		// Get the first or last child context, or the previous or next
		// brother context, NULL if none.

	emModel * Lookup(const type_info & modelClass,
	                 const char * name) const;
		// Search for a common model within this context.
		// Arguments:
		//   modelClass - Final class of the model.
		//   name       - Name of the model.
		// Returns: The model, or NULL if not found.

	emModel * LookupInherited(const type_info & modelClass,
	                          const char * name) const;
		// Like Lookup, but if the model is not found in this context,
		// the parent context is searched, then the grad-parent, and so
		// on.

	emString GetListing() const;
		// Just for debugging: Get a listing of all common models.

	void GetModelInfo(int * pCommonCount, int * pPrivateCount=NULL,
	                  emModel * * * pArrayOfCommon=NULL) const;
		// Just for debugging: Get the number of common and private
		// models, and create an array of pointers to all common models.
		// The array must be deleted by the caller.

protected:

	virtual bool Cycle();
		// emContext has been derived from emEngine for convenience.
		// This default implementation does nothing and returns false.

private:

	friend class emModel;
	friend class emRootContext;

	emContext(emScheduler & scheduler);

	void RegisterModel(emModel * model);
	void UnregisterModel(emModel * model);
	static int CalcHashCode(const type_info & modelClass,
	                        const char * name);
	emModel * SearchUnused() const;
	emModel * SearchUnused(int minHash) const;
	emModel * SearchGarbage();
	emModel * SearchGarbage(int minHash);
	void CollectGarbage();

	class SharedTimingEngine : public emEngine {
	public:
		SharedTimingEngine(emRootContext & rootContext,
		                   unsigned int gcPeriod);
		virtual ~SharedTimingEngine();
		virtual bool Cycle();
		emRootContext & RootContext;
		emTimer SecsTimer;
		unsigned int GCPeriod;
		unsigned int SecsCounter;
		unsigned int TimeOfGC;
	};

	friend class SharedTimingEngine;

	emRootContext & RootContext;
	emCrossPtrList CrossPtrList;
	SharedTimingEngine * SharedTiming;
	emContext * ParentContext;
	emContext * FirstChildContext;
	emContext * LastChildContext;
	emContext * PrevContext;
	emContext * NextContext;
	emAvlTree AvlTree;
	unsigned int ModelCount;
	bool DoGCOnModels;
};


//==============================================================================
//=============================== emRootContext ================================
//==============================================================================

class emRootContext : public emContext {

public:

	emRootContext(emScheduler & scheduler);
		// Construct a root context.

};


//==============================================================================
//============================== Implementations ===============================
//==============================================================================

inline void emContext::LinkCrossPtr(emCrossPtrPrivate & crossPtr)
{
	CrossPtrList.LinkCrossPtr(crossPtr);
}

inline emRootContext & emContext::GetRootContext() const
{
	return RootContext;
}

inline emContext * emContext::GetParentContext() const
{
	return ParentContext;
}

inline emContext * emContext::GetFirstChildContext() const
{
	return FirstChildContext;
}

inline emContext * emContext::GetLastChildContext() const
{
	return LastChildContext;
}

inline emContext * emContext::GetPrevContext() const
{
	return PrevContext;
}

inline emContext * emContext::GetNextContext() const
{
	return NextContext;
}

inline emRootContext::emRootContext(emScheduler & scheduler)
	: emContext(scheduler)
{
}


#endif
