#include <QCoreApplication>
#include <QStringList>
#include <iostream>
#include <sysexits.h>
#include "qcommandlineparser.h"
#include "mainclass.h"
#include "gpiomanager.h"
#include "randommanager.h"

MainClass::MainClass(QObject *parent)
    : QObject(parent)
    , m_input(nullptr)
    , m_device(Gpio)
    , m_address(QHostAddress::Any)
    , m_port(39415)
{
}

void MainClass::main()
{
    getOpts();

    InputManager* input = nullptr;
    if (m_device == Gpio)
        input = new GpioManager(this);
    else if (m_device == Random)
        input = new RandomManager(this);
    if (!input->init(m_channels))
    {
        std::cerr << "Failed to initialize device" << std::endl;
        exit(1);
        return;
    }

    auto server = new ServerManager(this);
    if (!server->init(m_address, m_port))
    {
        std::cerr << "Failed to bind socket" << std::endl;
        exit(2);
        return;
    }

    m_input = new InputBusiness(input, m_channels, server);
    m_input->readAndSend();
}

void MainClass::getOpts()
{
    QCommandLineParser parser;
    parser.setApplicationDescription("Server for GPIO monitoring");
    parser.addHelpOption();
    parser.addVersionOption();

    QCommandLineOption device((QStringList() << "d" << "device"), "device to use [gpio|rand]", "DEVICE", "gpio");
    parser.addOption(device);
    QCommandLineOption channel((QStringList() << "c" << "channel"), "channel to monitor", "CHANNEL");
    parser.addOption(channel);
    QCommandLineOption address((QStringList() << "a" << "address"), "address to bind socket", "ADDRESS", m_address.toString());
    parser.addOption(address);
    QCommandLineOption port((QStringList() << "p" << "port"), "port to bind socket [1-65535]", "PORT", QString::number(m_port));
    parser.addOption(port);

    parser.process(*qApp);

    auto dev = parser.value(device);
    if (dev == "gpio")
        m_device = Gpio;
    else if (dev == "rand" || dev == "random")
        m_device = Random;
    else
    {
        std::cerr << "Invalid device" << std::endl;
        parser.showHelp(EX_USAGE);
    }

    foreach (auto channel, parser.values(channel))
        m_channels.append(channel);
    if (m_channels.empty())
    {
        std::cerr << "At least one channel is required" << std::endl;
        parser.showHelp(EX_USAGE);
    }

    m_address = parser.value(address);
    if (m_address.isNull())
    {
        std::cerr << "Invalid address" << std::endl;
        parser.showHelp(EX_USAGE);
    }

    bool ok = false;
    m_port = parser.value(port).toInt(&ok);
    if (!ok || m_port <= 0 || m_port > 653535)
    {
        std::cerr << "Invalid port" << std::endl;
        parser.showHelp(EX_USAGE);
    }
}