#include <cstdio>
#include <fstream>
#include <unistd.h>
#include <cassert>

#include <kms++/kms++.h>
#include <kms++util/kms++util.h>

using namespace std;
using namespace kms;

static void read_frame(ifstream& is, DumbFramebuffer* fb, Crtc* crtc, Plane* plane)
{
	for (unsigned i = 0; i < fb->num_planes(); ++i)
		is.read((char*)fb->map(i), fb->size(i));

	unsigned w = min(crtc->width(), fb->width());
	unsigned h = min(crtc->height(), fb->height());

	int r = crtc->set_plane(plane, *fb,
				0, 0, w, h,
				0, 0, fb->width(), fb->height());

	ASSERT(r == 0);
}

static const char* usage_str =
	"Usage: kmsview [options] <file> <width> <height> <fourcc>\n\n"
	"Options:\n"
	"  -c, --connector <name>	Output connector\n"
	"  -t, --time <ms>		Milliseconds to sleep between frames\n";

static void usage()
{
	puts(usage_str);
}

int main(int argc, char** argv)
{
	uint32_t time = 0;
	string dev_path;
	string conn_name;

	OptionSet optionset = {
		Option("c|connector=", [&conn_name](string s) {
			conn_name = s;
		}),
		Option("|device=", [&dev_path](string s) {
			dev_path = s;
		}),
		Option("t|time=", [&time](const string& str) {
			time = stoul(str);
		}),
		Option("h|help", []() {
			usage();
			exit(-1);
		}),
	};

	optionset.parse(argc, argv);

	vector<string> params = optionset.params();

	if (params.size() != 4) {
		usage();
		exit(-1);
	}

	string filename = params[0];
	uint32_t w = stoi(params[1]);
	uint32_t h = stoi(params[2]);
	string modestr = params[3];

	auto pixfmt = fourcc_str_to_pixel_format(modestr);

	ifstream is(filename, ifstream::binary);

	is.seekg(0, std::ios::end);
	unsigned fsize = is.tellg();
	is.seekg(0);

	Card card(dev_path);
	ResourceManager res(card);

	auto conn = res.reserve_connector(conn_name);
	auto crtc = res.reserve_crtc(conn);
	auto plane = res.reserve_overlay_plane(crtc, pixfmt);
	FAIL_IF(!plane, "available plane not found");

	auto fb = new DumbFramebuffer(card, w, h, pixfmt);

	unsigned frame_size = 0;
	for (unsigned i = 0; i < fb->num_planes(); ++i)
		frame_size += fb->size(i);

	assert(frame_size);

	unsigned num_frames = fsize / frame_size;
	printf("file size %u, frame size %u, frames %u\n", fsize, frame_size, num_frames);

	for (unsigned i = 0; i < num_frames; ++i) {
		printf("frame %d", i);
		fflush(stdout);
		read_frame(is, fb, crtc, plane);
		if (!time) {
			getchar();
		} else {
			usleep(time * 1000);
			printf("\n");
		}
	}

	is.close();

	if (time) {
		printf("press enter to exit\n");
		getchar();
	}

	delete fb;
}
