// Copyright (c) 1999 Microsoft Corporation. All rights reserved.
//
// Declaration of CSegTriggerTrack.
//

// This track type holds events that cause other segments to be cued at
// specific points during playback of a segment.

#pragma once

#include "trackhelp.h"
#include "tlist.h"
#include "smartref.h"

//////////////////////////////////////////////////////////////////////
// Types

// Items in list of events
struct TriggerInfo
{
	TriggerInfo() : lTriggerTime(0), lTimePhysical(0), dwPlayFlags(0), dwFlags(0), pIDMSegment(NULL) {}
	~TriggerInfo() {
		RELEASE(pIDMSegment);
	}

	HRESULT Clone(const TriggerInfo &o, MUSIC_TIME mtStart)
	{
		lTriggerTime = o.lTriggerTime - mtStart;
		lTimePhysical = o.lTimePhysical - mtStart;
		dwPlayFlags = o.dwPlayFlags;
		dwFlags = o.dwFlags;
		pIDMSegment = o.pIDMSegment;
		pIDMSegment->AddRef();
		return S_OK;
	}

	// from event header chunk <scrh>
	MUSIC_TIME lTriggerTime; // Logical time
	MUSIC_TIME lTimePhysical;
	DWORD dwPlayFlags;
	DWORD dwFlags;
	// from reference <DMRF>
	IDirectMusicSegment *pIDMSegment;
};

// State data.  This track needs to get the audio path that's currently playing so that it
// can use it when playing triggered segments.
struct CSegTriggerTrackState : public CStandardStateData<TriggerInfo>
{
	CSegTriggerTrackState() : pAudioPath(NULL) {};
	~CSegTriggerTrackState() { if (pAudioPath) pAudioPath->Release(); }
	IDirectMusicAudioPath *pAudioPath;
};

//////////////////////////////////////////////////////////////////////
// CSegTriggerTrack

class CSegTriggerTrack;
typedef CPlayingTrack<CSegTriggerTrack, TriggerInfo, CSegTriggerTrackState> CSegTriggerTrackBase;

class CSegTriggerTrack
  : public CSegTriggerTrackBase
{
public:
	// When the segment trigger track plays one of its items, it plays a segment.  If an invalidation occurs, that Play operation
	// can't be retracted.  Then the track is played again (with the FLUSH bit set).  This was causing it to trigger the segment
	// a second time.  To fix this, the last parameter to the CSegTriggerTrackBase is false, which instructs it not to call play
	// a second time when the FLUSH bit is set.
	CSegTriggerTrack(HRESULT *pHr) : CSegTriggerTrackBase(&g_cComponent, CLSID_DirectMusicSegmentTriggerTrack, true, false), m_dwFlags(NULL), m_dwRecursionCount(0) {}

	// Implement SetParam by calling SetParam in turn on all the child segments.  This is needed, for example so that downloading a segment with a segment trigger track will download all the triggered segments as well.
	STDMETHOD(IsParamSupported)(REFGUID rguid) { return S_OK; } // Once or more of our child segments could potentially support any type of parameter.
	STDMETHOD(SetParam)(REFGUID rguid, MUSIC_TIME mtTime, void *pData);

	STDMETHOD(InitPlay)(
		IDirectMusicSegmentState *pSegmentState,
		IDirectMusicPerformance *pPerformance,
		void **ppStateData,
		DWORD dwTrackID,
		DWORD dwFlags);

protected:
	HRESULT PlayItem(
		const TriggerInfo &item,
		statedata &state,
		IDirectMusicPerformance *pPerf,
		IDirectMusicSegmentState* pSegSt,
		DWORD dwVirtualID,
		MUSIC_TIME mtOffset,
		REFERENCE_TIME rtOffset,
		bool fClockTime);
	HRESULT LoadRiff(SmartRef::RiffIter &ri, IDirectMusicLoader *pIDMLoader);

private:
	HRESULT LoadTrigger(SmartRef::RiffIter ri, IDirectMusicLoader *pIDMLoader);

	// Data
	DWORD m_dwFlags; // from track header (sgth chunk)
    BOOL  m_dwRecursionCount; // Used to keep track of recursive calls to self.
};