#pragma once

#include "RE/B/BSTEvent.h"
#include "RE/N/NiSmartPointer.h"
#include "REL/RuntimeDataAccessors.h"

namespace RE
{
	class TESObjectREFR;
	struct BGSEventProcessedEvent;
	struct TESActivateEvent;
	struct TESActiveEffectApplyRemoveEvent;
	struct TESActorLocationChangeEvent;
	struct TESBookReadEvent;
	struct TESCellAttachDetachEvent;
	struct TESCellFullyLoadedEvent;
	struct TESCellReadyToApplyDecalsEvent;
	struct TESCombatEvent;
	struct TESContainerChangedEvent;
	struct TESDeathEvent;
	struct TESDestructionStageChangedEvent;
	struct TESEnterBleedoutEvent;
	struct TESEquipEvent;
	struct TESFastTravelEndEvent;
	struct TESFormDeleteEvent;
	struct TESFurnitureEvent;
	struct TESGrabReleaseEvent;
	struct TESHitEvent;
	struct TESInitScriptEvent;
	struct TESLoadGameEvent;
	struct TESLockChangedEvent;
	struct TESMagicEffectApplyEvent;
	struct TESMagicWardHitEvent;
	struct TESMoveAttachDetachEvent;
	struct TESObjectLoadedEvent;
	struct TESObjectREFRTranslationEvent;
	struct TESOpenCloseEvent;
	struct TESPackageEvent;
	struct TESPerkEntryRunEvent;
	struct TESPlayerBowShotEvent;
	struct TESQuestInitEvent;
	struct TESQuestStageEvent;
	struct TESQuestStageItemDoneEvent;
	struct TESQuestStartStopEvent;
	struct TESResetEvent;
	struct TESResolveNPCTemplatesEvent;
	struct TESSceneActionEvent;
	struct TESSceneEvent;
	struct TESScenePhaseEvent;
	struct TESSellEvent;
	struct TESSleepStartEvent;
	struct TESSleepStopEvent;
	struct TESSpellCastEvent;
	struct TESSwitchRaceCompleteEvent;
	struct TESTopicInfoEvent;
	struct TESTrackedStatsEvent;
	struct TESTrapHitEvent;
	struct TESTriggerEnterEvent;
	struct TESTriggerEvent;
	struct TESTriggerLeaveEvent;
	struct TESUniqueIDChangeEvent;
	struct TESWaitStartEvent;
	struct TESWaitStopEvent;

	class ScriptEventSourceHolder :
		public BSTEventSource<BGSEventProcessedEvent>,           // 0000
		public BSTEventSource<TESActivateEvent>,                 // 0058
		public BSTEventSource<TESActiveEffectApplyRemoveEvent>,  // 00B0
		public BSTEventSource<TESActorLocationChangeEvent>,      // 0108
		public BSTEventSource<TESBookReadEvent>,                 // 0160
		public BSTEventSource<TESCellAttachDetachEvent>,         // 01B8
		public BSTEventSource<TESCellFullyLoadedEvent>,          // 0210
		public BSTEventSource<TESCellReadyToApplyDecalsEvent>,   // 0268
		public BSTEventSource<TESCombatEvent>,                   // 02C0
		public BSTEventSource<TESContainerChangedEvent>,         // 0318
		public BSTEventSource<TESDeathEvent>,                    // 0370
		public BSTEventSource<TESDestructionStageChangedEvent>,  // 03C8
		public BSTEventSource<TESEnterBleedoutEvent>,            // 0420
		public BSTEventSource<TESEquipEvent>,                    // 0478
		public BSTEventSource<TESFormDeleteEvent>,               // 04D0
		public BSTEventSource<TESFurnitureEvent>,                // 0528
		public BSTEventSource<TESGrabReleaseEvent>,              // 0580
		public BSTEventSource<TESHitEvent>,                      // 05D8
		public BSTEventSource<TESInitScriptEvent>,               // 0630
		public BSTEventSource<TESLoadGameEvent>,                 // 0688
		public BSTEventSource<TESLockChangedEvent>,              // 06E0
		public BSTEventSource<TESMagicEffectApplyEvent>,         // 0738
		public BSTEventSource<TESMagicWardHitEvent>,             // 0790
		public BSTEventSource<TESMoveAttachDetachEvent>,         // 07E8
		public BSTEventSource<TESObjectLoadedEvent>,             // 0840
		public BSTEventSource<TESObjectREFRTranslationEvent>,    // 0898
		public BSTEventSource<TESOpenCloseEvent>,                // 08F0
		public BSTEventSource<TESPackageEvent>,                  // 0948
		public BSTEventSource<TESPerkEntryRunEvent>,             // 09A0
		public BSTEventSource<TESQuestInitEvent>,                // 09F8
		public BSTEventSource<TESQuestStageEvent>,               // 0A50
		public BSTEventSource<TESQuestStageItemDoneEvent>,       // 0AA8
		public BSTEventSource<TESQuestStartStopEvent>,           // 0B00
		public BSTEventSource<TESResetEvent>,                    // 0B58
		public BSTEventSource<TESResolveNPCTemplatesEvent>,      // 0BB0
		public BSTEventSource<TESSceneEvent>,                    // 0C08
		public BSTEventSource<TESSceneActionEvent>,              // 0C60
		public BSTEventSource<TESScenePhaseEvent>,               // 0CB8
		public BSTEventSource<TESSellEvent>,                     // 0D10
		public BSTEventSource<TESSleepStartEvent>,               // 0D68
		public BSTEventSource<TESSleepStopEvent>,                // 0DC0
		public BSTEventSource<TESSpellCastEvent>,                // 0E18
		public BSTEventSource<TESPlayerBowShotEvent>,            // 0E70
		public BSTEventSource<TESTopicInfoEvent>,                // 0EC8
		public BSTEventSource<TESTrackedStatsEvent>,             // 0F20
		public BSTEventSource<TESTrapHitEvent>,                  // 0F78
		public BSTEventSource<TESTriggerEvent>,                  // 0FD0
		public BSTEventSource<TESTriggerEnterEvent>,             // 1028
		public BSTEventSource<TESTriggerLeaveEvent>,             // 1080
		public BSTEventSource<TESUniqueIDChangeEvent>,           // 10D8
		public BSTEventSource<TESWaitStartEvent>,                // 1130 - ?
		public BSTEventSource<TESWaitStopEvent>,                 // 1188 - ?
#if defined(EXCLUSIVE_SKYRIM_FLAT)
		public BSTEventSource<TESSwitchRaceCompleteEvent>,  // 11E0
		public BSTEventSource<TESFastTravelEndEvent>        // 1238
#else
		public BSTEventSource<TESSwitchRaceCompleteEvent>  // 11E0
#endif
	{
	public:
		static ScriptEventSourceHolder* GetSingleton();

		void SendActivateEvent(const NiPointer<TESObjectREFR>& a_objectActivated, const NiPointer<TESObjectREFR>& a_actionRef);  // may be VR only
		void SendOpenCloseEvent(const NiPointer<TESObjectREFR>& a_ref, const NiPointer<TESObjectREFR>& a_activeRef, bool a_isOpened);
		void SendSpellCastEvent(const NiPointer<TESObjectREFR>& a_object, FormID a_formID);

		template <class T>
		inline BSTEventSource<T>* GetEventSource() noexcept
		{
			return static_cast<BSTEventSource<T>*>(this);
		}

		template <>
		inline BSTEventSource<TESFastTravelEndEvent>* GetEventSource() noexcept
		{
			return AsTESFastTravelEndEventSource();
		}

		SE_ONLY_POINTER_ACCESSOR(BSTEventSource<TESFastTravelEndEvent>, AsTESFastTravelEndEventSource, 0x1238);

		template <class T>
		inline void AddEventSink(BSTEventSink<T>* a_sink)
		{
			GetEventSource<T>()->AddEventSink(a_sink);
		}

		template <class T>
		inline void PrependEventSink(BSTEventSink<T>* a_sink)
		{
			GetEventSource<T>()->PrependEventSink(a_sink);
		}

		template <class T>
		inline void RemoveEventSink(BSTEventSink<T>* a_sink)
		{
			GetEventSource<T>()->RemoveEventSink(a_sink);
		}

		template <class T>
		inline void SendEvent(const T* a_event)
		{
			GetEventSource<T>()->SendEvent(a_event);
		}
	};
	STATIC_ASSERT_SIZE(ScriptEventSourceHolder, 0x1290, 0x1238);
}
