#include <fstream>
#include <list>
#include <string>
#include <algorithm>

#include "dither.h"
#include "format.h"
#include "filesystem.h"
#include "util.h"
#include "png++/png.hpp"
#include "lyra/lyra.hpp"

int main(int argc, char **argv) {
	std::string typenames = join(map_keys(dither_types),", ");
	std::string source, destination, palette, palette_mask("0-255"), palette_remap, colorspace("euclid"), dither_type("none");
	int palette_size = 256;
	//int ignore_palette_index = -1;
	float error_factor = 1.0;
	bool show_help = false, verbose = false;
	auto cli = lyra::cli_parser();

	cli |= lyra::help(show_help);
	cli |= lyra::opt(source, "input")["-i"]["--in"]("Input png file").required();
	cli |= lyra::opt(destination, "output")["-o"]["--out"]("Output png file").required();
	cli |= lyra::opt(palette, "palette")["-p"]["--palette"]("Use palette from png file").required();
	cli |= lyra::opt(palette_mask, "mask")["-m"]["--mask"]("Use subset of palette during quantization (comma seperated ints or ranges e.g. '0,1,10,100-255')").optional();
	cli |= lyra::opt(palette_remap, "remap")["-r"]["--remap"]("Remap colors in final pass (comma seperated int mappings e.g. '0:160,64:161,66:162,69:163')").optional();
	cli |= lyra::opt(colorspace, "colorspace")["-c"]["--colorspace"]("Use colorspace for palette matching (euclid, cie76, cmc1984, cie94g, cie94t, ciede2000, delta_gray)").optional();
	cli |= lyra::opt(dither_type, "dither")["-d"]["--dither"](string_format("Use dither algorithm (%s)",typenames.c_str())).optional();
	cli |= lyra::opt(error_factor, "factor")["-f"]["--factor"]("Scale dither error by factor").optional();
	cli |= lyra::opt(verbose)["-v"]["--verbose"]("Show verbose output").optional();

	auto result = cli.parse({argc, argv});

	if (!result) {
		std::cerr << "Error: " << result.errorMessage() << std::endl;
		std::cerr << cli << std::endl; 
		exit(1);
	}

	if (show_help) {
		std::cout << cli << std::endl;
		exit(0);
	}

	fs::path source_path(source);
	fs::path dest_path(destination);
	fs::path palette_path(palette);

	if(verbose) {
		std::cout << "in: " << source_path << std::endl;
		std::cout << "out: " << dest_path << std::endl;
		std::cout << "palette: " << palette_path << std::endl;
		std::cout << "colorspace: " << colorspace << std::endl;
		std::cout << "dither: " << dither_type << std::endl;
		std::cout << "factor: " << error_factor << std::endl;
	}

	png::image<png::rgb_pixel> input_image(source_path);
	png::image<png::index_pixel> palette_image(palette_path, png::require_color_space<png::index_pixel>());
	png::image<png::index_pixel> output_image(input_image.get_width(), input_image.get_height());
	output_image.set_palette(palette_image.get_palette());
	dither(input_image, output_image, colorspace, palette_mask, palette_remap, dither_type, error_factor);
	output_image.write(dest_path);
}
