#include "response.h"
#include "socket-common.h"
#include "lcd.h"
#include "i2c.h"
#include "signalobject.h"
#include "parser.h"
#include <string.h>
#include <stdlib.h>
#include <glib.h>

//RESPONSE related functions from the server

extern guint signalMyCb; //signal id
extern GAsyncQueue* stdinQueue; //our queue
SignalObject* signalObject; //the signal object which registered the signal id

//write output to client
static void writeOutput(GPollableOutputStream* stream, gchar* data);

//callback for client output, this is where the queue messages are sent to the client
gboolean cbClientOutput(gpointer data, gpointer additional)
{
	GPollableOutputStream* outStream = (GPollableOutputStream*)data;
	GAsyncQueue* queue = (GAsyncQueue*)additional;
	if(g_async_queue_length(queue) <= 0) {
		return FALSE;
	}

	gpointer elem;
	//try to pop an element from the queue
	elem=g_async_queue_try_pop(queue);
	if(elem) {
		char* buf = (char*)elem;
		gssize size = strlen(buf);
		gssize written = 0;

		written=g_pollable_output_stream_write_nonblocking(outStream, buf, size+1, NULL, NULL);
		if(written==-1) {
			g_printerr("Could not write to client\n");
		}

		//free the alloc'ed memory
		free(buf);
	}

	return FALSE;
}

//the client input callback
gboolean cbClientInput(gpointer data, gpointer additional)
{

	char buffer[1024];
	gssize size=0;
	memset(buffer,0,1024);

	GPollableInputStream* inStream = (GPollableInputStream*)data;
	GPollableOutputStream* outStream = (GPollableOutputStream*)additional;
	GError* error = NULL;

	if(!g_pollable_input_stream_is_readable(inStream)) {
		return FALSE;
	}
	size=g_pollable_input_stream_read_nonblocking(inStream, buffer, 1024, NULL, &error);

	if(error && error->message) {
		g_print_debug("Error: %s\n",error->message);
		return FALSE;
	}

	if(size <= 0) {
		g_print_debug("Got: %d\n", (int) size);
		return FALSE;
	}

	//emit a signal which calls the echoCb function
	SignalObjectClass myStruct;
	myStruct.instance = NULL;
	myStruct.cb = writeOutput;
	myStruct.data = buffer;
	myStruct.size = size;
	myStruct.inStream = inStream;
	myStruct.outStream = outStream;
	g_signal_emit(signalObject, signalMyCb, 0, &myStruct, NULL);

	return TRUE;
}

//write output to client
static void writeOutput(GPollableOutputStream* stream, gchar* data)
{
	gssize written_bytes = 0;

	gchar *terminated;
	if (data==NULL) {
		terminated = g_strdup("");
	} else if (!strlen(data)) {
		// prompt generation
		terminated = g_strdup("\r\n> ");
	} else {
		terminated = g_strdup_printf ("%s\r\n", data);
	}

	written_bytes = g_pollable_output_stream_write_nonblocking(stream, terminated, strlen(terminated), NULL, NULL);
	if (written_bytes == -1) {
		g_print("Could not send message to client\n");
	}

	g_free (terminated);
	return;
}

//initialize the signals
void initSignals(guint *signal)
{
	*signal = g_signal_new("runService", SIGNAL_OBJECT_TYPE, G_SIGNAL_RUN_FIRST, 0, NULL, NULL,
	                       g_cclosure_marshal_VOID__POINTER , G_TYPE_NONE, 1, G_TYPE_POINTER);

	signalObject = g_object_new(SIGNAL_OBJECT_TYPE, NULL);
	g_signal_connect (signalObject, "runService", G_CALLBACK (responseCb), NULL);
}

//parse message and send to client
void responseCb(gpointer instance, GObject *arg1, gpointer user_data)
{
	static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
	g_static_mutex_lock (&mutex);
	SignalObjectClass *data = (SignalObjectClass*)arg1;
	GPollableOutputStream* stream = (GPollableOutputStream*)data->outStream;
	gchar* str = data->data;

	Parser_main(str, 1, data->cb, stream);

	g_static_mutex_unlock (&mutex);
}