// Copyright 2016 The Fuchsia Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef COBALT_CONFIG_CONFIG_H_
#define COBALT_CONFIG_CONFIG_H_

#include <fcntl.h>
#include <google/protobuf/io/tokenizer.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>

#include <memory>
#include <string>
#include <unordered_map>
#include <utility>

namespace cobalt {
namespace config {

enum Status {
  kOK = 0,

  // The specified file could not be opened.
  kFileOpenError = 1,

  // The specified file could not be parsed as the appropriate type
  // of protocol message.
  kParsingError = 2,

  // The specified file could be parsed but it contained two different
  // objects with the same fully-qualified ID.
  kDuplicateRegistration = 3
};

// A template for a Registry.
//
// RT should be one of:
// RegisteredEncodings, RegisteredReports, RegisteredMetrics.
//
// We then define |T| to be the corresponding one of:
// EncodingConfig, ReportConfig, Metric.
//
// A Registry<RT> is then a container for all of the |T|s registered in Cobalt.
template <class RT>
class Registry {
 public:
  // This is some template meta-programming magic that has the effect of
  // defining |T| to be the type of the objects contained in a registry
  // of type |RT|.
  typedef typename std::remove_pointer<decltype(
      (reinterpret_cast<RT*>(0))->mutable_element(0))>::type T;

 private:
  // The container for the registry.  The keys in this map are strings that
  // encode ID triples of the form (customer_id, project_id, id).
  typedef std::unordered_map<std::string, std::unique_ptr<T>> Map;

 public:
  // Iterator for going through registry items.  We just use the Map iterator
  // but return only values (without keys).
  class RegistryIterator {
   public:
    explicit RegistryIterator(const typename Map::iterator& iter)
        : iter_(iter) {}

    const T& operator*() const { return *iter_->second; }

    bool operator!=(const RegistryIterator& rhs) const {
      return iter_ != rhs.iter_;
    }

    const RegistryIterator& operator++() {
      ++iter_;
      return *this;
    }

   private:
    typename Map::iterator iter_;
  };
  typedef RegistryIterator iterator;

  // Populates a new instance of Registry<RT> by swapping the contents out of
  // of |contents|. Returns a pair consisting of a pointer to the
  // result and a Status.
  //
  // If the operation is successful then the status is kOK. Otherwise the
  // Status indicates the error.
  //
  // If |error_collector| is not null then it will be notified of any parsing
  // errors or warnings.
  static std::pair<std::unique_ptr<Registry<RT>>, Status> TakeFrom(
      RT* contents, google::protobuf::io::ErrorCollector* error_collector);

  // Returns the number of |T| in this registry.
  size_t size();

  // Returns the |T| with the given ID triple, or nullptr if there is
  // no such |T|. The caller does not take ownership of the returned
  // pointer.
  const T* const Get(uint32_t customer_id, uint32_t project_id, uint32_t id) {
    auto iterator = map_.find(MakeKey(customer_id, project_id, id));
    if (iterator == map_.end()) {
      return nullptr;
    }
    return iterator->second.get();
  }

  // Provide a mechansim to iterate through all registry items.
  RegistryIterator begin() { return RegistryIterator(map_.begin()); }
  RegistryIterator end() { return RegistryIterator(map_.end()); }

 private:
  // Builds a map key that encodes the triple (customer_id, project_id, id)
  static std::string MakeKey(uint32_t customer_id, uint32_t project_id,
                             uint32_t id);

  // Builds a map key from the ids in |config_proto|.
  static std::string MakeKey(const T& config_proto);

  // The keys in this map are strings that encode ID triples of the form
  // (customer_id, project_id, id)
  Map map_;
};

//////////////////////////////////////////////////////////////////
/// IMPLEMENTATION BELOW
//////////////////////////////////////////////////////////////////

template <class RT>
std::string Registry<RT>::MakeKey(uint32_t customer_id, uint32_t project_id,
                                  uint32_t id) {
  // Three 32-bit positive ints (at most 10 digits each) plus 3 colons plus a
  // trailing null is <= 34 bytes.
  char out[34];
  int size =
      snprintf(out, sizeof(out), "%u:%u:%u", customer_id, project_id, id);
  if (size <= 0) {
    return "";
  }
  return std::string(out, size);
}

template <class RT>
std::string Registry<RT>::MakeKey(const T& config_proto) {
  return MakeKey(config_proto.customer_id(), config_proto.project_id(),
                 config_proto.id());
}

template <class RT>
std::pair<std::unique_ptr<Registry<RT>>, Status> Registry<RT>::TakeFrom(
    RT* registered_configs,
    google::protobuf::io::ErrorCollector* error_collector) {
  // Make an empty registry to return;
  std::unique_ptr<Registry<RT>> registry(new Registry<RT>());

  // Put all of the T's into the map, ensuring that the id triples
  // are unique.
  int num_configs = registered_configs->element_size();
  for (int i = 0; i < num_configs; i++) {
    T* config_proto = registered_configs->mutable_element(i);
    // First build the key and insert an empty Tg into the map
    // at that key.
    auto pair = registry->map_.insert(
        std::make_pair(MakeKey(*config_proto), std::unique_ptr<T>(new T())));
    const bool& success = pair.second;
    auto& inserted_pair = pair.first;
    if (!success) {
      return std::make_pair(std::move(registry), kDuplicateRegistration);
    }
    // Then swap in the data from the T;
    inserted_pair->second->Swap(config_proto);
  }
  return std::make_pair(std::move(registry), kOK);
}

template <class RT>
size_t Registry<RT>::size() {
  return map_.size();
}

}  // namespace config
}  // namespace cobalt

#endif  // COBALT_CONFIG_CONFIG_H_
