/* tmname.cc
****************************************************************************************************************
****************************************************************************************************************

    Copyright (C) 2014, 2015. 2021 Askar Almatov

    This file is part of Trafficmeter.

    Trafficmeter 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.

    Trafficmeter 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 Trafficmeter. If not, see
    <http://www.gnu.org/licenses/>.
*/

#include <iostream>
#include <string>
#include <stdexcept>
#include <getopt.h>

#include "namequery.h"
#include "path.h"
#include "tmdefs.h"

using namespace iclass;
using namespace trafficmeter;

using std::cerr;
using std::cout;
using std::endl;
using std::invalid_argument;
using std::string;

enum class SortMode
{
    NONE,
    ASCENDING,
    DESCENDING
};

static const struct option  LONG_OPTIONS_[] =
{
    { "dsort",   required_argument, nullptr, 'S' },
    { "asort",   required_argument, nullptr, 's' },
    { "count",   no_argument,       nullptr, 'c' },
    { "version", no_argument,       nullptr, 'v' },
    { "help",    no_argument,       nullptr, 'h' },
    { nullptr,   0,                 nullptr,  0  }
};

/**************************************************************************************************************/
void
printRow( const NameQuery::Row& row )
{
    cout << row.ip.str() << "\t" << row.name << endl;
}

/**************************************************************************************************************/
int
main( int argc, char* argv[] )
{
    string      progName( Path(argv[0]).fileName() );
    NameQuery   query( Path::base + '/' + NAME_DB );
    SortMode    sortMode = SortMode::NONE;
    int         nRowsLimit;
    int         opt;

    while ( (opt = getopt_long(argc,argv,"S:s:cvh",LONG_OPTIONS_,nullptr)) != -1 )
    {
        switch ( opt )
        {
            case 'S':

                sortMode = SortMode::DESCENDING;
                nRowsLimit = atoi( optarg );
                break;

            case 's':

                sortMode = SortMode::ASCENDING;
                nRowsLimit = atoi( optarg );
                break;

            case 'c':

                cout << query.nFileRecords() << " records, " << query.fileSize() << " bytes\n";
                return EXIT_SUCCESS;

            case 'v':

                cout <<
                    "Trafficmeter Name browser version " << VERSION << " for " << SYSTEM_TYPE << "\n"
                    "For info, please visit http://www.trafficmeter.org\n";

                return EXIT_SUCCESS;

            case 'h':
            default:

                cout <<
                    progName << " is the utility to browse collected domain names\n"
                    "Usage: " << progName << " [options] [IP ...]\n"
                    "\tIP\t\t\tIP address or network: 'ddd.ddd.ddd.ddd[/mm]'\n"
                    "\t-S --dsort=<rows>\tSort rows descending by name size, print first <rows>\n"
                    "\t-s --asort=<rows>\tSort rows ascending by name size, print first <rows>\n"
                    "\t-c --count\t\tCount records in database\n"
                    "\t-v --version\t\tPrint version information\n"
                    "\t-h --help\t\tPrint help message\n";

                return EXIT_SUCCESS;
        }
    }

    if ( sortMode != SortMode::NONE && nRowsLimit <= 0 )
    {
        cerr << progName << ": incorrect argument of sort option\n";
        return EXIT_FAILURE;
    }

    argc -= optind;
    argv += optind;

    if ( argc < 1 )
    {
        cerr << progName << ": IP address/network must be specified\n";
        return EXIT_FAILURE;
    }

    try
    {
        while ( argc-- )
        {
            query.addNetwork( ipnet4t(*argv++) );
        }
    }
    catch ( invalid_argument )
    {
        cerr << progName << ": incorrect IP address or network\n";
        return EXIT_FAILURE;
    }

    if ( sortMode == SortMode::ASCENDING )
    {
        auto&&  rows = query.fetchSmall( nRowsLimit );

        for ( auto i = rows.begin(); i != rows.end() ; ++i )
        {
            printRow( *i );
        }
    }
    else if ( sortMode == SortMode::DESCENDING )
    {
        auto&&  rows = query.fetchLarge( nRowsLimit );

        for ( auto i = rows.rbegin(); i != rows.rend() ; ++i )
        {
            printRow( *i );
        }
    }
    else
    {
        while ( query.hasRows() )
        {
            printRow( query.getRow() );
        }
    }

    return EXIT_SUCCESS;
}
