#include <stdio.h>
#include <string.h>
#include <err.h>
#include <libgen.h>
#include <getopt.h>

#include "cli.h"

int main(int argc, char **argv)
{
	int cmdID = -1;
	char * command;
	int c;
	int i , useSymlink = 0;
	struct backend_conn  *conn;
	int needCliHelp = 0, needCommandHelp = 0;

	// Determine if the cli was called using a symlink
	command = basename(argv[0]);
	for(i = 0; i < MAX_COMMANDS; ++i) {
		if (strncmp(command, commandNames[i], strlen(commandNames[i])) == 0)
		{
			cmdID = i;
			useSymlink = 1;
		}
	}

	// Verify the user has entered enough information to continue
	if (argc < 2 && !useSymlink) {
		printf("Incorrect usage :\n");
		printf("Usage Syntax: \n\t./Cli command [options...]\n\n");
		printf("For a list of available 'command' names\n\t./Cli --help\n\n");
		printf("For a list of available options for a 'command'\n\t./Cli command --help\n");
		return -1;
	}

	if (!useSymlink) {
		// Determine if the user called for help on the cli
		needCliHelp = (strncmp("--help", argv[1], strlen(argv[1])) ==  0);
	}

	// If the user runs './Cli help' , provide the user with a list of commands available.
	if (needCliHelp) {
		printf("Usage Syntax: \n\t./Cli command [options...]\n\n");
		printf("Available 'command' names include the following\n");
		for(int i = 0; i < MAX_COMMANDS; ++i) {
			printf("\t '%s'\n",commandNames[i]);
		}
		return 0;
	}

	// recognize which cli command the user has entered
	if (cmdID == -1) {
		command = argv[1];
		for (i = 0; i < MAX_COMMANDS; ++i) {
			if (strncmp(command, commandNames[i], strlen(commandNames[i])) == 0) {
				cmdID = i;
			}	
		}
	}

	if (cmdID == -1){
		printf("Could not match '%s' with a command. Please try again...\n", command);
		printf("For help running the program, run ./Cli --help\n");
		return -1;
	}

	// Determine if the user called for help on the command
	if (!useSymlink && argc > 2) {
		if (strncmp("--help", argv[2], strlen(argv[2])) == 0) {
			needCommandHelp = 1;
		}
	} else if (useSymlink && argc > 1) {
		if (strncmp("--help", argv[1], strlen(argv[1])) == 0) {
			needCommandHelp = 1;
		}
	}
	
	/**
	 * If the user has asked for help, and we have already found
	 *  the command that they are trying to use. Then we need
	 *  to be able to provide the help info wihtout the 
	 *  requirement of the backend
	 *
	 * It is important to note that this will only work if the 
	 * 	command the user has asked for handles this help case 
	 * 
	 */

	// Only require the backend if we will need to use it.
	if (!needCommandHelp) {
		// Create the connection to the backend
		conn = ucart_backendConnect();
		if (conn == NULL) {
			return -1;
		}
	}

	// Call the appropriate function
	if (useSymlink) {
		(*cli_functions[cmdID]) (conn, argc, &argv[0]);
	} else {
		(*cli_functions[cmdID]) (conn, argc-1, &argv[1]);
	}

	// Disconnect from the backend
	if (!needCommandHelp) {
		ucart_backendDisconnect(conn);
	}
    return 0;
}

/* This function is called by other cli functions to check for a help condition */
int help_check(int argc, char ** argv) {
	int c;
	static int needHelp = 0;
	static struct option long_options[] = {
 		/* These options don’t set a flag. We distinguish them by their indices. */
 		{"help",	no_argument,	&needHelp,	1},
 		{0, 0, 0, 0}
 	};

 	while (1)
	{
		/* getopt_long stores the option index here. */
		int option_index = 0;

		c = getopt_long(argc, argv, "h", long_options, &option_index);

		/* Detect the end of the options. */
		if (c == -1)
			break;

		if (c == 'h') {
			needHelp = 1;
		}
	}
	return needHelp;
}

int isNumber(char *number) {
    int i = 0;
    //checking for negative numbers
    if (number[0] == '-')
        i = 1;
    for (; number[i] != 0; i++)
    {
        //if (number[i] > '9' || number[i] < '0')
        if (!isdigit(number[i]))
            return 0;
    }
    return 1;
}

int convert_to_id(struct backend_conn * conn, char **argv, struct convert_data * convert_data, int conversion_requirement) {
	/* variables used to search for id values */
	size_t num_nodes = 0, i;
	struct frontend_node_data* search_data = NULL;
	int search_1 = 0, search_2 = 0;
	const struct graph_node_type * node_definition;

		

	if (!isNumber(argv[1])) {
		search_1 = 1;
	} else {
		convert_data->val_1 = atoi(argv[1]);	
	}

	if (!isNumber(argv[2])) {
		search_2 = 1;
	} else {
		convert_data->val_2 = atoi(argv[2]);
	}

	if (!search_1 && !search_2) {
		return 0;
	}

	/**
	 * node_data must be NULL,
	 * num_nodes must equal zero.
	 */
	if (frontend_getnodes(conn, &search_data, &num_nodes)) {
		return 1;
	}

	if (search_1) {
		for (i = 0; i < num_nodes; ++i) {
			if (strncasecmp(search_data[i].name, argv[1], strlen(search_data[i].name)) == 0) {
				convert_data->val_1 = search_data[i].block;
				node_definition = blockDefs[search_data[i].type];
				break;
			}
		}
	}

	if (i == num_nodes)
		return 1;

	if (search_2) {
		const int  *num_s2_options;
		const char* const* s2_options_arr;

		if (!search_1) {
			node_definition = blockDefs[search_data[convert_data->val_1].type];
		}
		
		switch (conversion_requirement) {
			case PARAM:
				num_s2_options = &node_definition->n_params;
				s2_options_arr = node_definition->param_names;
				break;
			case INPUT:
				num_s2_options = &node_definition->n_inputs;
				s2_options_arr = node_definition->input_names;
				break;
			case OUTPUT:
				num_s2_options = &node_definition->n_outputs;
				s2_options_arr = node_definition->output_names;
				break;
		}

		for (i = 0; i < (size_t)*num_s2_options; ++i) {
			if (strncasecmp(s2_options_arr[i], 
					argv[2], 
					strlen(s2_options_arr[i])) == 0) {
				convert_data->val_2 = i;
				search_2 = 0;
				break;
			}
		}
	}
	frontend_free_node_data(search_data, num_nodes);
	return search_2;
}