// Copyright (C) 2003 Dolphin Project.

// This program 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, version 2.0.

// This program 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 2.0 for more details.

// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/

// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/

#ifndef _FIFOPLAYER_H_
#define _FIFOPLAYER_H_

#include "FifoPlaybackAnalyzer.h"
#include <string>
#include <vector>

class FifoDataFile;
struct MemoryUpdate;
struct AnalyzedFrameInfo;

class FifoPlayer
{
public:
	typedef void(*CallbackFunc)(void);

	~FifoPlayer();

	bool Open(const std::string& filename);
	void Close();

	// Play is controlled by the state of PowerPC
	bool Play();

	FifoDataFile *GetFile() { return m_File; }

	u32 GetFrameObjectCount();
	u32 GetCurrentFrameNum() { return m_CurrentFrame; }

	// Frame range
	u32 GetFrameRangeStart() { return m_FrameRangeStart; }
	void SetFrameRangeStart(u32 start);

	u32 GetFrameRangeEnd() { return m_FrameRangeEnd; }
	void SetFrameRangeEnd(u32 end);

	// Object range
	u32 GetObjectRangeStart() { return m_ObjectRangeStart; }
	void SetObjectRangeStart(u32 start) { m_ObjectRangeStart = start; }

	u32 GetObjectRangeEnd() { return m_ObjectRangeEnd; }
	void SetObjectRangeEnd(u32 end)  { m_ObjectRangeEnd = end; }

	// If enabled then all memory updates happen at once before the first frame
	// Default is disabled
	void SetEarlyMemoryUpdates(bool enabled) { m_EarlyMemoryUpdates = enabled; }

	// Callbacks
	void SetFileLoadedCallback(CallbackFunc callback) { m_FileLoadedCb = callback; }
	void SetFrameWrittenCallback(CallbackFunc callback) { m_FrameWrittenCb = callback; }

	static FifoPlayer &GetInstance();

private:
	FifoPlayer();

	void WriteFrame(const FifoFrameInfo &frame, const AnalyzedFrameInfo &info);
	void WriteFramePart(u32 dataStart, u32 dataEnd, u32 &nextMemUpdate, const FifoFrameInfo &frame, const AnalyzedFrameInfo &info);

	void WriteAllMemoryUpdates();
	void WriteMemory(const MemoryUpdate &memUpdate);

	// writes a range of data to the fifo
	// start and end must be relative to frame's fifo data so elapsed cycles are figured correctly
	void WriteFifo(u8 *data, u32 start, u32 end);

	void SetupFifo();

	void LoadMemory();

	void WriteCP(u32 address, u16 value);
	void WritePI(u32 address, u32 value);

	void FlushWGP();

	void LoadBPReg(u8 reg, u32 value);
	void LoadCPReg(u8 reg, u32 value);
	void LoadXFReg(u16 reg, u32 value);
	void LoadXFMem16(u16 address, u32 *data);

	bool ShouldLoadBP(u8 address);

	u32 m_CurrentFrame;
	u32 m_FrameRangeStart;
	u32 m_FrameRangeEnd;

	u32 m_ObjectRangeStart;
	u32 m_ObjectRangeEnd;

	bool m_EarlyMemoryUpdates;

	u64 m_CyclesPerFrame;
	u32 m_ElapsedCycles;
	u32 m_FrameFifoSize;

	CallbackFunc m_FileLoadedCb;
	CallbackFunc m_FrameWrittenCb;

	FifoDataFile *m_File;

	std::vector<AnalyzedFrameInfo> m_FrameInfo;	
};

#endif