/* macaddress.cc
****************************************************************************************************************
****************************************************************************************************************

    Copyright (C) 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 <cstdio>
#include <stdexcept>

#include "macaddress.h"

using namespace trafficmeter;

using std::invalid_argument;
using std::string;

constexpr const char*   WHITESPACE_CHAR_    = " \t\f\v\r\a";
constexpr const char*   VALID_CHAR_         = ".-:0123456789ABCDEFabcdef";
constexpr const char*   COLON_FORMAT_       = "%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx%n";
constexpr const char*   HYPHEN_FORMAT_      = "%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx%n";
constexpr const char*   PERIOD_FORMAT_      = "%2hhx%2hhx.%2hhx%2hhx.%2hhx%2hhx%n";
constexpr const char*   SOLID_FORMAT_       = "%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%n";
constexpr const char*   PRINT_FORMAT_       = "%02x:%02x:%02x:%02x:%02x:%02x";

/**************************************************************************************************************/
MacAddress::MacAddress( string str )
{
    str.erase( str.find_last_not_of(WHITESPACE_CHAR_) + 1 ).erase( 0, str.find_first_not_of(WHITESPACE_CHAR_) );

    if ( str.find_first_not_of(VALID_CHAR_) != string::npos )
    {
        throw invalid_argument( "MacAddress::MacAddress( std::string ) invalid character" );
    }

    const char*     format = SOLID_FORMAT_;

    if ( str.size() == 17 && str[2] == ':' )
    {
        format = COLON_FORMAT_;
    }
    else if ( str.size() == 17 && str[2] == '-' )
    {
        format = HYPHEN_FORMAT_;
    }
    else if ( str.size() == 14 && str[4] == '.' )
    {
        format = PERIOD_FORMAT_;
    }
    else if ( str.size() != 12 )
    {
        throw invalid_argument( "MacAddress::MacAddress( std::string ) invalid length" );
    }

    int     nAssigns;
    int     scanEnd;

    nAssigns = sscanf( str.data(), format, address_, address_ + 1,
            address_ + 2, address_ + 3, address_ + 4, address_ + 5, &scanEnd );

    if ( nAssigns != 6 || scanEnd != str.size() )
    {
        throw invalid_argument( "MacAddress::MacAddress( std::string ) invalid format" );
    }
}

/**************************************************************************************************************/
string
MacAddress::str() const
{
    char    str[ 18 ];

    snprintf( str, sizeof(str), PRINT_FORMAT_,
            address_[0], address_[1], address_[2], address_[3], address_[4], address_[5] );

    return str;
}

