/*
 * CVideoHandler.h, part of VCMI engine
 *
 * Authors: listed in file AUTHORS in main folder
 *
 * License: GNU General Public License v2.0 or later
 * Full text of license available in license.txt file, in main folder
 *
 */
#pragma once

#include "../lib/Rect.h"
#include "../lib/filesystem/ResourcePath.h"

struct SDL_Surface;
struct SDL_Texture;

enum class EVideoType : ui8
{
	INTRO = 0, // use entire window: stopOnKey = true, scale = true, overlay = false
	SPELLBOOK  // overlay video: stopOnKey = false, scale = false, overlay = true
};

class IVideoPlayer : boost::noncopyable
{
public:
	virtual bool open(const VideoPath & name, bool scale = false)=0; //true - succes
	virtual void close()=0;
	virtual bool nextFrame()=0;
	virtual void show(int x, int y, SDL_Surface *dst, bool update = true)=0;
	virtual void redraw(int x, int y, SDL_Surface *dst, bool update = true)=0; //reblits buffer
	virtual bool wait()=0;
	virtual int curFrame() const =0;
	virtual int frameCount() const =0;
};

class IMainVideoPlayer : public IVideoPlayer
{
public:
	virtual ~IMainVideoPlayer() = default;
	virtual void update(int x, int y, SDL_Surface *dst, bool forceRedraw, bool update = true, std::function<void()> restart = nullptr){}
	virtual bool openAndPlayVideo(const VideoPath & name, int x, int y, EVideoType videoType)
	{
		return false;
	}
	virtual std::pair<std::unique_ptr<ui8 []>, si64> getAudio(const VideoPath & videoToOpen) { return std::make_pair(nullptr, 0); };
	virtual Point size() { return Point(0, 0); };
};

class CEmptyVideoPlayer final : public IMainVideoPlayer
{
public:
	int curFrame() const override {return -1;};
	int frameCount() const override {return -1;};
	void redraw( int x, int y, SDL_Surface *dst, bool update = true ) override {};
	void show( int x, int y, SDL_Surface *dst, bool update = true ) override {};
	bool nextFrame() override {return false;};
	void close() override {};
	bool wait() override {return false;};
	bool open(const VideoPath & name, bool scale = false) override {return false;};
};

#ifndef DISABLE_VIDEO

struct AVFormatContext;
struct AVCodecContext;
struct AVCodec;
struct AVFrame;
struct AVIOContext;

VCMI_LIB_NAMESPACE_BEGIN
class CInputStream;
VCMI_LIB_NAMESPACE_END

class CVideoPlayer final : public IMainVideoPlayer
{
	int stream;					// stream index in video
	AVFormatContext *format;
	AVCodecContext *codecContext; // codec context for stream
	const AVCodec *codec;
	AVFrame *frame;
	struct SwsContext *sws;

	AVIOContext * context;

	VideoPath fname;  //name of current video file (empty if idle)

	// Destination. Either overlay or dest.

	SDL_Texture *texture;
	SDL_Surface *dest;
	Rect destRect;			// valid when dest is used
	Rect pos;				// destination on screen

	/// video playback currnet progress, in seconds
	double frameTime;
	bool doLoop;				// loop through video

	bool playVideo(int x, int y, bool stopOnKey, bool overlay);
	bool open(const VideoPath & fname, bool loop, bool useOverlay = false, bool scale = false);
public:
	CVideoPlayer();
	~CVideoPlayer();

	bool init();
	bool open(const VideoPath & fname, bool scale = false) override;
	void close() override;
	bool nextFrame() override;			// display next frame

	void show(int x, int y, SDL_Surface *dst, bool update = true) override; //blit current frame
	void redraw(int x, int y, SDL_Surface *dst, bool update = true) override; //reblits buffer
	void update(int x, int y, SDL_Surface *dst, bool forceRedraw, bool update = true, std::function<void()> onVideoRestart = nullptr) override; //moves to next frame if appropriate, and blits it or blits only if redraw parameter is set true

	// Opens video, calls playVideo, closes video; returns playVideo result (if whole video has been played)
	bool openAndPlayVideo(const VideoPath & name, int x, int y, EVideoType videoType) override;

	std::pair<std::unique_ptr<ui8 []>, si64> getAudio(const VideoPath & videoToOpen) override;

	Point size() override;

	//TODO:
	bool wait() override {return false;};
	int curFrame() const override {return -1;};
	int frameCount() const override {return -1;};

	// public to allow access from ffmpeg IO functions
	std::unique_ptr<CInputStream> data;
	std::unique_ptr<CInputStream> dataAudio;
};

#endif
