#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

#include <patty/ax25.h>
#include <patty/print.h>

static void usage(int argc, char **argv, const char *message, ...) {
    if (message) {
        va_list args;

        va_start(args, message);
        vfprintf(stderr, message, args);
         fprintf(stderr, "\n");
        va_end(args);
    }

    fprintf(stderr, "usage: %s [/dev/ttyXX|kiss.cap]\n", argv[0]);

    exit(1);
}

int main(int argc, char **argv) {
    patty_kiss_tnc *tnc;
    void *buf;
    int port;

    if (argc > 2) {
        usage(argc, argv, NULL);
    }

    tnc = (argc == 2)?
        patty_kiss_tnc_new(argv[1]):
        patty_kiss_tnc_new_fd(0);

    if (tnc == NULL) {
        perror("Unable to open TNC");

        goto error_kiss_tnc_open;
    }

    if ((buf = malloc(PATTY_KISS_BUFSZ)) == NULL) {
        perror("malloc()");

        goto error_malloc_buf;
    }

    while (1) {
        ssize_t len,
                decoded,
                offset = 0;

        patty_ax25_frame frame;

        if ((len = patty_kiss_tnc_recv(tnc, buf, PATTY_KISS_BUFSZ, &port)) < 0) {
            fprintf(stderr, "%s: %s: %s\n",
                argv[0], "patty_kiss_tnc_recv()", strerror(errno));

            goto error_kiss_tnc_recv;
        } else if (len == 0) {
            break;
        }

        if ((decoded = patty_ax25_frame_decode_address(&frame, buf, len)) < 0) {
            printf("Invalid frame address\n");

            goto error_ax25_frame_decode_address;
        } else {
            offset += decoded;
        }

        if ((decoded = patty_ax25_frame_decode_control(&frame, PATTY_AX25_FRAME_NORMAL, buf, offset, len)) < 0) {
            printf("Invalid frame control\n");

            goto error_ax25_frame_decode_control;
        } else {
            offset += decoded;
        }

        if (patty_print_frame_header(stdout, &frame) < 0) {
            fprintf(stderr, "%s: %s: %s\n",
                argv[0], "patty_print_frame_header()", strerror(errno));

            goto error_io;
        }

        if (frame.type == PATTY_AX25_FRAME_XID) {
            patty_ax25_params params;

            if (patty_ax25_frame_decode_xid(&params,
                                            buf,
                                            offset,
                                            len) < 0) {
                printf("Invalid XID parameters\n");

                goto error_ax25_frame_decode_xid;
            } else {
                if (patty_print_params(stdout, &params) < 0) {
                    goto error_io;
                }
            }
        }

error_ax25_frame_decode_xid:
error_ax25_frame_decode_control:
error_ax25_frame_decode_address:
        if (patty_print_hexdump(stdout, buf, len) < 0) {
            goto error_io;
        }

        if (fflush(stdout) < 0) {
            goto error_io;
        }
    }

    free(buf);

    patty_kiss_tnc_destroy(tnc);

    return 0;

error_io:
error_kiss_tnc_recv:
    free(buf);

error_malloc_buf:
    patty_kiss_tnc_destroy(tnc);

error_kiss_tnc_open:
    return 127;
}