/* tmdump.cc
****************************************************************************************************************
****************************************************************************************************************

    Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2021, 2026 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 <cstdlib>
#include <iomanip>
#include <iostream>
#include <stdexcept>
#include <getopt.h>
#include <unistd.h>

#include "dag.h"
#include "dumpprocessor.h"
#include "iface.h"
#include "path.h"

using namespace iclass;
using namespace trafficmeter;

using std::cerr;
using std::cout;
using std::endl;
using std::exception;
using std::setw;
using std::string;

static const struct option  LONG_OPTIONS_[] =
{
    { "num",        required_argument, nullptr, 'n' },
    { "len",        required_argument, nullptr, 'l' },
    { "no-promisc", no_argument,       nullptr, 'P' },
    { "version",    no_argument,       nullptr, 'v' },
    { "help",       no_argument,       nullptr, 'h' },
    { nullptr,      0,                 nullptr,  0  }
};

/**************************************************************************************************************/
int
main( int argc, char* argv[] )
{
    string      progName( Path(argv[0]).fileName() );
    int         nPacketsPrint = DEFAULT_DUMP_PACKETS;
    int         nBytesPrint = DEFAULT_DUMP_BYTES;
    bool        isPromisc = true;
    int         opt;

    while ( (opt = getopt_long(argc,argv,"n:l:pvh",LONG_OPTIONS_,nullptr)) != -1 )
    {
        switch ( opt )
        {
            case 'n':

                nPacketsPrint = atoi( optarg );
                break;

            case 'l':

                nBytesPrint = atoi( optarg );
                break;

            case 'P':

                isPromisc = false;
                break;

            case 'v':

                cout <<
                    "Trafficmeter Dump 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 hexadecimal dump selected packets\n"
                    "Usage: " << progName << " [options] source [pattern ...]\n"
                    "\t-n --num=<packets>\tNumber of packets to print, default '" << DEFAULT_DUMP_PACKETS << "'\n"
                    "\t-l --len=<bytes>\tBytes of packet to print, default '" << DEFAULT_DUMP_BYTES << "'\n"
                    "\t-P --no-promisc\t\tDo not set interface to promiscuous mode\n"
                    "\t-v --version\t\tPrint version information\n"
                    "\t-h --help\t\tPrint help message\n"
                    "\t^12x08004\t\tInversion '^', offset 12(dec), delimiter 'x', fragment 08004(hex),\n"
                    "\t\t\t\tthis pattern means print only non-IPv4 packets\n";

                return EXIT_SUCCESS;
        }
    }

    argc -= optind;
    argv += optind;

    if ( nPacketsPrint <= 0 )
    {
        cerr << progName << "; incorrect number of packets\n";
        return EXIT_FAILURE;
    }

    if ( nBytesPrint <= 0 )
    {
        cerr << progName << "; incorrect number of bytes\n";
        return EXIT_FAILURE;
    }

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

    string      sourceName( argv[0] );
    Source*     source;

    try
    {
        if ( sourceName.find("dag") == 0 )
        {
            source = new Dag( sourceName );
        }
        else
        {
            source = new Iface( sourceName, isPromisc );
        }
    }
    catch ( exception& e )
    {
        cerr << "Cannot establish packet catcher on " << sourceName << " - " << e.what() << "\n";
        return EXIT_FAILURE;
    }

    DumpProcessor  dumpProcessor( source, nPacketsPrint, nBytesPrint );

    for ( int i = 1; i < argc; i++ )
    {
        try
        {
            dumpProcessor.addPattern( argv[i] );
        }
        catch ( exception& e )
        {
            cerr << progName << "; incorrect pattern " << argv[i] << " - " << e.what() << "\n";
            return EXIT_FAILURE;
        }
    }

    cout << "Source: " << source->name() << " - " << source->info() << "\n\n len  time             ";

    for ( int i = 0; i < nBytesPrint; i++ )
    {
        cout << setw(2) << i%10;
    }

    cout << endl;
    dumpProcessor.start();

    while ( !dumpProcessor.finished() )
    {
        usleep( 100000 );
    }

    dumpProcessor.stop();
    delete source;
    return EXIT_SUCCESS;
}

