// Copyright 2019 Google LLC
//
// 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 FCP_TRACING_TRACING_TRAITS_H_
#define FCP_TRACING_TRACING_TRAITS_H_

#include <memory>
#include <string>

#include "absl/base/attributes.h"
#include "fcp/tracing/tracing_severity.h"
#include "fcp/tracing/tracing_tag.h"
#include "flatbuffers/flatbuffers.h"

namespace fcp {

// Base class for tracing traits, allows working with generated tracing traits
// (see below) in polymorphic way at runtime without knowledge of a type.
class TracingTraitsBase {
 public:
  // Returns printable name of the FlatBuffers table
  ABSL_MUST_USE_RESULT virtual const char* Name() const = 0;
  // Returns printable severity of the event represented by this table.
  ABSL_MUST_USE_RESULT virtual TracingSeverity Severity() const = 0;
  // Formats a serialized flatbuffer into human readable format.
  ABSL_MUST_USE_RESULT virtual std::string TextFormat(
      const flatbuffers::DetachedBuffer& buf) const = 0;
  // Formats a serialized flatbuffer into a Json string.
  ABSL_MUST_USE_RESULT virtual std::string JsonStringFormat(
      const uint8_t* flatbuf_bytes) const = 0;

  // Allows to lookup FlatBuffers table traits by its 4-character tag.
  // For unknown tag returns a stub.
  static TracingTraitsBase const* Lookup(TracingTag tag);

  // Registers runtime trait information (to be used for generated code only).
  // Multiple compilation units are allowed to register the same traits,
  // last registration wins.
  static void Register(TracingTag tag,
                       std::unique_ptr<TracingTraitsBase> trait);

  static std::string SeverityString(const TracingSeverity tracing_severity) {
    switch (tracing_severity) {
      case TracingSeverity::kInfo:
        return "INFO";
      case TracingSeverity::kWarning:
        return "WARNING";
      case TracingSeverity::kError:
        return "ERROR";
    }
  }

  virtual ~TracingTraitsBase() = default;
};

// Specializations of TracingTraits used by TracingSpan are typically included
// into user code together with the definitions of concrete FlatBufferTable via
// "tracing_schema.h" header. The latter is auto-generated by
// tracing_traits_generator tool from "tracing_schema.fbs".
template <class FlatBufferTable>
class TracingTraits;

namespace internal {

// Helper class to for automatic registration of traits for runtime use.
// This is intended to be used from autogenerated code only.
template<class FlatBufferTable>
struct TracingTraitsRegistrar {
  TracingTraitsRegistrar() {
    TracingTraitsBase::Register(
        TracingTraits<FlatBufferTable>::kTag,
        std::make_unique<TracingTraits<FlatBufferTable>>());
  }
};

}  // namespace internal

}  // namespace fcp

#endif  // FCP_TRACING_TRACING_TRAITS_H_
