#include "common.h"
#include "dbinterface.h"

#define TIMEOUT 2

extern DbInterface dbi;

Job::Job(int nproc){
    status = QUEUED;
    bitmap_changed = 0;

    ip = port = pid = type = priority = 0;
    client_soc_fd = min_proc = max_proc = dbid = 0;

    argv = NULL;
    strcpy(argbuf, "");

    Stdout = Stdin = Stderr = working_directory = NULL;

    num_system_proc = nproc;
    num_allocated_proc = 0;

    //    bit_map = new char[num_system_proc]; // HACK CHECK LATER
    memset(bit_map, 0, num_system_proc);
    next = NULL;
}

Job::~Job(){
    /********  CHECK LATER
    if(bit_map)
	delete[] bit_map;
    */
    if(argv)
	delete[] argv;
    
}

int Job::delete_all(char *system_bit_map){

    //    close(client_soc_fd);
    
    if(type == MCHARM)
	CcsFinalize(&svr);
    
    for(int i=0; i < num_system_proc; i++)
	system_bit_map[i] |= bit_map[i];

    int nfreed = num_allocated_proc;
    num_allocated_proc = 0;

    status = FINISHED;
    dbi.update_status(dbid, FINISHED);

    return nfreed;
}

int Job::connect(){
    
    printf("In Connect %d\n", port);
    
    if(status >= CONNECTED){
	printf("Job removed or already connected\n");
	return -1;
    }

    if(CcsConnectIp(&svr, ip, port, TIMEOUT) < 0)
	return -1;

    //Successfully connected, can do set bitmaps.
    status = CONNECTED;
    //    dbi.update_status(dbid, CONNECTED);
    return 0;
}

// Checks if the job is still alive. returns 1 if the job is alive 
// else it returns 0.
int Job::ping(){
    if(kill(pid, 0) != -1)
	return 1;
    else
	return 0;
}

int Job::set_bitmap(){
    if(type != MCHARM)
	return -1;

    // BitMap has not changed.
    if(!bitmap_changed)
	return -1;

    // Not connected or could not connect, return.
    if(status != CONNECTED) //|| (status != BITMAPSET))
      return -1;

    printf("set bit map alloc = %d\n", num_allocated_proc);
    bitmap_changed = 0;
    
    //    status = BITMAPSET;

    dbi.update_bitmap(dbid, bit_map);

    return CcsSendRequest(&svr, "set_bitmap",  0, 
			  num_system_proc, bit_map, TIMEOUT);
}

void Job::parse_query(char *query){

    int count = 0;
    
    query[strlen(query)-1] = '\0';
    
    count = atoi(strtok(query, " "));
    char **temp_argv = new char*[count];
    for(int i = 0; i < count; i++)
	temp_argv[i] = strtok(NULL, " ");
    
    type = NCHARM;
    min_proc = 1;
    max_proc = num_system_proc;
    priority = 0;
    
    int name_assigned = 0;
    int argc = 0;
    
    char tempbuf[1024];
    strcpy(tempbuf, "");
    for(int i = 0; i < count; i++){
	if(strcmp(temp_argv[i], "-minpe") == 0){
	    min_proc = atoi(temp_argv[i + 1]);
	    i++;
	}
	else if(strcmp(temp_argv[i], "-maxpe") == 0){
	    max_proc = atoi(temp_argv[i + 1]);
	    i++;
	}
	else if(strcmp(temp_argv[i], "-type") == 0){
	    if(strcmp(temp_argv[i + 1], "mcharm") == 0)
		type = MCHARM;
	    else if(strcmp(temp_argv[i + 1], "mpi") == 0)
		type = MPI;
	    else if(strcmp(temp_argv[i + 1], "charm") == 0)
		type = NCHARM;
	    i++;
	}
	else if(strcmp(temp_argv[i], "-priority") == 0){
	    priority = atoi(temp_argv[i + 1]);
	    i++;
	}
	else if(!name_assigned){
	    strcpy(name, temp_argv[i]);
	    name_assigned = 1;
	}
	else{
	    strcat(tempbuf, temp_argv[i]);
	    strcat(tempbuf, " ");                 // New seperator later.
	    argc ++;
	}
    }
    
    sprintf(argbuf, "%d %s", argc, tempbuf);
    delete[] temp_argv;
}

void Job::init_arg(){    

    int argc = atoi(strtok(argbuf, " "));
    char **temp_argv = new char*[argc];
    for(int i = 0; i < argc; i++)
	temp_argv[i] = strtok(NULL, " ");

    int argcount = 0;	
    char *num_proc_string = new char[10];
    // We prepare the job's command-line arguments here.
    if(type == MCHARM){
	argv = new char*[argc + 8 + 1];
	argv[0] = "conv-host";
	sprintf(num_proc_string, "+p%d", num_system_proc);
	argv[1] = num_proc_string;
	argv[2] = "++server";
	argv[3] = "++server-port";
	argv[4] = new char[10];
	sprintf(argv[4], "%d", port);
	argv[5] = "++nodelist";
	argv[6] = NULL;
	argcount += 7;
    }
    else if(type == MPI){
	argv = new char*[argc + 6 + 1];
	argv[0] = "mpirun";
	argv[1] = "-np";	
	sprintf(num_proc_string, "%d", num_allocated_proc);
	argv[2] = num_proc_string;
	argv[3] = "-machinefile";
	argv[4] = NULL;
	argcount += 5;
    }
    else if(type == NCHARM){
	argv = new char*[argc + 5 + 1];
	argv[0] = "conv-host";
	sprintf(num_proc_string, "+p%d", num_allocated_proc);
	argv[1] = num_proc_string;
	argv[2] = "++nodelist";
	argv[3] = NULL;
	argcount += 4;
    }

    argv[argcount++] = name;

    Stdout = "socket";
    Stdin  = "socket";
    Stderr = "socket";
    
    //    printf("before loop %d %s\n", argc, temp_argv[0]);
    for(int i = 0; i < argc; i++){

	if(strcmp(temp_argv[i], "-stdout") == 0){
	    Stdout = temp_argv[i + 1];
	    i++;
	}
	else if(strcmp(temp_argv[i], "-stdin") == 0){
	    Stdin = temp_argv[i + 1];
	    i++;
	}
	else if(strcmp(temp_argv[i], "-stderr") == 0){
	    Stderr = temp_argv[i + 1];
	    i++;
	}
	else if(strcmp(temp_argv[i], "-pwd") == 0){
	    working_directory = temp_argv[i+1];
	    i++;
	}
	else{
	    argv[argcount ++] = temp_argv[i];
	}
    }

    delete[] temp_argv;
    
    //    printf("init_arg %s, %s, %s, %s, %s, %s, %s\n", argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], working_directory);

    argv[argcount] = NULL;
}

void Job::add_proc(int p){
    
    num_allocated_proc++;
    if(p < num_system_proc)
	bit_map[p] = 1;
    bitmap_changed = 1;
}

int Job::delete_proc(){
    num_allocated_proc --;
    int i;
    bitmap_changed = 1;
    for(i=0; i < num_system_proc; i++)
	if(bit_map[i] == 1)
	    break;

    if(bit_map[i] == 1){
	bit_map[i] = 0;
	return i;
    }
    else return -1;
}

void Job::Kill(){
    kill(pid, 9);
}

void Job::started(){
    status = RUNNING;
    dbi.update_status(dbid, RUNNING);
    dbi.update_pid(dbid, pid);
    dbi.update_bitmap(dbid, bit_map);
}

