// Copyright 2020 The Fuchsia 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 "src/logger/event_vector_index.h"

#include "src/lib/statusor/status_macros.h"
#include "src/lib/statusor/statusor.h"

namespace cobalt::logger {

namespace {

// Returns a sorted list of the event codes which are explicitly enumerated in
// |metric_dim|.
std::vector<uint32_t> GetSortedEnumeratedEventCodes(
    const MetricDefinition::MetricDimension &metric_dim) {
  std::vector<uint32_t> event_codes;
  for (const auto &[key, value] : metric_dim.event_codes()) {
    event_codes.push_back(key);
  }

  std::sort(event_codes.begin(), event_codes.end());
  return event_codes;
}

}  // namespace

uint64_t GetNumEventCodes(const MetricDefinition::MetricDimension &metric_dim) {
  if (metric_dim.max_event_code() != 0u) {
    return metric_dim.max_event_code() + 1;
  }
  return metric_dim.event_codes_size();
}

uint64_t GetNumEventVectors(
    const google::protobuf::RepeatedPtrField<MetricDefinition::MetricDimension>
        &metric_dimensions) {
  uint64_t num_event_vectors = 1;
  for (const auto &metric_dim : metric_dimensions) {
    num_event_vectors *= GetNumEventCodes(metric_dim);
  }
  return num_event_vectors;
}

lib::statusor::StatusOr<uint64_t> EventCodeToIndexForDimension(
    uint32_t event_code, const MetricDefinition::MetricDimension &metric_dim) {
  // If |metric_dim| has a max_event_code, just cast |event_code| to a uint64.
  if (metric_dim.max_event_code() != 0u) {
    if (event_code > metric_dim.max_event_code()) {
      return util::Status(util::INVALID_ARGUMENT, "event_code is larger than max_event_code.");
    }
    return event_code;
  }
  // Otherwise, find the index of |event_code| in the sorted list of enumerated
  // event codes.
  std::vector<uint32_t> event_codes = GetSortedEnumeratedEventCodes(metric_dim);
  for (uint64_t i = 0; i < event_codes.size(); ++i) {
    if (event_codes[i] == event_code) {
      return i;
    }
  }
  return util::Status(util::INVALID_ARGUMENT, "event_code not found in MetricDimension.");
}

lib::statusor::StatusOr<uint32_t> EventCodeFromIndexForDimension(
    uint64_t index, const MetricDefinition::MetricDimension &metric_dim) {
  // If |metric_dim| has a max_event_code, just cast |index| to a uint32.
  if (metric_dim.max_event_code() != 0) {
    if (index > metric_dim.max_event_code()) {
      return util::Status(util::INVALID_ARGUMENT, "event_code not found in MetricDimension.");
    }
    return static_cast<uint32_t>(index);
  }
  // Otherwise, |index| is an index into the sorted list of enumerated event
  // codes.
  if (index >= static_cast<uint64_t>(metric_dim.event_codes_size())) {
    return util::Status(util::INVALID_ARGUMENT, "event_code not found in MetricDimension.");
  }
  std::vector<uint32_t> event_codes = GetSortedEnumeratedEventCodes(metric_dim);
  return event_codes[index];
}

lib::statusor::StatusOr<uint64_t> EventVectorToIndex(std::vector<uint32_t> event_vector,
                                                     const MetricDefinition &metric_def) {
  if (int(event_vector.size()) != metric_def.metric_dimensions_size()) {
    return util::Status(util::INVALID_ARGUMENT,
                        "event_vector size differs from number of metric dimensions");
  }
  uint64_t multiplier = 1;
  uint64_t result = 0;
  for (size_t i = 0; i < event_vector.size(); ++i) {
    CB_ASSIGN_OR_RETURN(uint32_t index, EventCodeToIndexForDimension(
                                            event_vector[i], metric_def.metric_dimensions(i)));
    result += index * multiplier;
    multiplier *= GetNumEventCodes(metric_def.metric_dimensions(i));
  }

  return result;
}

lib::statusor::StatusOr<std::vector<uint32_t>> EventVectorFromIndex(
    uint64_t index, const google::protobuf::RepeatedPtrField<MetricDefinition::MetricDimension>
                        &metric_dimensions) {
  std::vector<uint32_t> result;
  uint64_t divisor = 1;
  for (const auto &dim : metric_dimensions) {
    divisor *= GetNumEventCodes(dim);
  }

  for (int64_t i = static_cast<int64_t>(metric_dimensions.size()) - 1; i >= 0; --i) {
    divisor /= GetNumEventCodes(metric_dimensions[i]);
    CB_ASSIGN_OR_RETURN(uint32_t decoded_event_code,
                        EventCodeFromIndexForDimension(index / divisor, metric_dimensions[i]));
    result.insert(result.begin(), decoded_event_code);
    index = index % divisor;
  }

  if (index > 0) {
    return util::Status(util::INVALID_ARGUMENT,
                        "index is too large to correspond to an event vector");
  }
  return result;
}

}  // namespace cobalt::logger
