/*!
 * \file    /utl/com/_1wire_id.h
 * \brief   An 1-wire Rom ID type
 *
 * Copyright (C) 2018 Christos Choutouridis
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3
 * of the License, or (at your option) any later version.
 *
 * This program 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
#ifndef __utl_com_1wire_id_h__
#define __utl_com_1wire_id_h__

#include <utl/core/impl.h>
#include <utl/container/id.h>

namespace utl {

   /*!
    * 1-wire Rom-ID type
    */
   class _1wire_id_t : public id_t<uint8_t, 8> {

   /*!
    * \name Constructors
    */
   //!@{
   public:
      _1wire_id_t () noexcept
         : id_t<uint8_t, 8> {0, 0, 0, 0, 0, 0, 0, 0} { }
      _1wire_id_t (const _1wire_id_t& id) noexcept {
         std::copy(id.begin(), id.end(), this->begin());
      }
   //!@}
   /*!
    * \name User functionality provided by the interface
    */
   //!@{
      //! Return nullDev reference
      static constexpr const _1wire_id_t& nullDev () { return nullDev_; }

      //!@{
      //! Return the RomID family code (The LSB)
      uint8_t& family() noexcept { return front(); }
      const uint8_t& family() const noexcept { return front(); }
      //!@}

      //!@{
      //! Access the CRC8 byte (The MSB).
      uint8_t& crc8() noexcept { return back(); }
      const uint8_t& crc8() const noexcept { return back(); }
      //!@}

      /*!
       * \brief
       *    Full compare two dev_ids
       * \return  The comparison result
       *    \arg  0    dev_ids are equal
       *    \arg -1    dev_id lhs is smaller than dev_id rhs
       *    \arg  1    dev_id rhs is smaller than dev_id lhs
       */
      static int compare (const _1wire_id_t& lhs, const _1wire_id_t& rhs) noexcept {
         auto p = std::mismatch (lhs.rbegin(), lhs.rend(), rhs.rbegin());
         if (p.first == lhs.rend())       return 0;
         else if (*p.first < *p.second)   return -1;
         else                             return 1;
      }
   //!@{

   //!@{
   //! Self referenced special null Rom_ID object as static
   private:
      static const _1wire_id_t nullDev_;
   //!@}
   };

   // Init static member
   const _1wire_id_t _1wire_id_t::nullDev_ { };

} // namespace tbx

#endif /* __utl_com_1wire_id_h__ */
