/* statreport.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 "statreport.h"

using namespace iclass;
using namespace trafficmeter;

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

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

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

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

/**************************************************************************************************************/
void
StatReport::showHosts()
{
    shouldShowHosts_ = true;
}

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

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

    divisor_ = value;

    return true;
}

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

    minimalTraffic_ = value;

    return true;
}

/**************************************************************************************************************/
void
StatReport::printHeader() const
{
    if ( !shouldHideTime_ )
    {
        cout << setw(16) << "time";
    }
    else if ( !shouldShowVlans_ && !shouldShowHosts_ && !shouldShowFlows_ )
    {
        cout << "   ";
    }

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

    cout << "   ";

    if ( shouldShowHosts_ )
    {
        cout << setw(27) << left << "host" << 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
StatReport::printRow( const StatQuery::Key& stat, 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 != stat.group )
        {
            struct tm  timeComponents;

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

        cout << setw(16) << timeCacheString;
    }
    else if ( !shouldShowVlans_ && !shouldShowHosts_ && !shouldShowFlows_ )
    {
        cout << "   ";
    }

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

    cout << "   ";

    if ( shouldShowHosts_ )
    {
        cout << setw(27) << left << stat.ip.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
StatReport::printFooter( string message, const SummaryIo& summary ) const
{
    cout << setw(19 + shouldHideTime_*-16 + shouldShowVlans_*6 + shouldShowHosts_*27) << left << message << 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;
    }
}

