
#include "IcoFormat.h"
#include <Spectre/System/ByteOrder.h>
#include <Spectre/Graphics/Image.h>
#include <Spectre/System/Log.h>

#include "Format/ico.h"

namespace sp {
namespace image {

ICONDIRENTRY* findLargestImage(ICONDIRENTRY *ent, uint16_t size) {

	uint32_t idx = 0, lgsz = 0, sz;

	for (int i = 0; i < size; i++) {
		sz = ent[i].width * ent[i].height;
		if (sz > lgsz) {
			lgsz = sz;
			idx = i;
		}
	}
	return ent + idx;
}

bool IcoFormat::decode(Image& img, const unsigned char *data, unsigned size)
{
	uint8_t *pixels;
	PixelFormat format;
	ICONDIRENTRY *ent;
	ICONDIRENTRY *largest;
	uint16_t type;
	uint16_t num_ent;

	type 		= system::ltoh16(data + 2);
	num_ent 	= system::ltoh16(data + 4);

	// Type: 1 = ICO, 2 = CUR
	if (type != 0x0001 || num_ent < 1) {
		return false;
	}

	// Allocate ICONDIRENT for all images in the file.
	ent = (ICONDIRENTRY *) malloc(sizeof(ICONDIRENTRY) * num_ent);
	if (!ent) {
		return false;
	}

	for (int i = 0; i < num_ent; i++) {
		unsigned int p = 6 + (i * ICONDIRENTRY_SIZE);
		ent[i].width 		 = data[p + 0];
		ent[i].height 		 = data[p + 1];
		ent[i].num_colors 	 = data[p + 2];
		ent[i].color_planes  = data[p + 4];
		ent[i].bpp			 = data[p + 6];
		ent[i].size		 	 = system::ltoh32(data + p + 8);
		ent[i].offset		 = system::ltoh32(data + p + 12);
	}

	// Find Largest image
	largest = findLargestImage(ent, num_ent);

	if (largest->bpp == 32) {
		format = PixelFormat::PF_BGRA;
	} else {
		format = PixelFormat::PF_BGR;
	}

	// NOTE: plus 40 bytes here to skip over the DIB header.
	img.create(largest->width, largest->height, data + largest->offset + 40, format);
	free(ent);

	return true;
}

}} // namespace sp::image
