#ifndef __JDATABASE__JMACADDRESS__
#define __JDATABASE__JMACADDRESS__

#include <string>
#include <istream>
#include <ostream>
#include <iomanip>
#include <vector>

#include "JLang/JEquals.hh"

/**
 * \file
 * MAC address.
 * \author mdejong
 */
namespace JDATABASE {}
namespace JPP { using namespace JDATABASE; }

namespace JDATABASE {

  using JLANG::JEquals;


  /**
   * MAC address
   */
  struct JMACAddress :
    public std::vector<unsigned char>,
    public JEquals<JMACAddress>
  {
    enum { 
      NUMBER_OF_BYTES = 6                    //!< number of bytes
    };


    /**
     * Get list of allowed separators.
     *
     * \return              allowed separators
     */
    static const char* get_separator()
    {
      return ":.-";
    }


    /**
     * Check if given character is an allowed separator.
     *
     * \param  c            character
     * \return              true if separator; else false
     */
    static bool is_separator(const int c)
    {
      const std::string buffer(JMACAddress::get_separator());

      for (std::string::const_iterator i = buffer.begin(); i != buffer.end(); ++i) {
	if ((int) *i == c) {
	  return true;
	}
      }

      return false;
    }


    /**
     * Default constructor.
     */
    JMACAddress() :
      std::vector<unsigned char>(NUMBER_OF_BYTES, 0)
    {}


    /**
     * Equal method.
     *
     * \param  address      MAC address
     * \return              true if this MAC address and given MAC address are equal; else false
     */
    inline bool equal(const JMACAddress& address) const
    {
      for (int i = 0; i != NUMBER_OF_BYTES; ++i) {
	if ((*this)[i] != address[i]) {
	  return false;
	}
      }

      return true;
    }


    /**
     * Read MAC address from input stream.
     *
     * \param  in         input stream
     * \param  object     MAC address
     * \return            input stream
     */
    friend inline std::istream& operator>>(std::istream& in, JMACAddress& object)
    {
      using namespace std;

      object = JMACAddress();

      int c;
      
      if (in >> hex >> c) {

	object[0] = (unsigned char) c;

	for (int i = 1; i != NUMBER_OF_BYTES; ++i) {
	  if (is_separator(in.get()) && in >> hex >> c) 
	    object[i] = (unsigned char) c;
	  else
	    in.setstate(ios::failbit);
	}
      }

      return in >> dec;
    }



    /**
     * Write MAC address to output stream.
     *
     * \param  out        output stream
     * \param  object     MAC address
     * \return            output stream
     */
    friend inline std::ostream& operator<<(std::ostream& out, const JMACAddress& object)
    {
      using namespace std;

      out << setw(2) << setfill('0') << hex << (int) object[0];

      for (int i = 1; i != NUMBER_OF_BYTES; ++i) {
	out << setw(1) << JMACAddress::get_separator()[0] 
	    << setw(2) << setfill('0') << hex << (int) object[i];
      }
      
      return out << setfill(' ') << dec;
    }

    ClassDefNV(JMACAddress, 1);
  };
}

#endif