/*
	Main library.	See Docs/model.txt (or perhaps, you should just try 
	to dicipher the comments in the code instead.)
	
	-- Roy Keene [151119990247] rkeene@suspend.net
*/

#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#ifdef DEBUG
#include <stdio.h>
#endif
#include "distlib.h"
#include "net.h"

int taskid=1;
int distlib_connection_fd[32]={-1, -1, -1, -1, -1, -1, -1, -1,
                               -1, -1, -1, -1, -1, -1, -1, -1,
                               -1, -1, -1, -1, -1, -1, -1, -1,
                               -1, -1, -1, -1, -1, -1, -1, -1};
char *distlib_hosts[DISTLIB_NUM_HOSTS]={"10.0.0.1", "10.0.0.3"};
struct distlib_hostinfo distlib_hostinfo_data[DISTLIB_NUM_HOSTS];

int distlib_calc_int (int v1, int v2, unsigned char op, int n, int cost) {
	struct distlib_calc_msg1 mesg;
	mesg.v1=v1;
	mesg.v2=v2;
	mesg.op=op;
#ifdef DEBUG
	printf("distlib.c: distlib_calc_int(%i, %i, %i, %i, %i)\n",v1,v2,op,n,cost);
	printf("distlib.c: distlib_calc_int: sizeof(mesg)=%i\n",sizeof(mesg));
	printf("distlib.c: distlib_calc_int: sizeof(distlib_calc_msg1)=%i\n",sizeof(struct distlib_calc_msg1));
#endif
	return(distlib_sendmessage(0, &mesg, sizeof(mesg)-3, DISTLIB_TYPE_CALC_INT, 0, cost));
}

int distlib_calc_float (float v1, float v2, unsigned char op, int n, int cost) {
	struct distlib_calc_msg2 mesg;
	mesg.v1=v1;
	mesg.v2=v2;
	mesg.op=op;
#ifdef DEBUG
	printf("distlib.c: distlib_calc_float(%f, %f, %i, %i, %i)\n",v1,v2,op,n,cost);
	printf("distlib.c: distlib_calc_float: sizeof(mesg)=%i\n",sizeof(mesg));
#endif
	return(distlib_sendmessage(0, &mesg, sizeof(mesg)-3, DISTLIB_TYPE_CALC_FLOAT, 0, cost));
}

int distlib_exec (char path[127], char args[128][127], int cost) {
	struct distlib_exec_msg mesg;
	strcpy(mesg.path,path);
	return(-1);
}


int distlib_memset (char *name, char *value, int size) {
	struct distlib_mem *mesg;
	int taskid;
	mesg=malloc(size+64+sizeof(size));
	mesg->size=size;
#ifdef DEBUG
	printf("distlib.c: distlib_memset(\"%s\",\"%s\",%i)\n",name,value,size);
	strncpy(mesg->name,name,63);
	printf("distlib.c: distlib_memset: strncpy(mesg.name, name, 63)\n");
	strcpy(&(mesg->value),value);
	printf("distlib.c: distlib_memset: strcpy(mesg.value,value)\n");
#else
	strncpy(mesg->name,name,63);
	strcpy(mesg->value,value);
#endif
	taskid=distlib_sendmessage(0, mesg,size+64+sizeof(size),DISTLIB_TYPE_MEM, 0, DISTLIB_COST_MEMSET);
	free(mesg);
	return(taskid);
}

/*
distlib_msg_reply *distlib_getmem(char *name) {
	
}
*/

int distlib_sendmessage (int desthost, void *message, int size, unsigned char typeid, int taskid, unsigned char cost) {
	struct distlib_msg_hdr hdr;
	unsigned char dest[(sizeof(hdr)+size)];
	int new_taskid=0;
#ifdef DEBUG
	int i;
#endif
	hdr.size[0]=sizeof(dest)&0xff;
	hdr.size[1]=sizeof(dest)&0xff00;
	hdr.size[2]=sizeof(dest)&0xff0000;
	hdr.size[3]=sizeof(dest)&0xff000000;
	hdr.typeid=typeid;
	hdr.cost=cost;
	hdr.taskid=taskid;
#ifdef DEBUG
	printf("distlib.c: distlib_sendmessage(%i, %lu, %i, %i, %i)\n", desthost, (unsigned long) &message, size, typeid, cost);
#endif
	if (distlib_connection_fd[desthost]==-1) distlib_init(desthost);
	memcpy((void *) dest, &hdr, sizeof(hdr));
	memcpy(((void *) dest)+sizeof(hdr), message, size);
	write(distlib_connection_fd[desthost],&dest,sizeof(dest));
	read(distlib_connection_fd[desthost], &new_taskid, sizeof(new_taskid));
#ifdef DEBUG
	printf("distlib.c: distlib_sendmessage: dest[]={");
	for (i=0;i<sizeof(dest);i++)
		printf("0x%-2x ", dest[i]);
	printf("}\n");
#endif
	return(new_taskid);
}

void distlib_init (int dest) {
#ifdef DEBUG
	printf("distlib.c: distlib_init(%i)\n", dest);
	printf("distlib.c: distlib_init: distlib_hosts[%i]=%s\n", dest, distlib_hosts[dest]);
#endif
	if (distlib_connection_fd[dest]!=-1) return;
	distlib_hostinfo_data[dest].load=0;
	distlib_hostinfo_data[dest].max_load=1000;
	distlib_connection_fd[dest]=createconnection_tcp(distlib_hosts[dest] ,PORT);
	return;
}

int distlib_decode (unsigned char *data, int size) {
	unsigned long packet_size;
	int loc=0;
	struct distlib_msg_hdr hdr;
	void *packet;
	while (1) {
		memcpy(&hdr, &data[loc], sizeof(hdr));
		packet_size=hdr.size[0]+(hdr.size[1]<<8)+(hdr.size[2]<<16)+(hdr.size[3]<<24);
		packet=malloc(packet_size-sizeof(hdr));
		memcpy(packet, &data[loc+sizeof(hdr)], packet_size-sizeof(hdr));
		printf("%lu, %i, %i\n",packet_size, hdr.typeid, hdr.cost);
		switch (hdr.typeid) {
			case DISTLIB_TYPE_CALC_INT:
				printf("Got DISTLIB_TYPE_CALC_INT!\n");
				distlib_sendmessage(distlib_create_job(hdr.cost, hdr.taskid),packet,packet_size-sizeof(hdr), hdr.typeid, hdr.taskid, hdr.cost);
				break;
			case DISTLIB_TYPE_CALC_FLOAT:
				printf("Got DISTLIB_TYPE_CALC_FLOAT!\n");
				break;
			default:
				printf("Got type %i!\n",hdr.typeid);
		}
		loc+=packet_size;
		if (loc>=size) break;		
	}
	free(packet);
	return(-1);
}


int distlib_create_taskid (void) {
#ifdef DEBUG
	printf("distlib.c: distlib_create_taskid()\n");
#endif
	taskid++;
	return(taskid);
}


/*
	Look for a host with the lowest Load and add COST to it.
	Return it's host ID.
*/
int distlib_create_job (int cost, int taskid) {
	int i,lowest=0;
#ifdef DEBUG
	printf("distlib.c: distlib_create_job(%i, %i)\n", cost, taskid);
#endif
	for (i=0;i<(DISTLIB_NUM_HOSTS-1);i++) {
		if (distlib_hostinfo_data[i].load<lowest) {
			lowest=distlib_hostinfo_data[i].load;
			break;
		}
	}
	distlib_hostinfo_data[i].load+=cost;
#ifdef DEBUG
	printf("distlib.c: distlib_create_job: i=%i\n", i);
#endif
	return(i);
}
