/* dracal-sensgate-scan: Find SensGate devices on all network interfaces via UDP broadcast.
 *
 * Copyright (C) 2020-2024  Dracal Technologies Inc.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 3
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <getopt.h>

#include "discovery.h"
#include "str_helper.h"
#include "usbtenki_version.h"


#define DEFAULT_INTERVAL 100
#define DEFAULT_COUNT 50


#define VERSION_STRING "dracal-sensgate-scan " USBTENKI_VERSION

static const char VERSION_TEXT[] =
    "\n"
    VERSION_STRING "\n"
    "Copyright (C) 2020-2025 Dracal Technologies Inc.\n"
    "\n"
    "This software is free software: you can redistribute it and/or modify it under the\n"
    "terms of the GNU General Public License as published by the Free Software Foundation,\n"
    "either version 3 of the License, or (at your option) any later version.\n"
    "\n"
    "This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;\n"
    "without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
    "See the GNU General Public License for more details.\n"
    "\n"
;

static const char HELP_TEXT[] =
    "\n"
    "Usage: dracal-sensgate-scan [OPTION...]\n"
    "Find SensGate devices on all network interfaces via UDP broadcast.\n"
    "\n"
    "It is recommended to invoke this program without arguments in order to use default options.\n"
    "Sending too many broadcast packets may flood your network and cause unwanted effects.\n"
    "\n"
    "  -h, --help        Print this help screen\n"
    "  -v, --version     Print the version and copyright notice\n"
    "  -p, --port=N      Broadcast to port number (default: " STR(TENKINET_SERVER_PORT) ")\n"
    "  -I, --interval=N  Set the broadcast interval in milliseconds (default: " STR(DEFAULT_INTERVAL) ")\n"
    "  -c, --count=N     Set the number of broadcast packets to send (default: " STR(DEFAULT_COUNT) ")\n"
    "\n"
;

static const struct option OPTIONS[] = {

    { "help", no_argument, NULL, 'h' },
    { "version", no_argument, NULL, 'v' },
    { "port", required_argument, NULL, 'p' },
    { "interval", required_argument, NULL, 'I' },
    { "count", required_argument, NULL, 'c' },
    { NULL, 0, NULL, 0 }

};

static uint16_t port = TENKINET_SERVER_PORT;
static unsigned int interval = DEFAULT_INTERVAL;
static unsigned int count = DEFAULT_COUNT;


static void print_server_info(TenkinetServerInfo *info) {

    printf("%s:%s\t%s, %s, v%u.%u.%u [Devices: %u]\n",
        info->address_str,
        info->port_str,
        info->name_str,
        info->serial_number,
        info->version.major,
        info->version.minor,
        info->version.revision,
        info->device_count
    );

}

int main(int argc, char *argv[]) {

    int c;

    while ((c = getopt_long(argc, argv, "hvp:I:c:", OPTIONS, NULL)) != -1) {
        switch (c) {
            case 'h':
                fputs(HELP_TEXT, stdout);
                return 0;
            case 'v':
                fputs(VERSION_TEXT, stdout);
                return 0;
            case 'p':
                port = atoi(optarg);
                break;
            case 'I':
                interval = atoi(optarg);
                if (interval == 0) { interval = 1; }
                break;
            case 'c':
                count = atoi(optarg);
                if (count == 0) { count = 1; }
                break;
            default:
                fprintf(stderr, "Invalid option %c\n", c);
                return 1;
        }
    }

    double seconds = ((double)(count * interval)) / 1000.0;

    if (tenkinet_discovery_init(port, print_server_info)) {
        fprintf(stderr, "Cannot connect to network.\n");
        return 1;
    }

    fprintf(stderr, "Sending %u broadcast packets to port %hu at a %u ms interval (total duration: %.3f s)\n\n",
        count,
        port,
        interval,
        seconds
    );

    tenkinet_discovery_loop(interval, count);
    tenkinet_discovery_exit();

    return 0;

}
