#include <sys\timeb.h>
#include <SDL_ttf.h>

#include "Notification.h"
#include "Log.h"

func_on_notification_disappear_callback* _onDisappearCallback;
func_notification_must_cancel_callback* _mustCancelCallback;

Uint8 _isInitialized = 0;
SDL_Rect _notification_rectangle;
Uint8 _zoom;
#define FONT_HEIGHT 7
TTF_Font* _font;

// notification duration is always expressed in real time, 
// so it is unaffected by frame duration
Uint64 _targetMs;

#define _MESSAGE_BUFFER_SIZE 128
static char _message[_MESSAGE_BUFFER_SIZE];

void _render__NOOP_on_notification_disappear_callback() {
}

Uint8 _render__NOOP_notification_must_cancel_callback() {
	return 0;
}

void _render_text(SDL_Renderer* renderer, char* text) {
	SDL_Color textColour = { 188, 188, 255, 255 };
	SDL_Surface* messageSurface = TTF_RenderText_Solid(_font, text, textColour);
	SDL_Texture* messageTexture = SDL_CreateTextureFromSurface(renderer, messageSurface);
	SDL_FreeSurface(messageSurface);

	SDL_Rect textureRectangle;
	textureRectangle.x = _notification_rectangle.x;
	textureRectangle.y = _notification_rectangle.y;

	TTF_SizeText(_font, (const char*)text, &textureRectangle.w, &textureRectangle.h);

	SDL_RenderCopy(renderer, messageTexture, NULL, &textureRectangle);

	SDL_DestroyTexture(messageTexture);
}

void notification_show(
	char* message, 
	Uint32 durationMs, 
	func_on_notification_disappear_callback* onDisappearCallback, 
	func_notification_must_cancel_callback* mustCancelCallback
) {
	if (!_isInitialized) {
		return;
	}
	if (message == NULL) {
		return;
	}

	_onDisappearCallback = onDisappearCallback;
	if (_onDisappearCallback == NULL) {
		_onDisappearCallback = _render__NOOP_on_notification_disappear_callback;
	}

	_mustCancelCallback = mustCancelCallback;
	if (_mustCancelCallback == NULL) {
		_mustCancelCallback = _render__NOOP_notification_must_cancel_callback;
	}

	struct timeb now;
	ftime(&now);
	_targetMs = (Uint64)(1000.0 * (now.time) + (now.millitm + (Uint64)durationMs));
	
	SDL_strlcpy(_message, message, _MESSAGE_BUFFER_SIZE - 3);
}

Uint8 notification_render(SDL_Renderer* renderer) {
	if (!_isInitialized) {
		return 0;
	}

	Uint8 forceCancel = 0;
	if (_mustCancelCallback != NULL) {
		forceCancel = _mustCancelCallback();
	}

	struct timeb now;
	ftime(&now);
	Uint64 nowMs = (Uint64)(1000.0 * (now.time) + (now.millitm));
	if (nowMs >= _targetMs || forceCancel) {
		// notification is now cancelled
		_mustCancelCallback = NULL;

		// invoke callback just this frame
		if (_onDisappearCallback != NULL) {
			_onDisappearCallback();
			_onDisappearCallback = NULL;
		}

		// set target in the past
		_targetMs = 0;

		return 0;
	}

	SDL_SetRenderDrawColor(renderer, 150, 0, 0, 255);
	SDL_RenderFillRect(renderer, &_notification_rectangle);
	_render_text(renderer, _message);
	return 1;
}

void notification_start(Uint16 width, Uint16 top, Uint16 left, Uint8 zoom) {
	_zoom = zoom;

	_notification_rectangle.x = left;
	_notification_rectangle.y = top;
	_notification_rectangle.w = width;
	_notification_rectangle.h = FONT_HEIGHT*_zoom + 1*_zoom;

	if (TTF_Init() < 0) {
		log_write("Error: could not initialize fonts");
		return;
	}

	_font = TTF_OpenFont("data\\zx-spectrum.ttf", FONT_HEIGHT * _zoom);
	if (_font == NULL) {
		log_write("Error: unable to open font file");
		return;
	}

	_isInitialized = 1;
}

void notification_destroy() {
	if (!_isInitialized) {
		return;
	}

	TTF_CloseFont(_font);
}
