/* flow2report.cc
****************************************************************************************************************
****************************************************************************************************************

    Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2020, 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 <ctime>
#include <iomanip>
#include <iostream>

#include "flow2report.h"

using namespace trafficmeter;

using std::cout;
using std::dec;
using std::endl;
using std::fixed;
using std::hex;
using std::left;
using std::right;
using std::setfill;
using std::setprecision;
using std::setw;
using std::string;

/**************************************************************************************************************/
Flow2Report::Flow2Report() :
    shouldHideTime_( false ),
    shouldShowVlans_( false ),
    shouldShowFlows_( false ),
    divisor_( 1.0 ),
    minimalTraffic_( 0.0 )
{
}

/**************************************************************************************************************/
void
Flow2Report::hideTime()
{
    shouldHideTime_ = true;
}

/**************************************************************************************************************/
void
Flow2Report::showVlans()
{
    shouldShowVlans_ = true;
}

/**************************************************************************************************************/
void
Flow2Report::showFlows()
{
    shouldShowFlows_ = true;
}

/**************************************************************************************************************/
bool
Flow2Report::setDivisor( double value )
{
    if ( divisor_ != 1.0 || value <= 0.0 )
    {
        return false;
    }

    divisor_ = value;

    return true;
}

/**************************************************************************************************************/
bool
Flow2Report::setMinimalTraffic( double value )
{
    if ( value <= 0.0 )
    {
        return false;
    }

    minimalTraffic_ = value;

    return true;
}

/**************************************************************************************************************/
void
Flow2Report::printHeader() const
{
    if ( !shouldHideTime_ )
    {
        cout << setw(16) << "time";
    }

    if ( shouldShowVlans_ )
    {
        cout << setw(6) << "vlan";
    }

    cout << setw(7) << "etype" << "   " << left << setw(18) << "host" << "  " << setw(18) << "peer" << right;

    if ( shouldShowFlows_ )
    {
        cout << setw(12) << "i.flows" << setw(12) << "i.packets";
    }

    cout << setw(15) << "i.traffic";

    if ( shouldShowFlows_ )
    {
        cout << setw(12) << "o.flows" << setw(12) << "o.packets";
    }

    cout << setw(15) << "o.traffic" << endl;
}

/**************************************************************************************************************/
bool
Flow2Report::printRow( const Flow2Query::Key& flow, const SummaryIo& summary ) const
{
    uintmax_t   minimalBytes = static_cast<uintmax_t>( minimalTraffic_ * divisor_ );

    if ( minimalBytes && summary.nBytesIn() < minimalBytes && summary.nBytesOut() < minimalBytes )
    {
        return false;
    }

    if ( !shouldHideTime_ )
    {
        static time_t  timeCache = 0;
        static char    timeCacheString[ 32 ];

        if ( timeCache != flow.group )
        {
            struct tm  timeComponents;

            timeCache = flow.group;
            localtime_r( &timeCache, &timeComponents );
            strftime( timeCacheString, sizeof(timeCacheString), "%FT%H:%M", &timeComponents );
        }

        cout << setw(16) << timeCacheString;
    }

    if ( shouldShowVlans_ )
    {
        cout << setw(6) << flow.vlan;
    }

    cout
        << "   " << setw(4) << setfill('0') << hex << flow.etype << dec << setfill(' ') << "   "
        << left << setw(18) << flow.host.str() << "  " << setw(18) << flow.peer.str() << right;

    if ( shouldShowFlows_ )
    {
        cout << setw(12) << summary.nFlowsIn() << setw(12) << summary.nPacketsIn();
    }

    cout << setw(15);

    if ( divisor_ == 1.0 )
    {
        cout << summary.nBytesIn();
    }
    else
    {
        cout << fixed << setprecision(2) << summary.nBytesIn() / divisor_;
    }

    if ( shouldShowFlows_ )
    {
        cout << setw(12) << summary.nFlowsOut() << setw(12) << summary.nPacketsOut();
    }

    cout << setw(15);

    if ( divisor_ == 1.0 )
    {
        cout << summary.nBytesOut() << endl;
    }
    else
    {
        cout << fixed << setprecision(2) << summary.nBytesOut() / divisor_ << endl;
    }

    return true;
}

/**************************************************************************************************************/
void
Flow2Report::printFooter( string message, const SummaryIo& total ) const
{
    cout << setw(64 + shouldHideTime_*-16 + shouldShowVlans_*6) << left << message << right;

    if ( shouldShowFlows_ )
    {
        cout << setw(12) << total.nFlowsIn() << setw(12) << total.nPacketsIn();
    }

    cout << setw(15);

    if ( divisor_ == 1.0 )
    {
        cout << total.nBytesIn();
    }
    else
    {
        cout << fixed << setprecision(2) << total.nBytesIn() / divisor_;
    }

    if ( shouldShowFlows_ )
    {
        cout << setw(12) << total.nFlowsOut() << setw(12) << total.nPacketsOut();
    }

    cout << setw(15);

    if ( divisor_ == 1.0 )
    {
        cout << total.nBytesOut() << endl;
    }
    else
    {
        cout << fixed << setprecision(2) << total.nBytesOut() / divisor_ << endl;
    }
}

