#include "stdhead.h"
#include "parse.h"
#include "clilib.h"

void read_config_file (char **config_buff, char *file_name)
{
    int fd, n, size = 0;
    
    if ((fd = open (file_name, O_RDONLY)) == -1)
    {
	printf ("Error opening file %s.\n", file_name);
	write_to_log ("Error opening configuration file.", 1);
	exit (0);
    }
    
    write_to_log ("Reading configuration file.", 1);
    (*config_buff) = (char *) realloc (*config_buff, 1);
    size = 1;

    while (read (fd, &(*config_buff)[size - 1], 1) > 0)
    {
	size++;
	*config_buff = (char *) realloc (*config_buff, size);
    }
    (*config_buff)[size - 1] = '\0';

    close (fd);
}
    
void skip_whitespace (char **curr_ptr)
{
    while ((**curr_ptr == ' ') || (**curr_ptr == '\t') || (**curr_ptr == '\r') || (**curr_ptr == '\n'))
	(*curr_ptr)++;
}

int move_across_substring (char **curr_ptr, char *substring)
{
    *curr_ptr = strstr (*curr_ptr, substring);
    if (*curr_ptr)
	*curr_ptr += strlen (substring);
    else
	return 0;
    return 1;
}

int Move_across_substring (char **curr_ptr, char *substring)
{
    *curr_ptr = strstr (*curr_ptr, substring);
    if (*curr_ptr)
	*curr_ptr += strlen (substring);
    else
    {
	printf ("Configuration file format is incorrect.\n");
	exit (1);
    }
    return 1;
}

void read_token (char **token, char **curr_ptr)
{
    char *p;
    int n = 0;
    
    if (*token)
	*token = (char *) realloc (*token, 0);
    
    while ((**curr_ptr != ' ') && (**curr_ptr != '\t') && (**curr_ptr != '\r') && (**curr_ptr != '\n'))
    {
	n++;
	*token = (char *) realloc (*token, n);
	p = *token + (n - 1);
	*p = **curr_ptr;
	(*curr_ptr)++;
    }

    n++;
    *token = (char *) realloc (*token, n);
    p = *token + (n - 1);
    *p = '\0';
}

struct interface * get_interface_details (char *interface_name)
{
    struct interface *interface_details;
    char *config_buff = 0, *curr_ptr = 0, *token = 0, *start = 0;
    u_int8_t temp[2];
    int found_interface_flag = 0, i, count = 0;
    int br=0; 
    interface_details = (struct interface *) malloc (sizeof (struct interface));
    read_config_file (&config_buff, DEFAULT_SOLICIT_CONFIG_FILE);
    curr_ptr = config_buff;
    
    while (!found_interface_flag)
    {
	if (!move_across_substring (&curr_ptr, "interface"))
	    return NULL;
	    
	skip_whitespace (&curr_ptr);
	read_token (&token, &curr_ptr);
	
	if (!strcmp (token, interface_name))
	    found_interface_flag = 1;
    }
    
    Move_across_substring (&curr_ptr, "{");    
    Move_across_substring (&curr_ptr, "duid_type");
    skip_whitespace (&curr_ptr);
    read_token (&token, &curr_ptr);
    interface_details -> duid_type = atoi (token);
    Move_across_substring (&curr_ptr, "{");    
    start = curr_ptr;
    
    if (interface_details -> duid_type == 1 || interface_details -> duid_type == 3)
    {
	curr_ptr = start;
	Move_across_substring (&curr_ptr, "hardware_type");
	skip_whitespace (&curr_ptr);
	read_token (&token, &curr_ptr);
	interface_details -> haddr_type = atoi (token);
    
        curr_ptr = start;
        Move_across_substring (&curr_ptr, "hardware_len");
        skip_whitespace (&curr_ptr);
        read_token (&token, &curr_ptr);
        interface_details -> haddr_len = atoi (token);

        curr_ptr = start;
        Move_across_substring (&curr_ptr, "hardware_addr");
        skip_whitespace (&curr_ptr);
        read_token (&token, &curr_ptr);
        interface_details -> haddr = (char *) malloc (interface_details -> haddr_len * sizeof (char));
        for (i = 0; i < 3 * interface_details -> haddr_len - 1; i += 3)
        {
	    temp[0] = convert_character_to_hex (token[i]);
	    temp[1] = convert_character_to_hex (token[i + 1]);
	    interface_details -> haddr[count++] = (temp[0] << 4) | temp[1];
	}
    }

    printf("\nmac:");
    for(br=0;br<6;br++){
        printf("%x ", interface_details -> haddr[br]);
    }
    
    if (interface_details -> duid_type == 1)
    {
	curr_ptr = start;
	Move_across_substring (&curr_ptr, "time");
	skip_whitespace (&curr_ptr);
	read_token (&token, &curr_ptr);
	interface_details -> time = atoi (token);
    }
    
    if (interface_details -> duid_type == 2)
    {
	curr_ptr = start;
	Move_across_substring (&curr_ptr, "ident_len");
	skip_whitespace (&curr_ptr);
	read_token (&token, &curr_ptr);
	interface_details -> identifier_length = atoi (token);

	curr_ptr = start;
	Move_across_substring (&curr_ptr, "identifier");
	skip_whitespace (&curr_ptr);
	read_token (&token, &curr_ptr);
	interface_details -> identifier = (u_int8_t *) malloc (interface_details -> identifier_length * sizeof (u_int8_t));
	count = 0;
	for (i = 0; i < strlen (token); i += 2)
	{
	    temp[0] = convert_character_to_hex (token[i]);
	    temp[1] = convert_character_to_hex (token[i + 1]);
	    interface_details -> identifier[count++] = (temp[0] << 4) | temp[1];
	}

	curr_ptr = start;
	Move_across_substring (&curr_ptr, "domain_name");
	skip_whitespace (&curr_ptr);
	read_token (&token, &curr_ptr);
	interface_details -> domain_name_len = strlen (token);
	interface_details -> domain_name = (char *) malloc (strlen (token) * sizeof (char));
	for (i = 0; i < strlen (token); i++)
	    interface_details -> domain_name[i] = token[i];
    }
    
    Move_across_substring (&curr_ptr, "}");
    curr_ptr = start;
    Move_across_substring (&curr_ptr, "link_local_addr");
    skip_whitespace (&curr_ptr);
    read_token (&token, &curr_ptr);
    interface_details -> link_local_addr = (struct in6_addr *) malloc (sizeof (struct in6_addr));
    inet_pton (AF_INET6, token, interface_details -> link_local_addr);
    
    curr_ptr = start;
    if (!move_across_substring (&curr_ptr, "preferred_ipv6_address"))
	interface_details -> pref_ipv6_addr = NULL;
    else
    {
	skip_whitespace (&curr_ptr);
	read_token (&token, &curr_ptr);
	interface_details -> pref_ipv6_addr = (struct in6_addr *) malloc (sizeof (struct in6_addr));
        inet_pton (AF_INET6, token, interface_details -> pref_ipv6_addr);
    }
    
    curr_ptr = start;
    if (!move_across_substring (&curr_ptr, "preferred_lifetime"))
	interface_details -> pref_lifetime = 0;
    else
    {
	skip_whitespace (&curr_ptr);
	read_token (&token, &curr_ptr);
	interface_details -> pref_lifetime = atoi (token);
    }

    curr_ptr = start;
    if (!move_across_substring (&curr_ptr, "valid_lifetime"))
	interface_details -> valid_lifetime = 0;
    else
    {
	skip_whitespace (&curr_ptr);
	read_token (&token, &curr_ptr);
	interface_details -> valid_lifetime = atoi (token);
    }
    
    move_across_substring (&curr_ptr, "}");
    return interface_details;
}

void print_interface_details (struct interface *interface_details)
{
    char name[64];
    int i;
    
    printf ("Interface details\n");
    
    printf ("DUID Type = %d\n", interface_details -> duid_type);
    
    if (interface_details -> duid_type == 1 || interface_details -> duid_type == 3)
    {
	printf ("Hardware Type = %d\n", interface_details -> haddr_type);
	printf ("Hardware Length = %d\n", interface_details -> haddr_len);
	printf ("Hardware Address = ");
	for (i = 0; i < interface_details -> haddr_len; i++)
	{
	    printf ("%x", interface_details -> haddr[i]);
	
    	    if (i == (interface_details -> haddr_len - 1))
		printf ("\n");
	    else
		printf (":");
	}
    }
    
    if (interface_details -> duid_type == 1)
	printf ("Time = %d\n", interface_details -> time);

    if (interface_details -> duid_type == 2)
    {
	printf ("Identifier length = %d\n", interface_details -> identifier_length);
	printf ("Identifier = ");
        for (i = 0; i < interface_details -> identifier_length; i++)
	    printf ("%x", interface_details -> identifier[i]);
	printf ("\nDomain name = ");
	for (i = 0; i < interface_details -> domain_name_len; i++)
	    printf ("%c", interface_details -> domain_name[i]);
	printf ("\n");
    }
    
    printf ("Link local address of user = %s\n", inet_ntop (AF_INET6, (char *) interface_details -> link_local_addr, name, 64));
    if (interface_details -> pref_ipv6_addr)
	printf ("Preferred IPv6 address of user = %s\n", inet_ntop (AF_INET6, (char *) interface_details -> pref_ipv6_addr, name, 64));
    if (interface_details -> pref_lifetime)
	printf ("Preferred lifetime = %d\n", interface_details -> pref_lifetime);
    if (interface_details -> valid_lifetime)
	printf ("Valid lifetime = %d\n", interface_details -> valid_lifetime);
}
