struct packet {
	char priority;
	char type;
	uint32_t sequence;
	uint32_t length;
	uint8_t  *payload;
	struct sockaddr_in source;
	struct sockaddr_in destination;
	/* "extra" info that is never put on a stream: */
	void * info;
	char *dot_addr;
};


struct packet_q_wrapper {
	struct packet *packet;
	struct packet_q_wrapper *next;
	struct packet_q_wrapper *prev;
	/* add extra info here: */
	double time; 
	int reset_count;
};

struct packet_q {
	/*struct packet *first;
	struct packet *last;*/
	struct packet_q_wrapper *w_first;
	struct packet_q_wrapper *w_last;
	struct packet_q_wrapper *w_iter_current;
	struct packet_q_wrapper *w_iter_next;
	struct packet *current;
	double current_time;
	int current_resets;
	int length;
};

void packet_q_new(struct packet_q* packet_q);
void packet_q_enqueue(struct packet_q* packet_q, struct packet* packet);

/* side effect of add_by_sequence: the iterator is reset */
void packet_q_add_by_sequence(struct packet_q* packet_q, struct packet *packet); 

/*void packet_q_dequeue(struct packet_q* packet_q, struct packet* packet);*/
void packet_q_reset_iter(struct packet_q* packet_q);
void packet_q_remove_current(struct packet_q* packet_q);
struct packet* packet_q_next(struct packet_q* packet_q);


int Socket(int domain, int type, int protocol);
int Bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen);
int Sendto(int s, void *buf, size_t len, int flags, 
		struct sockaddr *to, socklen_t tolen);
ssize_t Recvfrom(int s, void *buf, size_t len, int flags,
				struct sockaddr *from, socklen_t *fromlen);
FILE *Fopen(char *path, char *mode);
ssize_t Write(int fd, const void *buf, size_t count);

double get_time();

void error(char *message);
uint8_t* packet_to_buffer(struct packet *packet, unsigned int *packet_size);
struct packet* buffer_to_packet(uint8_t *);

void packet_send(int sockfd, struct packet* packet);

struct packet* packet_receive(int sockfd);

void print_packet(struct packet* packet);
void print_sockaddr(struct sockaddr_in* a);


unsigned int options_parse_port();
void str_to_sockaddr_in(struct sockaddr_in *addr, const char *s);


uint8_t* packet_to_buffer(struct packet *packet, unsigned int *packet_size);
struct packet* buffer_to_packet(uint8_t *);
/*(
**
void host_q_add_by_sequence(struct host_q* host_q, struct hostinfo* hostinfo){
	host_q__check("add_by_sequence", host_q, 0);
	struct host_q_wrapper *p_wrapper = (void *)
		malloc(sizeof(struct host_q_wrapper));
	struct hostinfo *other_hostinfo = NULL;
	p_wrapper->hostinfo = hostinfo;
	p_wrapper->time = get_time();
	p_wrapper->reset_count = 1;
	host_q_reset_iter(host_q);
	do {
		if(other_hostinfo && other_hostinfo->sequence == hostinfo->sequence) return;
		if(!host_q->w_iter_next || host_q->w_iter_next->hostinfo->sequence
				> hostinfo->sequence) break;
	} while((other_hostinfo = host_q_next(host_q)));

	host_q->length++;
	
	

	p_wrapper->prev = host_q->w_iter_current;
	p_wrapper->next = host_q->w_iter_next;
	if (p_wrapper->prev) 
		p_wrapper->prev->next = p_wrapper; 
	if(p_wrapper->next)
		p_wrapper->next->prev = p_wrapper; 
	if(host_q->w_first == p_wrapper->next) 
		host_q->w_first = p_wrapper;
	if(host_q->w_last == p_wrapper->prev) 
		host_q->w_last = p_wrapper;
}
*/


int packet_q_utest(){
	struct packet original_packet[OKAY_TEST_COUNT];
	struct packet *next;
	struct packet other_packet;
	int i;
	int bad_sequence_number = 13;
	/* make a queue */
	struct packet_q q;
	packet_q_new(&q);
	/* make a bunch of pakcets... */
	i = 0;
	while(i < OKAY_TEST_COUNT){
		original_packet[i].priority = 1; 
		original_packet[i].type = 'R';
		original_packet[i].sequence = i;
		original_packet[i].length = 512 + i;
		original_packet[i].payload = malloc(original_packet->length);
		original_packet[i].source.sin_addr.s_addr = 0xFEE1900D;
		original_packet[i].source.sin_port = 1337 + i;
		original_packet[i].destination.sin_addr.s_addr = 0x900DFEE1;
		original_packet[i].destination.sin_port = 6969 + i;
		i++;
	}
	if(q.length != 0){
		printf("packet_q: length should be zero.");
		return 0;
	}
	packet_q_reset_iter(&q);
	if(packet_q_next(&q) != NULL){
		printf("packet_q: next should start as null for empty list.");
		return 0;
	}
	/* add all the packets to the queue */
	i = 0;
	while(i < OKAY_TEST_COUNT){
		packet_q_enqueue(&q, &original_packet[i]);
		i++;
	}
	if(q.length != OKAY_TEST_COUNT){
		printf("packet_q: length incorrect.");
		return 0;
	}

	/* check looping and that the enqueueing was successful */
	i = 0;
	packet_q_reset_iter(&q);
	while(i < OKAY_TEST_COUNT){
		next = packet_q_next(&q);
		if(next == NULL){
			printf("packet_q: next is null before end of list.");
			return 0;
		}
		if(original_packet[i].sequence != next->sequence){
			printf("packet_q: wrong packet, sequence numbers do not match up.");
			return 0;
		}
		i++;
	}
	next = packet_q_next(&q);
	if(next != NULL){
		printf("packet_q: next should be null.");
		return 0;
	}
	/* remove a packet with sequence number 13 */
	i = 0;
	packet_q_reset_iter(&q);
	while(i < OKAY_TEST_COUNT){
		next = packet_q_next(&q);
		if(next == NULL){
			printf("packet_q: next is null before end of list. (2)");
			return 0;
		}
		if(original_packet[i].sequence != next->sequence){
			printf("packet_q: wrong packet, sequence numbers do not match up. (2)");
			return 0;
		}
		if(next->sequence == bad_sequence_number){
			packet_q_remove_current(&q);
		}
		i++;
	}
	next = packet_q_next(&q);
	if(next != NULL){
		printf("packet_q: next should be null. (2)");
		return 0;
	}
	/* makes sure that it is removed */
	if(q.length != OKAY_TEST_COUNT-1){
		printf("packet_q: remove failed, length incorrect.(3)");
		return 0;
	}
	i = 0;
	packet_q_reset_iter(&q);
	while(i < OKAY_TEST_COUNT-1){
		next = packet_q_next(&q);
		if(next == NULL){
			printf("packet_q: next is null before end of list. (3)");
			return 0;
		}
		if(next->sequence == bad_sequence_number){
			printf("packet_q: sequence number not removed! (3)"); 
			return 0;
		}
		i++;
	}
	next = packet_q_next(&q);
	if(next != NULL){
		printf("packet_q: next should be null. (3)");
		return 0;
	}
	/* enqueues another */
	other_packet = original_packet[0];
	other_packet.sequence = 1337;
	packet_q_enqueue(&q, &other_packet);
	if(q.length != OKAY_TEST_COUNT){
		printf("packet_q: enqueue failed, length incorrect. (4)");
		return 0;
	}
	packet_q_reset_iter(&q);
	next = packet_q_next(&q);
	if(next == NULL){
		printf("packet_q: enqueue failed, null. (3)");
		return 0;
	}
	/* test normal iteration method, and that current time is as expected */
	struct packet* packet;
	packet_q_reset_iter(&q);
	i = 0;
	double last_current_time = 0;
	while((packet = packet_q_next(&q))){
		if(i==OKAY_TEST_COUNT && next->sequence != other_packet.sequence){
			printf("packet_q: enqueue failed, sequence not match: %i!=%i (4)",
					next->sequence, other_packet.sequence);
			return 0;
		}
		if(i++>OKAY_TEST_COUNT) {
			printf("packet_q: next failed to work normally. (4.5)");
			return 0;
		}
		if(last_current_time > q.current_time){
			printf("packet_q: current time went up!? %lf>%lf (4.5)", 
					last_current_time, q.current_time);
			return 0;
		}
		last_current_time = q.current_time;
	}
	/* remove them all */
	i = 0;
	packet_q_reset_iter(&q);
	while(i < OKAY_TEST_COUNT){
		next = packet_q_next(&q);
		if(next == NULL){
			printf("packet_q: next is null before end of list. (5)");
			return 0;
		}
		if(q.length != OKAY_TEST_COUNT - i){
			printf("packet_q: length does not match. (5)");
			return 0;
		}
		packet_q_remove_current(&q);
		i++;
	}
	next = packet_q_next(&q);
	if(next != NULL){
		printf("packet_q: next should be null. (5)");
		return 0;
	}
	if(q.length != 0){
		printf("packet_q: length should be zero. (5)");
		return 0;
	}
	packet_q_reset_iter(&q);
	if(packet_q_next(&q) != NULL){
		printf("packet_q: next should start as null for empty list. (5)");
		return 0;
	}
	/* NOW WE TEST the sequence number thing */
	/* adds them all again in a arbitrary order */ 
	packet_q_add_by_sequence(&q, &original_packet[10]);
	packet_q_add_by_sequence(&q, &original_packet[3]);
	packet_q_add_by_sequence(&q, &original_packet[1]);
	packet_q_add_by_sequence(&q, &original_packet[4]);
	packet_q_add_by_sequence(&q, &original_packet[2]);
	packet_q_add_by_sequence(&q, &original_packet[6]);
	packet_q_add_by_sequence(&q, &original_packet[9]);
	packet_q_add_by_sequence(&q, &original_packet[7]);
	packet_q_add_by_sequence(&q, &original_packet[5]);
	packet_q_add_by_sequence(&q, &original_packet[4]);
	packet_q_add_by_sequence(&q, &original_packet[0]);
	packet_q_add_by_sequence(&q, &original_packet[2]);
	packet_q_add_by_sequence(&q, &original_packet[12]);
	packet_q_add_by_sequence(&q, &original_packet[11]);
	packet_q_add_by_sequence(&q, &original_packet[15]);
	packet_q_add_by_sequence(&q, &original_packet[13]);
	packet_q_add_by_sequence(&q, &original_packet[12]);
	packet_q_add_by_sequence(&q, &original_packet[14]);
	packet_q_add_by_sequence(&q, &original_packet[15]);
	packet_q_add_by_sequence(&q, &original_packet[13]);
	packet_q_add_by_sequence(&q, &original_packet[13]);
	packet_q_add_by_sequence(&q, &original_packet[13]);
	packet_q_add_by_sequence(&q, &original_packet[13]);
	packet_q_add_by_sequence(&q, &original_packet[13]);
	packet_q_add_by_sequence(&q, &original_packet[13]);
	packet_q_add_by_sequence(&q, &original_packet[13]);
	packet_q_add_by_sequence(&q, &original_packet[13]);
	packet_q_add_by_sequence(&q, &original_packet[12]);
	packet_q_add_by_sequence(&q, &original_packet[8]);
	packet_q_add_by_sequence(&q, &original_packet[1]);
	packet_q_add_by_sequence(&q, &original_packet[1]);
	i = 0;
	packet_q_reset_iter(&q);
	while(i < OKAY_TEST_COUNT){
		next = packet_q_next(&q);
		if(next == NULL){
			printf("packet_q: next is null before end of list. (5)");
			return 0;
		}
		if(original_packet[i].sequence != next->sequence){
			printf("packet_q: does not amthch. (5)");
			return 0;
		}
		i++;
	}
	next = packet_q_next(&q);
	if(next != NULL){
		printf("packet_q: next is NOT null at end of list. (5)");
		return 0;
	}
	/* test normal iteration method, and that current time is as expected */
	packet_q_reset_iter(&q);
	i = 0;
	int last_seq = -100;
	while((packet = packet_q_next(&q))){
		if(i==OKAY_TEST_COUNT && next->sequence != other_packet.sequence){
			printf("packet_q: enqueue failed, sequence not match: %i!=%i (6)",
					next->sequence, other_packet.sequence);
			return 0;
		}
		if(i++>OKAY_TEST_COUNT) {
			printf("packet_q: next failed to work normally. (6)");
			return 0;
		}
		//fprintf(stderr, "%i,", packet->sequence);
		/*
		if(last_seq> packet->sequence){
			printf("packet_q: current seqy went up!? %i>%i (6)", 
					last_seq, packet->sequence);
			return 0;
		}*/
		last_seq = packet->sequence;
	}

	return 1;
}

/*
int current_host(){
	char dot_dec[32];
	gethostname(dot_dec, 32);
	dot_dec[31] = 0;
	printf("This should print out the current host: '%s'\n", dot_dec);
}
*/


/********************************************************************8******/
/******* OLDER CODE, that may be useful, or it may not, we'll see **********/
/********************************************************************8******/

/* 
** FORMAT:
**    --------------------------------------------------------------
**   |    8 bit     |   32 bit    |    32 bit   |   variable length |
**   | packet type  |   sequence  |    length   |      payload      |
**    --------------------------------------------------------------
**
*/
uint8_t* packet_to_buffer_old(struct packet *packet, unsigned int *packet_size){
	uint8_t  *buffer;
	uint8_t *buffer_start;
	*packet_size = (HEADER_SIZE + packet->length) * sizeof(uint8_t);
	buffer_start = buffer = malloc(*packet_size);
	/* Insert packet type */
	*buffer = packet->type;
	buffer += PACKET_TYPE_SIZE;
	/* Insert 32 bit sequence */
	num_to_buffer32(buffer, htonl(packet->sequence));
	buffer += PACKET_SEQUENCE_SIZE;
	/* Insert 32 bit length   */
	num_to_buffer32(buffer, htonl(packet->length));
	buffer += PACKET_LENGTH_SIZE;
	/* Insert variable length payload */
	(void) memcpy(buffer, packet->payload, packet->length);
	return buffer_start;
}

struct packet* buffer_to_packet_old(uint8_t *buffer){
	struct packet *packet = malloc(sizeof(struct packet));
	/* Get packet type */
	packet->type = (char) *buffer;
	buffer += PACKET_TYPE_SIZE;
	/* Extract 32 bit sequence */
	packet->sequence = ntohl(buffer_to_num32(buffer));
	buffer += PACKET_SEQUENCE_SIZE;
	/* Extract 32 bit length   */
	packet->length   = ntohl(buffer_to_num32(buffer));
	buffer += PACKET_LENGTH_SIZE;
	/* Extract variable length payload */
	packet->payload = malloc(packet->length * sizeof(uint8_t));
	(void) memcpy(packet->payload, buffer, packet->length);
	return packet;
}



