text: //
  // Created by stephane bourque on 2021-08-11.
  //
  
  #include "SerialNumberCache.h"
  #include <mutex>
  
  #include "StorageService.h"
  #include "framework/MicroService.h"
  
  namespace OpenWifi {
  
      int SerialNumberCache::Start() {
          return 0;
      }
  
      void SerialNumberCache::Stop() {
  
      }
  
      void SerialNumberCache::AddSerialNumber(const std::string &S, [[maybe_unused]] const std::string &DeviceType) {
          std::lock_guard		G(Mutex_);
  
          uint64_t SN = std::stoull(S, nullptr, 16);
          if(std::find(std::begin(SNs_),std::end(SNs_),SN) == std::end(SNs_)) {
              auto insert_point = std::lower_bound(SNs_.begin(), SNs_.end(), SN);
              SNs_.insert(insert_point, SN);
  
              auto R = ReverseSerialNumber(S);
              uint64_t RSN = std::stoull(R, nullptr, 16);
              auto rev_insert_point = std::lower_bound(Reverse_SNs_.begin(), Reverse_SNs_.end(), RSN);
              Reverse_SNs_.insert(rev_insert_point, RSN);
          }
      }
  
      void SerialNumberCache::DeleteSerialNumber(const std::string &S) {
          std::lock_guard		G(Mutex_);
  
          uint64_t SN = std::stoull(S,nullptr,16);
          auto It = std::find(SNs_.begin(),SNs_.end(),SN);
          if(It != SNs_.end()) {
              SNs_.erase(It);
  
              auto R = ReverseSerialNumber(S);
              uint64_t RSN = std::stoull(R, nullptr, 16);
              auto RIt = std::find(Reverse_SNs_.begin(),Reverse_SNs_.end(),RSN);
              if(RIt != Reverse_SNs_.end()) {
                  Reverse_SNs_.erase(RIt);
              }
          }
      }
  
      uint64_t Reverse(uint64_t N) {
          uint64_t Res = 0;
  
          for (int i = 0; i < 16; i++) {
              Res = (Res << 4) + (N & 0x000000000000000f);
              N  >>= 4;
          }
          Res >>= 16;
          return Res;
      }
  
      void SerialNumberCache::ReturnNumbers(const std::string &S, uint HowMany, const std::vector<uint64_t> &SNArr, std::vector<uint64_t> &A, bool ReverseResult) {
          std::lock_guard G(Mutex_);
  
          if (S.length() == 12) {
              uint64_t SN = std::stoull(S, nullptr, 16);
              auto It = std::find(SNArr.begin(), SNArr.end(), SN);
              if (It != SNArr.end()) {
                  A.push_back(ReverseResult ? Reverse(*It) : *It);
              }
          } else if (S.length() < 12) {
              std::string SS{S};
              SS.insert(SS.end(), 12 - SS.size(), '0');
              uint64_t SN = std::stoull(SS, nullptr, 16);
              auto LB = std::lower_bound(SNArr.begin(), SNArr.end(), SN);
              if (LB != SNArr.end()) {
                  for (; LB != SNArr.end() && HowMany; ++LB, --HowMany) {
                      if(ReverseResult) {
                          const auto TSN = ReverseSerialNumber(Utils::IntToSerialNumber(Reverse(*LB)));
                          if (S == TSN.substr(0,S.size())) {
                              A.emplace_back(Reverse(*LB));
                          } else {
                              break;
                          }
                      } else {
                          const auto TSN = Utils::IntToSerialNumber(*LB);
                          if (S == TSN.substr(0, S.size())) {
                              A.emplace_back(*LB);
                          } else {
                              break;
                          }
                      }
                  }
              }
          }
      }
  
      void SerialNumberCache::FindNumbers(const std::string &S, uint HowMany, std::vector<uint64_t> &A) {
          if(S.empty())
              return;
  
          if (S[0] == '*') {
              std::string Reversed;
              std::copy(rbegin(S), rend(S)-1, std::back_inserter(Reversed));
              if(Reversed.empty())
                  return;
              return ReturnNumbers(Reversed, HowMany, Reverse_SNs_, A, true);
          } else {
              return ReturnNumbers(S, HowMany, SNs_, A, false);
          }
      }
  }