/* Blinker
   Copyright 2011-2019 Stefan Schuermans <stefan@blinkenarea.org>
   Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html
   a blinkenarea.org project */

#include <arpa/inet.h>
#include <netinet/in.h>
#include <sstream>
#include <stdlib.h>
#include <string>
#include <sys/socket.h>
#include <sys/types.h>

#include "Udp4Addr.h"

namespace Blinker {

/// constructor
Udp4Addr::Udp4Addr()
{
  m_addr.sin_family = AF_INET;
  m_addr.sin_port = htons(0);
  m_addr.sin_addr.s_addr = htonl(INADDR_NONE);
}

/// virtual destructor
Udp4Addr::~Udp4Addr()
{
}

/// comparison
//@{

int Udp4Addr::compare(const Udp4Addr &that) const
{
  if (m_addr.sin_family < that.m_addr.sin_family)
    return -1;
  if (m_addr.sin_family > that.m_addr.sin_family)
    return 1;
  if (ntohl(m_addr.sin_addr.s_addr) < ntohl(that.m_addr.sin_addr.s_addr))
    return -1;
  if (ntohl(m_addr.sin_addr.s_addr) > ntohl(that.m_addr.sin_addr.s_addr))
    return 1;
  if (ntohs(m_addr.sin_port) < ntohs(that.m_addr.sin_port))
    return -1;
  if (ntohs(m_addr.sin_port) > ntohs(that.m_addr.sin_port))
    return 1;
  return 0;
}

bool Udp4Addr::operator==(const Udp4Addr &that) const
{
  return compare(that) == 0;
}

bool Udp4Addr::operator!=(const Udp4Addr &that) const
{
  return compare(that) != 0;
}

bool Udp4Addr::operator<(const Udp4Addr &that) const
{
  return compare(that) < 0;
}

bool Udp4Addr::operator>(const Udp4Addr &that) const
{
  return compare(that) > 0;
}

bool Udp4Addr::operator<=(const Udp4Addr &that) const
{
  return compare(that) <= 0;
}

bool Udp4Addr::operator>=(const Udp4Addr &that) const
{
  return compare(that) >= 0;
}

//@}

/// return address family
int Udp4Addr::getFamily() const
{
  return AF_INET;
}

/// return port (use this function only if absolutely necessary)
int Udp4Addr::getPort() const
{
  return ntohs(m_addr.sin_port);
}

/// set port (use this function only if absolutely necessary)
void Udp4Addr::setPort(int port)
{
  m_addr.sin_port = htons(port);
}

/**
 * @brief parse from string format
 * @param[in] str string format
 * @return if parsing was successful
 */
bool Udp4Addr::fromStr(const std::string &str)
{
  std::string::size_type posColon;
  std::string strIp, strPort;
  struct in_addr iaIp;
  unsigned long iPort;
  const char *szPort;
  char *szPortEnd;

  // split address into IP and port
  posColon = str.find(':');
  if (posColon == std::string::npos)
    return false;
  strIp = str.substr(0, posColon);
  strPort = str.substr(posColon + 1);

  // parse IP
  if (!inet_aton(strIp.c_str(), &iaIp))
    return false;

  // parse port
  szPort = strPort.c_str();
  iPort = strtoul(szPort, &szPortEnd, 10);
  if (*szPort == 0 || *szPortEnd != 0)
    return false;

  m_addr.sin_family = AF_INET;
  m_addr.sin_port = htons(iPort);
  m_addr.sin_addr = iaIp;
  return true;
}

/**
 * @brief convert to string format
 * @return string format
 */
std::string Udp4Addr::toStr() const
{
  std::stringstream strm;
  strm << inet_ntoa(m_addr.sin_addr) << ":" << ntohs(m_addr.sin_port);
  return strm.str();
}

} // namespace Blinker

