#include "stdafx.h"
#include "Icon.h"
#include "Utils/Bitwise.h"
#include "Core/SystemError.h"

namespace gui {

#ifdef GUI_WIN32

	// Create the color bitmap.
	static HBITMAP createColorBitmap(Image *image) {
		Nat scanline = image->width() * 4;
		vector<byte> data(scanline * image->height(), 0);

		// Copy pixels, we need to shift R and B as well.
		for (Nat y = 0; y < image->height(); y++) {
			Nat start = y * scanline;
			for (Nat x = 0; x < image->width(); x++) {
				byte *src = image->buffer(x, y);
				data[start + x*4 + 0] = src[2];
				data[start + x*4 + 1] = src[1];
				data[start + x*4 + 2] = src[0];
				data[start + x*4 + 3] = src[3];
			}
		}

		return CreateBitmap(image->width(), image->height(), 1, 32, &data[0]);
	}

	// Create the mask bitmap.
	static HBITMAP createMaskBitmap(Image *image) {
		Nat scanline = roundUp((image->width() + 7) / 8, Nat(2));
		vector<byte> data(scanline * image->height(), 0);

		for (Nat y = 0; y < image->height(); y++) {
			Nat start = scanline * y;
			for (Nat x = 0; x < image->width(); x++) {
				byte *b = image->buffer(x, y);
				if (b[4] == 0) {
					Nat idx = start + x / 8;
					data[idx] |= 1 << (7 - (x % 8));
				}
			}
		}

		return CreateBitmap(image->width(), image->height(), 1, 1, &data[0]);
	}

	// Create a HICON of the desired size.
	static Handle createIcon(ImageSet *from, Nat width, Nat height) {
		Image *image = from->atLeast(width, height);
		// Note: DrawIcon seems to handle shrinking icons as needed.

		HBITMAP maskBitmap = createMaskBitmap(image);
		HBITMAP colorBitmap = createColorBitmap(image);
		// PVAR(systemErrorMessage(from->engine(), GetLastError()));
		// PVAR(colorBitmap);

		ICONINFO info;
		info.fIcon = TRUE;
		info.xHotspot = 0;
		info.yHotspot = 0;
		info.hbmMask = maskBitmap;
		info.hbmColor = colorBitmap;
		HICON created = CreateIconIndirect(&info);

		DeleteObject(colorBitmap);
		DeleteObject(maskBitmap);

		// HDC desktop = GetDC(NULL);
		// DrawIcon(desktop, 1000, 500, created);
		// ReleaseDC(NULL, desktop);

		return created;
	}

	Icon::Icon(ImageSet *from) {
		smallIcon = createIcon(from, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON));
		largeIcon = createIcon(from, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON));
	}

	Icon::~Icon() {
		DestroyIcon(largeIcon.icon());
		DestroyIcon(smallIcon.icon());
	}

#endif

#ifdef GUI_GTK

	static GdkPixbuf *createPixbuf(Image *image) {
		GdkPixbuf *buf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, image->width(), image->height());
		if (!buf)
			return null;

		guchar *dst = gdk_pixbuf_get_pixels(buf);
		int stride = gdk_pixbuf_get_rowstride(buf);

		for (Nat y = 0; y < image->height(); y++) {
			byte *src = image->buffer(0, y);
			memcpy(dst + int(y)*stride, src, image->width() * 4);
		}

		return buf;
	}

	Icon::Icon(ImageSet *from) {
		gtkImages = runtime::allocArray<GdkPixbuf *>(engine(), &pointerArrayType, from->count());
		for (Nat i = 0; i < from->count(); i++) {
			if (GdkPixbuf *buffer = createPixbuf(from->at(i)))
				gtkImages->v[gtkImages->filled++] = buffer;
		}
	}

	Icon::~Icon() {
		for (size_t i = 0; i < gtkImages->filled; i++) {
			if (gtkImages->v[i])
				g_object_unref(gtkImages->v[i]);
		}
	}

	GList *Icon::gtkList() const {
		GList *current = NULL;
		for (Nat i = gtkImages->filled; i > 0; i--) {
			GdkPixbuf *item = gtkImages->v[i - 1];
			current = g_list_prepend(current, item);
		}
		return current;
	}

#endif

}
