//------------------------------------------------------------------------------
// 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