//------------------------------------------------------------------------------
/*
    Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================

#ifndef RIPPLE_ILOADMANAGER_H
#define RIPPLE_ILOADMANAGER_H

// types of load that can be placed on the server
// VFALCO TODO replace LT_ with loadType in constants
enum LoadType
{
    // Bad things
    LT_InvalidRequest,          // A request that we can immediately tell is invalid
    LT_RequestNoReply,          // A request that we cannot satisfy
    LT_InvalidSignature,        // An object whose signature we had to check and it failed
    LT_UnwantedData,            // Data we have no use for
    LT_BadPoW,                  // Proof of work not valid
    LT_BadData,                 // Data we have to verify before rejecting

    // RPC loads
    LT_RPCInvalid,              // An RPC request that we can immediately tell is invalid.
    LT_RPCReference,            // A default "reference" unspecified load
    LT_RPCException,            // An RPC load that causes an exception
    LT_RPCBurden,               // A particularly burdensome RPC load

    // Good things
    LT_NewTrusted,              // A new transaction/validation/proposal we trust
    LT_NewTransaction,          // A new, valid transaction
    LT_NeededData,              // Data we requested

    // Requests
    LT_RequestData,             // A request that is hard to satisfy, disk access
    LT_CheapQuery,              // A query that is trivial, cached data

    LT_MAX                      // MUST BE LAST
};

//------------------------------------------------------------------------------

/** Tracks the consumption of resources at an endpoint.

    To prevent monopolization of server resources or attacks on servers,
    resource consumption is monitored at each endpoint. When consumption
    exceeds certain thresholds, costs are imposed. Costs include charging
    additional XRP for transactions, requiring a proof of work to be
    performed, or simply disconnecting the endpoint.

    Currently, consumption endpoints include websocket connections used to
    service clients, and peer connections used to create the peer to peer
    overlay network implementing the Ripple protcool.

    The current "balance" of a LoadSource represents resource consumption
    debt or credit. Debt is accrued when bad loads are imposed. Credit is
    granted when good loads are imposed. When the balance crosses heuristic
    thresholds, costs are increased on the endpoint.

    The balance is represented as a unitless relative quantity.

    @note Although RPC connections consume resources, they are transient and
          cannot be rate limited. It is advised not to expose RPC interfaces
          to the general public.
*/
class LoadSource
{
public:
    // VFALCO TODO Use these dispositions
    /*
    enum Disposition
    {
        none,
        shouldWarn,
        shouldDrop,
    };
    */

    /** Construct a load source.

        Sources with admin privileges have relaxed or no restrictions
        on resource consumption.

        @param admin    `true` if the source should have admin privileges.
    */
    // VFALCO TODO See who is constructing this with a parameter
    explicit LoadSource (bool admin)
        : mBalance (0)
        , mFlags (admin ? lsfPrivileged : 0)
        , mLastUpdate (UptimeTimer::getInstance ().getElapsedSeconds ())
        , mLastWarning (0)
        , mLogged (false)
    {
    }

    /** Construct a load source with a given name.

        The endpoint is considered non-privileged.
    */
    explicit LoadSource (std::string const& name)
        : mName (name)
        , mBalance (0)
        , mFlags (0)
        , mLastUpdate (UptimeTimer::getInstance ().getElapsedSeconds ())
        , mLastWarning (0)
        , mLogged (false)
    {
    }

    /** Change the name of the source.

        An endpoint can be created before it's name is known. For example,
        on an incoming connection before the IP and port have been determined.
    */
    // VFALCO TODO Figure out a way to construct the LoadSource object with
    //             the proper name instead of renaming it later.
    //
    void rename (std::string const& name)
    {
        mName = name;
    }

    /** Retrieve the name of this endpoint.
    */
    std::string const& getName () const
    {
        return mName;
    }

    /** Determine if this endpoint is privileged.
    */
    bool isPrivileged () const
    {
        return (mFlags & lsfPrivileged) != 0;
    }

    /** Grant the privileged attribute on this endpoint.
    */
    void setPrivileged ()
    {
        mFlags |= lsfPrivileged;
    }

    /** Retrieve the load debit or credit associated with the endpoint.

        The balance is represented in a unitless relative quantity
        indicating the heuristically weighted amount of resource consumption.
    */
    int getBalance () const
    {
        return mBalance;
    }

    /** Returns true if the endpoint received a log warning.
    */
    bool isLogged () const
    {
        return mLogged;
    }

    /** Reset the flag indicating the endpoint received a log warning.
    */
    void clearLogged ()
    {
        mLogged = false;
    }

    /** Indicate that this endpoint is an outgoing connection.
    */
    void setOutbound ()
    {
        mFlags |= lsfOutbound;
    }

    /** Returns true if this endpoint is an outgoing connection.
    */
    bool isOutbound () const
    {
        return (mFlags & lsfOutbound) != 0;
    }

private:
    // VFALCO Make this not a friend
    friend class LoadManager;

    static const int lsfPrivileged  = 1;
    static const int lsfOutbound    = 2;

private:
    std::string mName;
    int         mBalance;
    int         mFlags;
    int         mLastUpdate;
    int         mLastWarning;
    bool        mLogged;
};

//------------------------------------------------------------------------------

/** Manages load sources.

    This object creates an associated thread to maintain a clock.

    When the server is overloaded by a particular peer it issues a warning
    first. This allows friendly peers to reduce their consumption of resources,
    or disconnect from the server.

    The warning system is used instead of merely dropping, because hostile
    peers can just reconnect anyway.

    @see LoadSource, LoadType
*/
class ILoadManager
{
public:
    /** Create a new manager.

        The manager thread begins running immediately.

        @note The thresholds for warnings and punishments are in
              the ctor-initializer
    */
    static ILoadManager* New ();

    /** Destroy the manager.

        The destructor returns only after the thread has stopped.
    */
    virtual ~ILoadManager () { }

    /** Start the associated thread.

        This is here to prevent the deadlock detector from activating during
        a lengthy program initialization.
    */
    // VFALCO TODO Simplify the two stage initialization to one stage (construction).
    //        NOTE In stand-alone mode the load manager thread isn't started
    virtual void startThread () = 0;

    /** Turn on deadlock detection.

        The deadlock detector begins in a disabled state. After this function
        is called, it will report deadlocks using a separate thread whenever
        the reset function is not called at least once per 10 seconds.

        @see resetDeadlockDetector
    */
    // VFALCO NOTE it seems that the deadlock detector has an "armed" state to prevent it
    //             from going off during program startup if there's a lengthy initialization
    //             operation taking place?
    //
    virtual void activateDeadlockDetector () = 0;

    /** Reset the deadlock detection timer.

        A dedicated thread monitors the deadlock timer, and if too much
        time passes it will produce log warnings.
    */
    virtual void resetDeadlockDetector () = 0;

    /** Update an endpoint to reflect an imposed load.

        The balance of the endpoint is adjusted based on the heuristic cost
        of the indicated load.

        @return `true` if the endpoint should be warned or punished.
    */
    virtual bool applyLoadCharge (LoadSource& sourceToAdjust, LoadType loadToImpose) const = 0;

    // VFALCO TODO Eliminate these two functions and just make applyLoadCharge()
    //             return a LoadSource::Disposition
    //
    virtual bool shouldWarn (LoadSource&) const = 0;
    virtual bool shouldCutoff (LoadSource&) const = 0;
};

#endif
