/** @file weakref.h
*	Custom weak references for EABaseTypes, based on SafeCom but more appropriate to our needs
*	@author Chris Burns (cburns@ea.com)
*
*	EABaseTypes
*	(c) 2013 Electronic Arts Inc.
*/

#ifndef EABASETYPES_WEAKREF_H_
#define EABASETYPES_WEAKREF_H_

#include "EABaseTypes/autoref.h"

namespace EA
{
	namespace Types
	{	
        class WeakRefBase;

        struct DoubleLinkedList
        {
            DoubleLinkedList* mPrev;
            DoubleLinkedList* mNext;
        };

        class WeakRefRoot
        {
        public:
            inline WeakRefRoot()
			{
				mRoot.mPrev = &mRoot;
				mRoot.mNext = &mRoot;
			}

            inline ~WeakRefRoot() { ClearWeakReferences(); }

        protected:

            inline void AddToLinkedList(WeakRefBase* weakRef);

            inline void RemoveFromLinkedList(WeakRefBase* weakRef);

        private:
            // On purpose, disabled copy constructor and assignment operator
            // These are meaningless for the root as we are not going to attach to the previous root
            // But create a new one completely disconnected from the other.
            // So we want to avoid any potentatial misunderstanding on the usage.

            // Start do not implement
            WeakRefRoot(const WeakRefRoot& other);
            WeakRefRoot& operator=(const WeakRefRoot& other);
            // End do not implement

            inline void ClearWeakReferences();

            DoubleLinkedList mRoot;

            // So it can access AddToLinkedList() and RemoveFromLinkedList()
            template<typename T>
            friend class WeakRef;
        };

        // Here, we inherit in a protected manner to make sure that:
        // - DoubleLinkedList members are first
        // - WeakRefBase does not access mPrev and mNext
        // - WeakRefBase "is a" DoubleLinkedList object and not "has a".
        class WeakRefBase : protected DoubleLinkedList
        {
		public:

			// The weak-reference to the instance
            // No ref-count operation should happen when storing / clearing this
            void* mInstance;

        protected:
			inline WeakRefBase(): mInstance(NULL) {}
			inline WeakRefBase(void* instance):mInstance(instance) {}
			inline ~WeakRefBase() {}

        private:
            // Start do not implement
            WeakRefBase(const WeakRefBase& other);
            WeakRefBase& operator=(const WeakRefBase& other);
            // End do not implement

            // So it can access the protected inheritance to DoubleLinkedList.
            friend class WeakRefRoot;
        };

        /* protected inline */ void WeakRefRoot::AddToLinkedList(WeakRefBase* weakRef)
        {
            // Add it after the root of the linked list
            weakRef->mNext = mRoot.mNext;
            weakRef->mPrev = &mRoot;
            mRoot.mNext    = weakRef;
            weakRef->mNext->mPrev = weakRef;
        }
        
        /* protected inline */ void WeakRefRoot::RemoveFromLinkedList(WeakRefBase* weakRef)
        {
            // Remove itself from the circular double linked-list.
            // Because it is circular, we don't need to test for NULL, the root being not removed from this list.
            weakRef->mPrev->mNext = weakRef->mNext;
            weakRef->mNext->mPrev = weakRef->mPrev;

            // Relink on itself
            weakRef->mPrev = weakRef;
            weakRef->mNext = weakRef;
        }
        
        /* private inline */ void WeakRefRoot::ClearWeakReferences()
        {
            DoubleLinkedList* mEnd = &mRoot;
            WeakRefBase* pointer = static_cast<WeakRefBase *>(mRoot.mNext);

            while (pointer != mEnd)
            {
                // Clear the reference
                pointer->mInstance = NULL;
                WeakRefBase* nextPointer = static_cast<WeakRefBase *>(pointer->mNext);

                // Remove from the list so it helps if we re-attach the cleared weak ref to something else later
                WeakRefRoot::RemoveFromLinkedList(pointer);

                pointer = nextPointer;
            }
        }

        // Simply use WeakRef<> the same way you would use an AutoRef<>.
        // Note that the cost of construction / copy-construction / assignment / destruction
        // is a bit expensive. So avoid passing / returning it by value whenever possible.
        template <typename T>
        class WeakRef : public WeakRefBase
        {
        public:
			inline WeakRef():WeakRefBase() {}
            inline WeakRef(const WeakRef<T>& other):WeakRefBase(other.mInstance) { AddToLinkedList(); }
			inline WeakRef(const AutoRefBase<T>& other):WeakRefBase(other.mUnsafePointer) { AddToLinkedList(); }
            inline ~WeakRef() { RemoveFromLinkedList(); }

			inline T* GetUnsafePointer() const { return static_cast<T*>(mInstance); }

            inline T* operator->() const { return static_cast<T*>(mInstance); } 
			inline T& operator*() { return *static_cast<T*>(mInstance); }
			inline T& operator*() const { return *static_cast<T*>(mInstance); }

            inline WeakRef& operator=(const WeakRef& other)
			{
				if (mInstance != other.mInstance)
				{
					RemoveFromLinkedList();
					mInstance = other.mInstance;
					AddToLinkedList();
				}

				return *this;
			}

			inline WeakRef& operator=(const AutoRefBase<T>& other)
			{
				T* pTOther = other.mUnsafePointer;

				if (mInstance != pTOther)
				{
					RemoveFromLinkedList();
					mInstance = pTOther;
					AddToLinkedList();
				}

				return *this;
			}

            template <typename RelatedT>
            inline bool operator==(const WeakRef<RelatedT>& other) const { return mInstance == other.mInstance; }

            template <typename RelatedT>
			inline bool operator!=(const WeakRef<RelatedT>& other) const { return mInstance != other.mInstance; }

            template <typename RelatedT>
			inline bool operator==(const AutoRefBase<RelatedT>& other) const { return mInstance == other.mUnsafePointer; }
            template <typename RelatedT>
			inline bool operator!=(const AutoRefBase<RelatedT>& other) const { return mInstance != other.mUnsafePointer; }

			template <typename RelatedT>
			inline bool operator==(RelatedT* unsafePointer) const { return mInstance == unsafePointer; }
            template <typename RelatedT>
			inline bool operator!=(const RelatedT* unsafePointer) const { return mInstance != unsafePointer; }

            inline bool operator==(intptr_t unsafePointer) const { return mInstance == reinterpret_cast<T*>(unsafePointer); }
            inline bool operator!=(intptr_t unsafePointer) const { return mInstance != reinterpret_cast<T*>(unsafePointer); }

            template<typename RelatedT>
			inline operator AutoRefIn<RelatedT>() const
            {
                return AutoRefIn<RelatedT>(static_cast<T*>(mInstance));
            }

		private:

			inline WeakRefRoot* GetWeakRefRoot() const
			{
				// This may not be type-safe.
				T* instance = static_cast<T*>(mInstance);
				WeakRefRoot* root = instance->GetWeakRefRoot();

				return root;
			}

			inline void AddToLinkedList()
			{
				if(mInstance != 0)
					GetWeakRefRoot()->AddToLinkedList(this);
			}

			inline void RemoveFromLinkedList()
			{
				if(mInstance != 0)
					GetWeakRefRoot()->RemoveFromLinkedList(this);
			}
        };
	}
}

#define EABASETYPES_WEAKREFERENCE_DECLARATION(__type) \
    typedef ::EA::Types::WeakRef<__type> __type ## WeakRef;


#endif // EABASETYPES_WEAKREF_H_
