#include "blue-dream.h"
#include "w_interface.h"

typedef struct t_resource
{
	int id;
	void *node;
	t_resource *next;
} t_resource;

t_resource *add_resource(t_resource *resource, int id, void *node)
{
	t_resource *next = (t_resource *)malloc(sizeof(t_resource));
	if (next == NULL) return NULL;

	next->id = id;
	next->node = node;
	next->next = NULL;

	t_resource *current = resource;

	while (NOT_NULL(current))
	{
		if (NOT_NULL(current->next))
			current = current->next;
		else 
		{
			current->next = next;
			break;
		}
	}

    return next;
}

void destroy_resource(t_resource *resource)
{
	t_resource *current = resource;
	t_resource *next = NULL;

	while (NOT_NULL(current))
	{
		if (NOT_NULL(current->node))
			free(current->node);

		if (NOT_NULL(current->next))
			next = current->next;

		else next = NULL;

		free(current);
		current = next;
	}
}

int SaveD2DBitmap(BYTE *source, int width, int height, LPCWSTR filename)
{
	IWICImagingFactory *piFactory = NULL;
	IWICBitmapEncoder *piEncoder = NULL;
	IWICBitmapFrameEncode *piBitmapFrame = NULL;
	IPropertyBag2 *pPropertybag = NULL;

	IWICStream *piStream = NULL;
	UINT uiWidth = width;
	UINT uiHeight = height;

	HRESULT hr = CoCreateInstance(
		CLSID_WICImagingFactory,
		NULL,
		CLSCTX_INPROC_SERVER,
		IID_IWICImagingFactory,
		(LPVOID *)&piFactory);

	if (SUCCEEDED(hr))
	{
		hr = piFactory->CreateStream(&piStream);
	}

	if (SUCCEEDED(hr))
	{
		hr = piStream->InitializeFromFilename(filename, GENERIC_WRITE);
	}

	if (SUCCEEDED(hr))
	{
		hr = piFactory->CreateEncoder(GUID_ContainerFormatPng, NULL, &piEncoder);
	}

	if (SUCCEEDED(hr))
	{
		hr = piEncoder->Initialize(piStream, WICBitmapEncoderNoCache);
	}

	if (SUCCEEDED(hr))
	{
		hr = piEncoder->CreateNewFrame(&piBitmapFrame, NULL);
	}


	hr = piBitmapFrame->Initialize(NULL);
	if (SUCCEEDED(hr))
	{
		hr = piBitmapFrame->SetSize(uiWidth, uiHeight);
	}

	WICPixelFormatGUID formatGUID = GUID_WICPixelFormat32bppBGRA;
	if (SUCCEEDED(hr))
	{
		hr = piBitmapFrame->SetPixelFormat(&formatGUID);
	}

	if (SUCCEEDED(hr))
	{
		// We're expecting to write out 24bppRGB. Fail if the encoder cannot do it.
		hr = IsEqualGUID(formatGUID, GUID_WICPixelFormat32bppBGRA) ? S_OK : E_FAIL;
	}

	if (SUCCEEDED(hr))
	{
		UINT cbStride = (uiWidth * 32) / 8/***WICGetStride***/;
		UINT cbBufferSize = uiHeight * cbStride;

		BYTE *pbBuffer = source;

		if (pbBuffer != NULL)
		{
			hr = piBitmapFrame->WritePixels(uiHeight, cbStride, cbBufferSize, pbBuffer);
		}
		else
		{
			hr = E_OUTOFMEMORY;

		}
	}

	if (SUCCEEDED(hr))
	{
		hr = piBitmapFrame->Commit();
	}

	if (SUCCEEDED(hr))
	{
		hr = piEncoder->Commit();
	}

	if (piFactory)
		piFactory->Release();

	if (piEncoder)
		piEncoder->Release();

	if (piBitmapFrame)
		piBitmapFrame->Release();

	if (pPropertybag)
		pPropertybag->Release();

	if (piStream)
		piStream->Release();

	return hr;
}

void Render(t_w_interface *w_interface)
{
	if (w_interface == NULL) return;
	if (w_interface->d2d_render_target == NULL) return;
	if (w_interface->d2d_bitmap == NULL) return;

	w_interface->d2d_render_target->BeginDraw();
	w_interface->d2d_render_target->SetTransform(D2D1::Matrix3x2F::Identity());
	w_interface->d2d_render_target->Clear(D2D1::ColorF(D2D1::ColorF::Black));

	D2D1_SIZE_F rtSize = w_interface->d2d_render_target->GetSize();

	w_interface->d2d_render_target->DrawBitmap
	(
		w_interface->d2d_bitmap,
		D2D1::RectF(0.0f, 0.0f, WINDOW_W, WINDOW_H),
		1.0,
		D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR
	);

	w_interface->d2d_render_target->EndDraw();
}

int WINAPI WinMain
(
	HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPSTR pCmdLine,
	int nCmdShow
)
{
	t_w_interface *w_interface = NULL;
	t_core *core = NULL;

	HRESULT hr = S_OK;

	HeapSetInformation(
		NULL,
		HeapEnableTerminationOnCorruption,
		NULL,
		0);

	core = create_core();
	if (core == NULL) return 0;
	get_eng_language(core->language);

	if (SUCCEEDED(CoInitialize(NULL)) == FALSE)
	{
		append_log
		(
			DIAGNOSTICS_LOG,
			get_language_record((const t_unicode **)core->language, LNG_COM_INITIALIZE_F)
		);

		return 0;
	}

	w_interface = create_w_interface(core, hInstance);
	if (w_interface == NULL)
	{
		release_core(core);
		return 0;
	}

	if (wi_create_window(w_interface, core, nCmdShow) < 0)
	{
		release_core(core);
		return 0;
	}

	if (wi_create_direct2d(w_interface, core) < 0)
	{
		release_core(core);
		return 0;
	}

	D2D1_RECT_U region = { 0, 0, VIEWPORT_W, VIEWPORT_H};
	
	if (core_setup(core) < 0)
	{
		release_core(core);
		release_w_interface(w_interface);

		show_taskbar(1);
		return 0;
	}

	MSG msg = {};
	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);

		core_process(core);

		w_interface->d2d_bitmap->CopyFromMemory(&region, core->viewport, VIEWPORT_W * 4);

		Render(w_interface);
		InvalidateRect(w_interface->hwnd, NULL, TRUE);
	}

	release_core(core);
	release_w_interface(w_interface);

	show_taskbar(1);
	return 0;
}