using System;
using System.Collections.Generic;
using System.Text;

namespace CommonLang.Concurrent
{
    public class AtomicInteger
    {
        private int mValue;

        public AtomicInteger(int v)
        {
            this.mValue = v;
        }

        public int Value
        {
            get
            {
                lock (this)
                {
                    return mValue;
                }
            }
            set
            {
                lock (this)
                {
                    mValue = value;
                }
            }
        }


        public int GetAndSet(int val)
        {
            lock (this)
            {
                int ret = mValue;
                mValue = val;
                return ret;
            }
        }

        public int GetAndIncrement()
        {
            lock (this)
            {
                int ret = mValue;
                mValue++;
                return ret;
            }
        }

        public int GetAndDecrement()
        {
            lock (this)
            {
                int ret = mValue;
                mValue--;
                return ret;
            }
        }

        public int GetAndAdd(int delta)
        {
            lock (this)
            {
                int ret = mValue;
                mValue += delta;
                return ret;
            }
        }

        public int IncrementAndGet()
        {
            lock (this)
            {
                mValue++;
                return mValue;
            }
        }

        public int DecrementAndGet()
        {
            lock (this)
            {
                mValue--;
                return mValue;
            }
        }

        public int AddAndGet(int delta)
        {
            lock (this)
            {
                mValue += delta;
                return mValue;
            }
        }


        public bool CompareAndSet(int expect, int update)
        {
            lock (this)
            {
                if (expect == mValue)
                {
                    mValue = update;
                    return true;
                }
                return false;
            }
        }


        public static AtomicInteger operator +(AtomicInteger value1, int value2)
        {
            lock (value1)
            {
                value1.Value += value2;
            }
            return value1;
        }
        public static AtomicInteger operator -(AtomicInteger value1, int value2)
        {
            lock (value1)
            {
                value1.Value -= value2;
            }
            return value1;
        }
        public static AtomicInteger operator *(AtomicInteger value1, int value2)
        {
            lock (value1)
            {
                value1.Value *= value2;
            }
            return value1;
        }
        public static AtomicInteger operator /(AtomicInteger value1, int value2)
        {
            lock (value1)
            {
                value1.Value /= value2;
            }
            return value1;
        }

        public static AtomicInteger operator ++(AtomicInteger value1)
        {
            lock (value1)
            {
                value1.Value += 1;
            }
            return value1;
        }
        public static AtomicInteger operator --(AtomicInteger value1)
        {
            lock (value1)
            {
                value1.Value -= 1;
            }
            return value1;
        }

    }



    public class AtomicLong
    {
        private long mValue;

        public AtomicLong(long v)
        {
            this.mValue = v;
        }

        public long Value
        {
            get
            {
                lock (this)
                {
                    return mValue;
                }
            }
            set
            {
                lock (this)
                {
                    mValue = value;
                }
            }
        }


        public long GetAndSet(long val)
        {
            lock (this)
            {
                long ret = mValue;
                mValue = val;
                return ret;
            }
        }

        public long GetAndIncrement()
        {
            lock (this)
            {
                long ret = mValue;
                mValue++;
                return ret;
            }
        }

        public long GetAndDecrement()
        {
            lock (this)
            {
                long ret = mValue;
                mValue--;
                return ret;
            }
        }

        public long GetAndAdd(long delta)
        {
            lock (this)
            {
                long ret = mValue;
                mValue += delta;
                return ret;
            }
        }

        public long IncrementAndGet()
        {
            lock (this)
            {
                mValue++;
                return mValue;
            }
        }

        public long DecrementAndGet()
        {
            lock (this)
            {
                mValue--;
                return mValue;
            }
        }

        public long AddAndGet(long delta)
        {
            lock (this)
            {
                mValue += delta;
                return mValue;
            }
        }


        public bool CompareAndSet(long expect, long update)
        {
            lock (this)
            {
                if (expect == mValue)
                {
                    mValue = update;
                    return true;
                }
                return false;
            }
        }




        public static AtomicLong operator +(AtomicLong value1, long value2)
        {
            lock (value1)
            {
                value1.Value += value2;
            }
            return value1;
        }
        public static AtomicLong operator -(AtomicLong value1, long value2)
        {
            lock (value1)
            {
                value1.Value -= value2;
            }
            return value1;
        }
        public static AtomicLong operator *(AtomicLong value1, long value2)
        {
            lock (value1)
            {
                value1.Value *= value2;
            }
            return value1;
        }
        public static AtomicLong operator /(AtomicLong value1, long value2)
        {
            lock (value1)
            {
                value1.Value /= value2;
            }
            return value1;
        }
        public static AtomicLong operator ++(AtomicLong value1)
        {
            lock (value1)
            {
                value1.Value += 1;
            }
            return value1;
        }
        public static AtomicLong operator --(AtomicLong value1)
        {
            lock (value1)
            {
                value1.Value -= 1;
            }
            return value1;
        }
    }


    public class AtomicUInt
    {
        private uint mValue;

        public AtomicUInt(uint v)
        {
            this.mValue = v;
        }

        public uint Value
        {
            get
            {
                lock (this)
                {
                    return mValue;
                }
            }
            set
            {
                lock (this)
                {
                    mValue = value;
                }
            }
        }


        public uint GetAndSet(uint val)
        {
            lock (this)
            {
                uint ret = mValue;
                mValue = val;
                return ret;
            }
        }

        public uint GetAndIncrement()
        {
            lock (this)
            {
                uint ret = mValue;
                mValue++;
                return ret;
            }
        }

        public uint GetAndDecrement()
        {
            lock (this)
            {
                uint ret = mValue;
                mValue--;
                return ret;
            }
        }

        public uint GetAndAdd(uint delta)
        {
            lock (this)
            {
                uint ret = mValue;
                mValue += delta;
                return ret;
            }
        }

        public uint IncrementAndGet()
        {
            lock (this)
            {
                mValue++;
                return mValue;
            }
        }

        public uint DecrementAndGet()
        {
            lock (this)
            {
                mValue--;
                return mValue;
            }
        }

        public uint AddAndGet(uint delta)
        {
            lock (this)
            {
                mValue += delta;
                return mValue;
            }
        }


        public bool CompareAndSet(uint expect, uint update)
        {
            lock (this)
            {
                if (expect == mValue)
                {
                    mValue = update;
                    return true;
                }
                return false;
            }
        }



        public static AtomicUInt operator +(AtomicUInt value1, uint value2)
        {
            lock (value1)
            {
                value1.Value += value2;
            }
            return value1;
        }
        public static AtomicUInt operator -(AtomicUInt value1, uint value2)
        {
            lock (value1)
            {
                value1.Value -= value2;
            }
            return value1;
        }
        public static AtomicUInt operator *(AtomicUInt value1, uint value2)
        {
            lock (value1)
            {
                value1.Value *= value2;
            }
            return value1;
        }
        public static AtomicUInt operator /(AtomicUInt value1, uint value2)
        {
            lock (value1)
            {
                value1.Value /= value2;
            }
            return value1;
        }
        public static AtomicUInt operator ++(AtomicUInt value1)
        {
            lock (value1)
            {
                value1.Value += 1;
            }
            return value1;
        }
        public static AtomicUInt operator --(AtomicUInt value1)
        {
            lock (value1)
            {
                value1.Value -= 1;
            }
            return value1;
        }
    }

    public class AtomicFloat
    {
        private float mValue;

        public AtomicFloat(float v)
        {
            this.mValue = v;
        }

        public float Value
        {
            get
            {
                lock (this)
                {
                    return mValue;
                }
            }
            set
            {
                lock (this)
                {
                    mValue = value;
                }
            }
        }


        public float GetAndSet(float val)
        {
            lock (this)
            {
                float ret = mValue;
                mValue = val;
                return ret;
            }
        }

        public float GetAndIncrement()
        {
            lock (this)
            {
                float ret = mValue;
                mValue++;
                return ret;
            }
        }

        public float GetAndDecrement()
        {
            lock (this)
            {
                float ret = mValue;
                mValue--;
                return ret;
            }
        }

        public float GetAndAdd(float delta)
        {
            lock (this)
            {
                float ret = mValue;
                mValue += delta;
                return ret;
            }
        }

        public float AddAndGet(float delta)
        {
            lock (this)
            {
                mValue += delta;
                return mValue;
            }
        }

        public bool CompareAndSet(float expect, float update)
        {
            lock (this)
            {
                if (expect == mValue)
                {
                    mValue = update;
                    return true;
                }
                return false;
            }
        }


        public static AtomicFloat operator +(AtomicFloat value1, float value2)
        {
            lock (value1)
            {
                value1.Value += value2;
            }
            return value1;
        }
        public static AtomicFloat operator -(AtomicFloat value1, float value2)
        {
            lock (value1)
            {
                value1.Value -= value2;
            }
            return value1;
        }
        public static AtomicFloat operator *(AtomicFloat value1, float value2)
        {
            lock (value1)
            {
                value1.Value *= value2;
            }
            return value1;
        }
        public static AtomicFloat operator /(AtomicFloat value1, float value2)
        {
            lock (value1)
            {
                value1.Value /= value2;
            }
            return value1;
        }
        public static AtomicFloat operator ++(AtomicFloat value1)
        {
            lock (value1)
            {
                value1.Value += 1;
            }
            return value1;
        }
        public static AtomicFloat operator --(AtomicFloat value1)
        {
            lock (value1)
            {
                value1.Value -= 1;
            }
            return value1;
        }
    }

    public class AtomicReference<T>
    {
        private T mData;

        public AtomicReference(T data)
        {
            this.mData = data;
        }

        public T Value
        {
            get
            {
                lock (this)
                {
                    return mData;
                }
            }
            set
            {
                lock (this)
                {
                    mData = value;
                }
            }
        }

        public bool Update(T data)
        {
            lock (this)
            {
              
                if (!mData.Equals(data))
                {
                    mData = data;
                    return true;
                }
                return false;
            }
        }

        public T GetAndSet(T data)
        {
            lock (this)
            {
                T ret = mData;
                mData = data;
                return ret;
            }
        }
        public bool CompareAndSet(Predicate<T> expect, T update)
        {
            lock (this)
            {
                if (expect(mData))
                {
                    mData = update;
                    return true;
                }
                return false;
            }
        }
        public bool CompareAndSet(T expect, T update)
        {
            lock (this)
            {
                if (expect.Equals(mData))
                {
                    mData = update;
                    return true;
                }
                return false;
            }
        }
        public bool CompareNotAndSet(T expect, T update)
        {
            lock (this)
            {
                if (!expect.Equals(mData))
                {
                    mData = update;
                    return true;
                }
                return false;
            }
        }
    }


    public class IDGenerator
    {
        private uint indexer = 0;

        public uint NextID()
        {
            lock (this)
            {
                indexer++;
                uint ret = indexer;
                return ret;
            }
        }

        public uint Regist(uint value)
        {
            lock (this)
            {
                indexer = Math.Max(indexer, value);
            }
            return value;
        }
    }
}