/*
	Copyright 2014 Michele "King_DuckZ" Santullo

	This file is part of CloonelJump.

	CloonelJump is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	CloonelJump 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 for more details.

	You should have received a copy of the GNU General Public License
	along with CloonelJump.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef id78906DE4FB0D43219CD3F0D9C620FC06
#define id78906DE4FB0D43219CD3F0D9C620FC06

#include "vector.hpp"
#include <cstddef>
#include <algorithm>

namespace cloonel {
	class SizeRatio;
	class SDLMain;
	class SizeNotifiableBase;

	namespace regbehaviours {
		class DontRegister {
		public:
			enum { SDLMAIN_NEEDED = false };

			DontRegister ( void ) = default;
			DontRegister ( DontRegister&&, SizeNotifiableBase* ) { }
			~DontRegister ( void ) noexcept = default;

			void Register ( SizeNotifiableBase* ) const noexcept { return; }
			void Unregister ( void ) const noexcept { return; }
		};

		class AutoRegister {
		public:
			enum { SDLMAIN_NEEDED = true };

			AutoRegister ( AutoRegister&& parOther, SizeNotifiableBase* parSwapTo );
			explicit AutoRegister ( SDLMain* parMain ) :
				m_sdlmain(parMain)
#if !defined(NDEBUG)
				, m_registered(false)
#endif
			{
			}
			~AutoRegister ( void ) noexcept = default;

			void Register ( SizeNotifiableBase* parNotifiable );
			void Unregister ( void ) noexcept;

		private:
			SDLMain* m_sdlmain;
			size_t m_id;
#if !defined(NDEBUG)
			bool m_registered;
#endif
		};
	} //namespace regbehaviours

	class SizeNotifiableBase {
	protected:
		SizeNotifiableBase ( void ) = default;
		SizeNotifiableBase ( const SizeNotifiableBase& ) = default;
		virtual ~SizeNotifiableBase ( void ) noexcept = default;
		SizeNotifiableBase& operator= ( const SizeNotifiableBase& ) = delete;

	public:
		virtual void NotifyResChanged ( const SizeRatio& parSize );
		const float2& Ratio ( void ) const noexcept { return m_scaleRatio; }

	private:
		float2 m_scaleRatio;
	};

	template <class RegisterBehaviour, bool=RegisterBehaviour::SDLMAIN_NEEDED>
	class SizeNotifiable;

	template <class RegisterBehaviour>
	class SizeNotifiable<RegisterBehaviour, false> : private RegisterBehaviour, public SizeNotifiableBase {
		static_assert(RegisterBehaviour::SDLMAIN_NEEDED == false, "SdlMainNeeded mismatches expected value");
	public:
		SizeNotifiable ( const SizeNotifiable& ) = delete;
		SizeNotifiable ( SizeNotifiable&& parOther ) :
			RegisterBehaviour(std::move(parOther), this),
			SizeNotifiableBase(parOther)
		{
		}
		SizeNotifiable ( void ) {
			this->Register(this);
		}
		virtual ~SizeNotifiable ( void ) noexcept {
			this->Unregister();
		}
	};

	template <class RegisterBehaviour>
	class SizeNotifiable<RegisterBehaviour, true> : private RegisterBehaviour, public SizeNotifiableBase {
		static_assert(RegisterBehaviour::SDLMAIN_NEEDED == true, "SdlMainNeeded mismatches expected value");
	public:
		SizeNotifiable ( const SizeNotifiable& ) = delete;
		SizeNotifiable ( SizeNotifiable&& parOther ) :
			RegisterBehaviour(std::move(parOther), this),
			SizeNotifiableBase(parOther)
		{
		}
		explicit SizeNotifiable ( SDLMain* parSdlMain ) :
			RegisterBehaviour(parSdlMain)
		{
			this->Register(this);
		}
		virtual ~SizeNotifiable ( void ) noexcept {
			this->Unregister();
		}
	};
} //namespace cloonel

#endif
