#ifndef GAME_MWMECHANICS_STAT_H
#define GAME_MWMECHANICS_STAT_H

#undef min
#undef max

#include <limits>

namespace MWMechanics
{
    template<typename T>
    class Stat
    {
            T mBase;
            T mModified;

        public:
            typedef T Type;

            Stat() : mBase (0), mModified (0) {}
            Stat(T base) : mBase (base), mModified (base) {}
            Stat(T base, T modified) : mBase (base), mModified (modified) {}

            const T& getBase() const
            {
                return mBase;
            }

            T getModified() const
            {
                return std::max(static_cast<T>(0), mModified);
            }

            T getModifier() const
            {
                return mModified-mBase;
            }

            /// Set base and modified to \a value.
            void set (const T& value)
            {
                mBase = mModified = value;
            }

            /// Set base and adjust modified accordingly.
            void setBase (const T& value)
            {
                T diff = value - mBase;
                mBase = value;
                mModified += diff;
            }

            /// Set modified value an adjust base accordingly.
            void setModified (T value, const T& min, const T& max = std::numeric_limits<T>::max())
            {
                T diff = value - mModified;

                if (mBase+diff<min)
                {
                    value = min + (mModified - mBase);
                    diff = value - mModified;
                }
                else if (mBase+diff>max)
                {
                    value = max + (mModified - mBase);
                    diff = value - mModified;
                }

                mModified = value;
                mBase += diff;
            }

            void setModifier (const T& modifier)
            {
                mModified = mBase + modifier;
            }
    };

    template<typename T>
    inline bool operator== (const Stat<T>& left, const Stat<T>& right)
    {
        return left.getBase()==right.getBase() &&
            left.getModified()==right.getModified();
    }

    template<typename T>
    inline bool operator!= (const Stat<T>& left, const Stat<T>& right)
    {
        return !(left==right);
    }

    template<typename T>
    class DynamicStat
    {
            Stat<T> mStatic;
            T mCurrent;

        public:
            typedef T Type;

            DynamicStat() : mCurrent (0) {}
            DynamicStat(T current) : mCurrent (current) {}
            DynamicStat(T base, T modified, T current) : mStatic(base, modified), mCurrent (current) {}
            DynamicStat(const Stat<T> &stat, T current) : mStatic(stat), mCurrent (current) {}

            const T& getBase() const
            {
                return mStatic.getBase();
            }

            T getModified() const
            {
                return mStatic.getModified();
            }

            const T& getCurrent() const
            {
                return mCurrent;
            }

            /// Set base, modified and current to \a value.
            void set (const T& value)
            {
                mStatic.set (value);
                mCurrent = value;
            }

            /// Set base and adjust modified accordingly.
            void setBase (const T& value)
            {
                mStatic.setBase (value);

                if (mCurrent>getModified())
                    mCurrent = getModified();
            }

            /// Set modified value an adjust base accordingly.
            void setModified (T value, const T& min, const T& max = std::numeric_limits<T>::max())
            {
                mStatic.setModified (value, min, max);

                if (mCurrent>getModified())
                    mCurrent = getModified();
            }

            /// Change modified relatively.
            void modify (const T& diff)
            {
                mStatic.modify (diff);
                setCurrent (getCurrent()+diff);
            }

            void setCurrent (const T& value)
            {
                mCurrent = value;

                if (mCurrent<0)
                    mCurrent = 0;
                else if (mCurrent>getModified())
                    mCurrent = getModified();
            }

            void setModifier (const T& modifier)
            {
                T diff =  modifier - mStatic.getModifier();
                mStatic.setModifier (modifier);
                setCurrent (getCurrent()+diff);
            }
    };

    template<typename T>
    inline bool operator== (const DynamicStat<T>& left, const DynamicStat<T>& right)
    {
        return left.getBase()==right.getBase() &&
            left.getModified()==right.getModified() &&
            left.getCurrent()==right.getCurrent();
    }

    template<typename T>
    inline bool operator!= (const DynamicStat<T>& left, const DynamicStat<T>& right)
    {
        return !(left==right);
    }
}

#endif