#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/socket.h>
#include <linux/ax25.h>
#include <string.h>
#include "rspfax25.h"
#include "rspfheard.h"

#define MAX_INTERFACES 10

#define SSID_MASK 0x1E
#define REPEATED  0x80

struct heard_list {
    struct heard_list *next;
    ax25_address address;
    time_t timestamp;
    unsigned long bytes_received;
    unsigned short packets_received;
};

struct port_list {
    struct port_list *next;
    char *name;
    struct heard_list *heard;
};

static struct port_list *ports = NULL;

static struct port_list *
 lookup_port(char *port)
{
    struct port_list *tick;

    for (tick = ports; tick != NULL; tick = tick->next) {
	if (!strcmp(tick->name, port))
	    return tick;
    }
    return NULL;
}

static struct heard_list *
 lookup_heard_address(struct port_list *head, ax25_address address)
{
    struct heard_list *tick;

    if (head == NULL)
	return NULL;

    for (tick = head->heard; tick != NULL; tick = tick->next) {
	if (!memcmp(tick->address.ax25_call, address.ax25_call, 6) &&
	    ((int) (address.ax25_call[6]) & SSID_MASK) == ((int) (tick->address.ax25_call[6]) & SSID_MASK))
	    return tick;
    }
    return NULL;
}

void add_heard(char *port, ax25_address address,
	       int packet_length)
{
    struct port_list *pitem;
    struct port_list *ptick;
    struct heard_list *tick;
    struct heard_list *item;

    pitem = lookup_port(port);
    if (pitem == NULL) {
	pitem = (struct port_list *)
	    malloc(sizeof(struct port_list));

	pitem->name = strdup(port);
	pitem->heard = NULL;
	pitem->next = NULL;
	if (ports == NULL)
	    ports = pitem;
	else {
	    for (ptick = ports; ptick->next != NULL; ptick = ptick->next);
	    ptick->next = pitem;
	}
    }
    item = lookup_heard_address(pitem, address);
    if (item == NULL) {
	item = (struct heard_list *)
	    malloc(sizeof(struct heard_list));

	item->address = address;
	item->packets_received = 0;
	item->bytes_received = 0L;
	item->next = NULL;
	if (pitem->heard == NULL)
	    pitem->heard = item;
	else {
	    for (tick = pitem->heard; tick->next != NULL;
		 tick = tick->next);
	    tick->next = item;
	}
    }
    item->bytes_received += (unsigned long) packet_length;
    item->packets_received++;
    item->timestamp = time(NULL);
}

time_t get_lastheard(ax25_address dladdr, char *port)
{
    struct heard_list *item;

    item = lookup_heard_address(lookup_port(port), dladdr);
    if (item)
	return item->timestamp;
    else
	return 0L;
}

unsigned long get_rx_bytes(ax25_address dladdr, char *port)
{
    struct heard_list *item;

    item = lookup_heard_address(lookup_port(port), dladdr);
    if (item)
	return item->bytes_received;
    else
	return 0L;
}

unsigned short get_rx_pkts(ax25_address dladdr, char *port)
{
    struct heard_list *item;

    item = lookup_heard_address(lookup_port(port), dladdr);
    if (item)
	return item->packets_received;
    else
	return 0;
}

void display_heard(FILE * f, char *port)
{
    struct heard_list *tick;
    struct port_list *p;
    char tbuf[30];

    p = lookup_port(port);
    fprintf(f, "  Callsign         Packets        Bytes      Age  Last Heard\r\n");
    if (p != NULL) {
	for (tick = p->heard; tick != NULL; tick = tick->next) {
	    strftime(tbuf, 30, "%a %H:%M:%S", localtime(&(tick->timestamp)));
	    fprintf(f, "  %-15s %8d %12ld %8ld  %s\r\n", ax25_ntoa(&(tick->address)),
		    tick->packets_received, tick->bytes_received,
		    time(NULL) - tick->timestamp, tbuf);
	}

    }
}
