/*
	Copyright (C) 2025 Mark Tyler

	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; either version 3 of the License, or
	(at your option) any later version.

	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 for more details.

	You should have received a copy of the GNU General Public License
	along with this program in the file COPYING.
*/

#ifndef GINBENCH_BE_H_
#define GINBENCH_BE_H_

#include <math.h>

#include <mtcelledit.h>
#include <mtgin.h>
#include <mtgin_sdl.h>



// Functions return: 0 = success, NULL = fail; unless otherwise stated.



#ifdef __cplusplus
extern "C" {
#endif

// C API

enum
{
	TEST_TOTAL_DEFAULT	= 100,
	TEST_TOTAL_MIN		= 1,
	TEST_TOTAL_MAX		= 1000000,
};



#ifdef __cplusplus
}

// C++ API

class CommandLine;
class TestSuite;



using PixmapVector = std::vector< mtPixy::Pixmap >;



class CommandLine
{
public:
	explicit CommandLine ( TestSuite & suite )
		:
		m_suite	( suite )
	{
	}

	int parse ( int argc, char const * const * argv );
		// 0 = Continue running (start UI)
		// 1 = Terminate program, returning exit.value()

	int get_test_total () const		{ return m_test_total; }
	char const * get_output_dir () const	{ return m_output_dir; }
	char const * get_output_sheet () const	{ return m_output_sheet; }
	int get_verbose () const		{ return m_verbose; }

	// Accessors

	mtKit::Exit & exit ()			{ return m_exit; }

/// ----------------------------------------------------------------------------

private:

/// ----------------------------------------------------------------------------

	mtKit::Exit	m_exit;
	TestSuite	& m_suite;

	int		m_test_total		= TEST_TOTAL_DEFAULT;
	char	const	* m_output_dir		= nullptr;
	char	const	* m_output_sheet	= nullptr;
	int		m_verbose		= 0;
};



class TestSuite
{
public:
	int init ( CommandLine const * const cline );
	int finish ();

	void run_test_unit ( char const * name );
	void list_units () const;
	int load_patterns ( char const * filename );
	int load_shapes ( char const * filename );

private:
	void prep_tests ();
	void prep_sprites ();
	void prep_palette ( mtPixmap * pixmap );

	void run_test_all ();

	void run_test_clear( PixmapVector &canvas );
	void run_test_dup( PixmapVector &canvas );
	void run_test_idx2rgb( PixmapVector &canvas );
	void run_test_lines( PixmapVector &canvas );
	void run_test_rects( PixmapVector &canvas );
	void run_test_paste( PixmapVector &canvas, PixmapVector const &sprites);
	void run_test_apaste( PixmapVector &canvas, PixmapVector const &sprites);
	void run_test_text();
	void run_test_sdl( PixmapVector &canvas );

	void print_next_test_name ( char const * name, char const * unit );
	void print_per_sec ( double secs );
	void print_percent ( double secs_total, double secs_used );

/// ----------------------------------------------------------------------------

	struct TestInfo
	{
		std::function<void()>	func;
		std::string		description;
		std::string		measure;
	};

	std::map< std::string, TestInfo > const m_test_map = {
		{ "all", { [this]()
			{
				run_test_all ();
			}
			, "Run all of the tests."
			, "per/sec"
		}},
		{ "clear", { [this]()
			{
				run_test_clear( m_canvases_idx );
				run_test_clear( m_canvases_rgb );
			}
			, "Clear the canvas."
			, "per/sec"
		}},
		{ "dup", { [this]()
			{
				run_test_dup( m_canvases_idx );
				run_test_dup( m_canvases_rgb );
			}
			, "Duplicate the canvas."
			, "per/sec"
		}},
		{ "idx2rgb", { [this]()
			{
				run_test_idx2rgb( m_canvases_idx );
				run_test_idx2rgb( m_canvases_rgb );
			}
			, "Convert to RGB canvas."
			, "per/sec"
		}},
		{ "lines", { [this]()
			{
				run_test_lines( m_canvases_idx );
				run_test_lines( m_canvases_rgb );
			}
			, "Paint lines on canvas."
			, "per/sec"
		}},
		{ "rects", { [this]()
			{
				run_test_rects( m_canvases_idx );
				run_test_rects( m_canvases_rgb );
			}
			, "Paint rectangles on canvas."
			, "per/sec"
		}},
		{ "paste", { [this]()
			{
				run_test_paste( m_canvases_idx, m_sprites_idx );
				run_test_paste( m_canvases_rgb, m_sprites_rgb );
			}
			, "Paste the sprites onto the canvas."
			, "per/sec"
		}},
		{ "apaste", { [this]()
			{
				run_test_apaste( m_canvases_idx, m_sprites_idx );
				run_test_apaste( m_canvases_rgb, m_sprites_rgb );
			}
			, "Paste the sprites with alpha onto the canvas."
			, "per/sec"
		}},
		{ "text", { [this]()
			{
				run_test_text();
			}
			, "Create some text string pixmaps."
			, "per/sec"
		}},
		{ "sdl", { [this]()
			{
				run_test_sdl( m_canvases_idx );
				run_test_sdl( m_canvases_rgb );
			}
			, "Test blitting to an SDL window."
			, "CPU %"
		}},
	};

/// ----------------------------------------------------------------------------

	CommandLine	const	* m_cline;

	mtKit::Clock		m_clock_whole;
	mtKit::Random		m_random;

	mtCED::Sheet		m_sheet_results;
	int			m_results_row = 1;
	int			m_results_column = 1;

	mtPixy::Brush		m_brush;

	PixmapVector		m_sprites_idx;
	PixmapVector		m_sprites_rgb;

	PixmapVector		m_canvases_idx;
	PixmapVector		m_canvases_rgb;
};



#endif		// C++ API



#endif		// GINBENCH_BE_H_

