/*
 * grifo_playback.h
 *
 */

#ifndef GRIFO_PLAYBACK_H_
#define GRIFO_PLAYBACK_H_

#include <stdint.h>

#include "ghost.h"

class GrifoPlaybackStreamReader
{
public:
	typedef int64_t stream_offset_t;

	virtual const char* streamName() const = 0;

	virtual void setStreamName(const char* name)=0;

	virtual bool streamOpen(const char* name)=0;

	virtual bool isOpen()=0;

	virtual void setAutorewind(bool autorewind)=0;

	virtual int read(void* datum, unsigned int size)=0;

	virtual uint32_t read32() { uint32_t tmp=0; read(&tmp, sizeof tmp); return tmp;}

	template<typename T_> int readDatum(T_* datum) { return read(datum, sizeof *datum);}


	virtual stream_offset_t currentPosition() const =0;	//as ftell()
	virtual int setCurrentPosition(stream_offset_t pos)=0;
	virtual int moveCurrentPosition(stream_offset_t offset)=0;

	virtual bool eof()  { return true;}
	virtual void rewind() {}
	virtual bool error() { return false;}

	virtual const void* getDataPointer(stream_offset_t pos) const;

	virtual ~GrifoPlaybackStreamReader();
};


extern GrifoPlaybackStreamReader* GrifoPlaybackCreateStdioReader();


class GrifoPlaybackMarker
{
public:
	typedef uint64_t marker_t;

	static bool isEqual(marker_t mrk, const char* str);
};

class GrifoPlaybackStream
{
public:
	struct marker_t
	{
		uint64_t value;
	};


	struct blockHandle
	{
		char name[16];
		unsigned int src;
		unsigned int dst;
		unsigned int size;

		GrifoPlaybackStreamReader::stream_offset_t offset;

		unsigned int soft_block;

		uint32_t b_counter;
		uint32_t s_counter;
		uint32_t b_timetag;
		uint32_t s_timetag;

		uint32_t buffer_status;
		uint32_t buffer_level;
	};

	static void setReaderInterface(GrifoPlaybackStreamReader*);
	//static void setLoggerInterface(GhostLogger*);

	static void reset();

	static marker_t nextBlock();

	typedef void* block_observer_cookie_t;

	typedef int (*block_observer_t)(block_observer_cookie_t cookie, const blockHandle& handle);

	static void registerBlockObserver(const char* marker, block_observer_t observer, block_observer_cookie_t cookie);

	static void registerPromisucousBlockObserver(block_observer_t observer, block_observer_cookie_t cookie);

	static bool readBlockData(void* buffer, unsigned int size);
	static bool readBlockData(void* buffer, const GrifoPlaybackStream::blockHandle&, unsigned int size=0);

	static bool readSignal(void* buffer, const GrifoPlaybackStream::blockHandle&);

	static const void* getDataPointer(const GrifoPlaybackStream::blockHandle& b);

	static GrifoPlaybackStream::blockHandle tryDecodeSoftReference(const void* p);

	static void scanFpgaHeader(void* hdrBuffer, unsigned hdrBufSize, const blockHandle& handle);
	static void scanHeaderExt(const blockHandle& handle, unsigned int start_offset);

	static const char* preprocessSoftHeader(const void* buffer, unsigned int size);

	//static void registerheaderObserver(const char* marker, block_observer_t observer, block_observer_cookie_t cookie);


	template<class T_> static void registerMethodBlockObserver(const char* marker, T_& obj, int (T_::*handleMethod)(const blockHandle&))
	{
		struct obs_cookie_t
		{
			T_* obj;
			int (T_::*mH)(const blockHandle&);


			static int obsCall(void* cookie, const blockHandle& b)
			{
				obs_cookie_t& c=*reinterpret_cast<obs_cookie_t*>(cookie);
				return (c.obj->*c.mH)(b);
			}
		};
		obs_cookie_t c={&obj, handleMethod};
		registerBlockObserver_(marker, obs_cookie_t::obsCall, &c, sizeof c);
	}

	template<class T_> static void registerMethodHeaderObserver(const char* marker, T_& obj, int (T_::*handleMethod)(const blockHandle&))
	{
		struct obs_cookie_t
		{
			T_* obj;
			int (T_::*mH)(const blockHandle&);


			static int obsCall(void* cookie, const blockHandle& b)
			{
				obs_cookie_t& c=*reinterpret_cast<obs_cookie_t*>(cookie);
				return (c.obj->*c.mH)(b);
			}
		};
		obs_cookie_t c={&obj, handleMethod};
		registerHeaderObserver_(marker, obs_cookie_t::obsCall, &c, sizeof c);
	}

	static void sleep(unsigned int ms);

	static void videoReaplyEnable();

private:
	static void registerBlockObserver_(const char* marker, block_observer_t observer, block_observer_cookie_t cookie, unsigned int cookie_size);
	static void registerHeaderObserver_(const char* marker, block_observer_t observer, block_observer_cookie_t cookie, unsigned int cookie_size);

};


#endif /* GRIFO_PLAYBACK_H_ */
