//------------------------------------------------------------------------------
// emPriSchedAgent.h
//
// Copyright (C) 2006-2008,2010 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 emPriSchedAgent_h
#define emPriSchedAgent_h

#ifndef emModel_h
#include <emCore/emModel.h>
#endif


//==============================================================================
//============================== emPriSchedAgent ===============================
//==============================================================================

class emPriSchedAgent : public emUncopyable {

public:

        // Abstract base class for an agent in exclusively accessing an abstract
        // thing via a simple priority scheduling algorithm. This has been
        // invented for the use in emFileModel to make sure that only one file
        // is loading at a time and that the files are loaded in a nice order.
        // Other objects could take part of that scheduling.

        emPriSchedAgent(emContext & context, const emString & resourceName,
                        double priority=0.0);
                // Constructor.
                // Arguments:
                //   context      - Should be the root context.
                //   resourceName - Should be "cpu". A future agreement could be
                //                  "network". ???: Maybe emFileModel should
                //                  say "disk" instead of "cpu", or both...
                //   priority     - The access priority (see SetAccessPriority).

        virtual ~emPriSchedAgent();
                // Destructor.

        void SetAccessPriority(double priority);
                // Set the access priority. Usually, this should be set from
                // emPanel::GetUpdatePriority.

        void RequestAccess();
                // Start waiting for access.

        bool IsWaitingForAccess() const;
                // Whether this agent is waiting for access.

        bool HasAccess() const;
                // Whether this agent got access.

        void ReleaseAccess();
                // Release an obtained access or stop waiting for access.

protected:

        virtual void GotAccess() = 0;
                // Called when this agent got access.

private:

        class PriSchedModel : public emModel {
        public:
                static emRef<PriSchedModel> Acquire(
                        emContext & context, const emString & name
                );
        protected:
                PriSchedModel(emContext & context, const emString & name);
                virtual bool Cycle();
        private:
                friend class emPriSchedAgent;
                emPriSchedAgent * List;
                emPriSchedAgent * Active;
        };

        friend class PriSchedModel;

        emRef<PriSchedModel> PriSched;

        double Priority;

        emPriSchedAgent * * ThisPtrInList;

        emPriSchedAgent * NextInList;
};

inline bool emPriSchedAgent::IsWaitingForAccess() const
{
        return ThisPtrInList!=NULL;
}

inline bool emPriSchedAgent::HasAccess() const
{
        return PriSched->Active==this;
}


#endif