/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file Copyright.txt or https://cmake.org/licensing for details.  */
#include "cmDefinitions.h"

#include "cm_string_view.hxx"

#include <assert.h>
#include <functional>
#include <unordered_set>
#include <utility>

cmDefinitions::Def cmDefinitions::NoDef;

cmDefinitions::Def const& cmDefinitions::GetInternal(const std::string& key,
                                                     StackIter begin,
                                                     StackIter end, bool raise)
{
  assert(begin != end);
  {
    auto it = begin->Map.find(key);
    if (it != begin->Map.end()) {
      it->second.Used = true;
      return it->second;
    }
  }
  StackIter it = begin;
  ++it;
  if (it == end) {
    return cmDefinitions::NoDef;
  }
  Def const& def = cmDefinitions::GetInternal(key, it, end, raise);
  if (!raise) {
    return def;
  }
  return begin->Map.emplace(key, def).first->second;
}

const std::string* cmDefinitions::Get(const std::string& key, StackIter begin,
                                      StackIter end)
{
  Def const& def = cmDefinitions::GetInternal(key, begin, end, false);
  return def.Exists ? &def.Value : nullptr;
}

void cmDefinitions::Raise(const std::string& key, StackIter begin,
                          StackIter end)
{
  cmDefinitions::GetInternal(key, begin, end, true);
}

bool cmDefinitions::HasKey(const std::string& key, StackIter begin,
                           StackIter end)
{
  for (StackIter it = begin; it != end; ++it) {
    if (it->Map.find(key) != it->Map.end()) {
      return true;
    }
  }
  return false;
}

cmDefinitions cmDefinitions::MakeClosure(StackIter begin, StackIter end)
{
  cmDefinitions closure;
  std::unordered_set<cm::string_view> undefined;
  for (StackIter it = begin; it != end; ++it) {
    // Consider local definitions.
    for (auto const& mi : it->Map) {
      // Use this key if it is not already set or unset.
      if (closure.Map.find(mi.first) == closure.Map.end() &&
          undefined.find(mi.first) == undefined.end()) {
        if (mi.second.Exists) {
          closure.Map.insert(mi);
        } else {
          undefined.emplace(mi.first);
        }
      }
    }
  }
  return closure;
}

std::vector<std::string> cmDefinitions::ClosureKeys(StackIter begin,
                                                    StackIter end)
{
  std::vector<std::string> defined;
  std::unordered_set<cm::string_view> bound;

  for (StackIter it = begin; it != end; ++it) {
    defined.reserve(defined.size() + it->Map.size());
    for (auto const& mi : it->Map) {
      // Use this key if it is not already set or unset.
      if (bound.emplace(mi.first).second && mi.second.Exists) {
        defined.push_back(mi.first);
      }
    }
  }

  return defined;
}

void cmDefinitions::Set(const std::string& key, cm::string_view value)
{
  this->Map[key] = Def(value);
}

void cmDefinitions::Unset(const std::string& key)
{
  this->Map[key] = Def();
}

std::vector<std::string> cmDefinitions::UnusedKeys() const
{
  std::vector<std::string> keys;
  keys.reserve(this->Map.size());
  // Consider local definitions.
  for (auto const& mi : this->Map) {
    if (!mi.second.Used) {
      keys.push_back(mi.first);
    }
  }
  return keys;
}
