//////////////////////////////////////////////////////////////////////
//	filename: 	SpineEventMonitor.h
//	
//	purpose:	Monitor spAnimationState Events
/////////////////////////////////////////////////////////////////////

#pragma once 

#include <vector>
#include <string>

// forward declarations
typedef struct spAnimationState spAnimationState;
typedef struct spTrackEntry spTrackEntry;
typedef struct spEvent spEvent;

//////////////////////////////////////////////////////////////////////
//	class: 	SpineEventMonitor
//	
//	purpose:	Monitor spAnimationState Events and report when there
//				are no more spTrackEntry(s) waiting to play on track 0;
//
//				Also allows for debug printing of Events to console.
/////////////////////////////////////////////////////////////////////
class SpineEventMonitor
{
public:
	SpineEventMonitor(spAnimationState* _pAnimationState = 0);
	virtual ~SpineEventMonitor();

	void RegisterListener(spAnimationState* _pAnimationState);

	void SetDebugLogging(bool val) { bLogging = val; }
	bool GetDebugLogging() { return bLogging; }

	virtual bool isAnimationPlaying();

protected:
	static void	spineAnimStateHandler(spAnimationState* state, int type, spTrackEntry* entry, spEvent* event);
	virtual void OnSpineAnimationStateEvent(spAnimationState* state, int type, spTrackEntry* trackEntry, spEvent* event);

protected:
	spAnimationState	*pAnimState;
	bool				bLogging;
};

//////////////////////////////////////////////////////////////////////
//	class: 	InterruptMonitor
//	
//	purpose:	Allows a programmer to interrupt/stop the updating
//				of an animation based on a specific sequence of
//				events generated by the animation.
/////////////////////////////////////////////////////////////////////
class InterruptMonitor : public SpineEventMonitor
{
private:
	struct InterruptEvent
	{
		InterruptEvent() {
			mEventType = -1; // invalid
			mTrackEntry = 0;
		}

		bool matches(spAnimationState* state, int type, spTrackEntry* trackEntry, spEvent* event);

		std::string mAnimName;
		int mEventType;
		spTrackEntry* mTrackEntry;
		std::string mEventName;
	};
	typedef std::vector<InterruptEvent> InterruptEventStack;


public:
	InterruptMonitor(spAnimationState* _pAnimationState = 0);
	~InterruptMonitor() {}

	virtual bool isAnimationPlaying() override;

public:
	InterruptMonitor& AddInterruptEvent(int theEventType);
	InterruptMonitor& AddInterruptEvent(int theEventType, const std::string& theAnimationName);
	InterruptMonitor& AddInterruptEvent(int theEventType, spTrackEntry* theTrackEntry);
	InterruptMonitor& AddInterruptEventTrigger(const std::string& theEventTriggerName);

protected:
	virtual void OnSpineAnimationStateEvent(spAnimationState* state, int type, spTrackEntry* trackEntry, spEvent* event) override;
	virtual void OnMatchingComplete() {}

protected:
	bool bForceInterrupt;
	InterruptEventStack mEventStack; // must match these events in this order
	size_t mEventStackCursor;
};

/*

EXAMPLE
=======

SpineEventMonitor eventMonitor(state);
eventMonitor.SetDebugLogging(true);

while(eventMonitor.isAnimationPlaying()){
	// update...
}



EXAMPLE
=======

InterruptMonitor eventMonitor(state);
eventMonitor.SetDebugLogging(true);

// Interrupt the animation on this specific sequence of spEventType(s)
eventMonitor
	.AddInterruptEvent(SP_ANIMATION_INTERRUPT, "jump")	// First, wait for INTERRUPT signal on the 'jump' animation spTrackEntry
	.AddInterruptEvent(SP_ANIMATION_START);				// Then, stop on any following START signal


*/
