// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/accessibility/platform/ax_unique_id.h"

#include <memory>
#include <unordered_set>

#include "base/lazy_instance.h"

namespace ui {

namespace {

base::LazyInstance<std::unordered_set<int32_t>>::Leaky g_assigned_ids =
    LAZY_INSTANCE_INITIALIZER;

}  // namespace

AXUniqueId::AXUniqueId(const int32_t max_id) : id_(GetNextAXUniqueId(max_id)) {}

AXUniqueId::~AXUniqueId() {
  g_assigned_ids.Get().erase(id_);
}

bool AXUniqueId::operator==(const AXUniqueId& other) const {
  return Get() == other.Get();
}

bool AXUniqueId::operator!=(const AXUniqueId& other) const {
  return !(*this == other);
}

bool AXUniqueId::IsAssigned(int32_t id) const {
  auto id_map = g_assigned_ids.Get();
  return id_map.find(id) != id_map.end();
}

int32_t AXUniqueId::GetNextAXUniqueId(const int32_t max_id) {
  static int32_t current_id = 0;
  static bool has_wrapped = false;

  const int32_t prev_id = current_id;

  while (true) {
    if (current_id == max_id) {
      current_id = 1;
      has_wrapped = true;
    } else {
      current_id++;
    }
    if (current_id == prev_id)
      LOG(FATAL) << "Over 2 billion active ids, something is wrong.";
    if (!has_wrapped || !IsAssigned(current_id))
      break;
  }

  g_assigned_ids.Get().insert(current_id);

  return current_id;
}

}  // namespace ui
