/// QasTools: Desktop toolset for the Linux sound system ALSA.
/// \copyright See COPYING file.

#include "ctl_address.hpp"

namespace QSnd
{

Ctl_Address::Ctl_Address ( const char * addr_str_n )
{
  if ( addr_str_n != nullptr ) {
    set_addr_str ( QString ( addr_str_n ) );
  }
}

Ctl_Address::Ctl_Address ( const QString & addr_str_n )
{
  set_addr_str ( addr_str_n );
}

Ctl_Address::Ctl_Address ( const Ctl_Address & ctl_addr_n ) = default;

Ctl_Address::Ctl_Address ( Ctl_Address && ctl_addr_n ) = default;

Ctl_Address::~Ctl_Address () = default;

void
Ctl_Address::clear ()
{
  _addr_str.clear ();
  _ctl_name.clear ();
  _args.clear ();
}

void
Ctl_Address::set_ctl_name ( const QString & ctl_name )
{
  _ctl_name = ctl_name;
  update_addr_str ();
}

void
Ctl_Address::set_addr_str ( const QString & addr_str_n )
{
  clear ();

  if ( addr_str_n.isEmpty () ) {
    return;
  }

  int idx = addr_str_n.indexOf ( QChar ( ':' ) );
  if ( idx == 0 ) {
    // Invalid
    return;
  }
  if ( idx < 0 ) {
    // Simple name
    _ctl_name = addr_str_n;
    _addr_str = _ctl_name;
    return;
  }
  // Name with arguments
  {
    QString pstr = addr_str_n;
    _ctl_name = pstr.left ( idx );
    pstr = pstr.mid ( idx + 1 );

    QString arg_str;
    while ( !pstr.isEmpty () ) {
      idx = pstr.indexOf ( QChar ( ',' ) );
      if ( idx < 0 ) {
        arg_str = pstr;
        pstr.clear ();
      } else {
        arg_str = pstr.left ( idx );
        pstr = pstr.mid ( idx + 1 );
      }

      QSnd::Ctl_Address_Argument argm;

      idx = arg_str.indexOf ( QChar ( '=' ) );
      if ( idx < 0 ) {
        argm.set_value ( arg_str );
      } else {
        argm.set_name ( arg_str.left ( idx ) );
        argm.set_value ( arg_str.mid ( idx + 1 ) );
      }

      if ( !argm.value ().isEmpty () ) {
        _args.push_back ( std::move ( argm ) );
      }
    }
  }
  update_addr_str ();
}

void
Ctl_Address::append_arg ( const QSnd::Ctl_Address_Argument & arg_n )
{
  _args.push_back ( arg_n );
  update_addr_str ();
}

void
Ctl_Address::append_arg ( QSnd::Ctl_Address_Argument && arg_n )
{
  _args.push_back ( std::move ( arg_n ) );
  update_addr_str ();
}

bool
Ctl_Address::match ( const QSnd::Ctl_Address & ctl_addr_n ) const
{
  if ( _ctl_name != ctl_addr_n.ctl_name () ) {
    return false;
  }
  if ( num_args () != ctl_addr_n.num_args () ) {
    return false;
  }

  for ( std::size_t ii = 0; ii != num_args (); ++ii ) {
    const auto & arg1 = arg ( ii );
    const auto & arg2 = ctl_addr_n.arg ( ii );
    // Same value?
    if ( arg1.value () != arg2.value () ) {
      return false;
    }
    // Also same name?
    if ( !arg1.name ().isEmpty () && !arg2.name ().isEmpty () &&
         ( arg1.name () != arg2.name () ) ) {
      return false;
    }
  }

  return true;
}

QSnd::Ctl_Address &
Ctl_Address::operator= ( const QSnd::Ctl_Address & ctl_addr_n ) = default;

QSnd::Ctl_Address &
Ctl_Address::operator= ( QSnd::Ctl_Address && ctl_addr_n ) = default;

bool
Ctl_Address::operator== ( const Ctl_Address & ctl_addr_n ) const
{
  return ( _addr_str == ctl_addr_n._addr_str );
}

bool
Ctl_Address::operator!= ( const Ctl_Address & ctl_addr_n ) const
{
  return ( _addr_str != ctl_addr_n._addr_str );
}

void
Ctl_Address::update_addr_str ()
{
  _addr_str = _ctl_name;
  if ( _args.empty () ) {
    return;
  }

  _addr_str.append ( QChar ( ':' ) );
  for ( std::size_t ii = 0; ii < _args.size (); ++ii ) {
    const auto & argm = arg ( ii );
    if ( ii != 0 ) {
      _addr_str.append ( QChar ( ',' ) );
    }
    if ( !argm.name ().isEmpty () ) {
      _addr_str.append ( argm.name () );
      _addr_str.append ( QChar ( '=' ) );
    }
    _addr_str.append ( argm.value () );
  }
}

} // namespace QSnd
