// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd

// Author: liujisi@google.com (Pherl Liu)

#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_GENERATOR_FACTORY_H__
#define GOOGLE_PROTOBUF_COMPILER_JAVA_GENERATOR_FACTORY_H__

#include <memory>
#include <string>

#include "absl/container/btree_map.h"
#include "absl/container/flat_hash_map.h"
#include "absl/strings/string_view.h"
#include "google/protobuf/compiler/java/context.h"
#include "google/protobuf/descriptor.h"

namespace google {
namespace protobuf {
namespace compiler {
namespace java {

class MessageGenerator {
 public:
  explicit MessageGenerator(const Descriptor* descriptor);
  MessageGenerator(const MessageGenerator&) = delete;
  MessageGenerator& operator=(const MessageGenerator&) = delete;
  virtual ~MessageGenerator();

  // All static variables have to be declared at the top-level of the file
  // so that we can control initialization order, which is important for
  // DescriptorProto bootstrapping to work.
  virtual void GenerateStaticVariables(io::Printer* printer,
                                       int* bytecode_estimate) = 0;

  // Output code which initializes the static variables generated by
  // GenerateStaticVariables(). Returns an estimate of bytecode size.
  virtual int GenerateStaticVariableInitializers(io::Printer* printer) = 0;

  // Generate the class itself.
  virtual void Generate(io::Printer* printer) = 0;

  // Generates the base interface that both the class and its builder
  // implement
  virtual void GenerateInterface(io::Printer* printer) = 0;

  // Generate code to register all contained extensions with an
  // ExtensionRegistry.
  virtual void GenerateExtensionRegistrationCode(io::Printer* printer) = 0;

 protected:
  const Descriptor* descriptor_;
  absl::btree_map<int, const OneofDescriptor*> oneofs_;
};

class EnumGenerator {
 public:
  virtual ~EnumGenerator() = default;
  virtual void Generate(io::Printer* printer) = 0;
};

// Generates code for an extension, which may be within the scope of some
// message or may be at file scope.  This is much simpler than FieldGenerator
// since extensions are just simple identifiers with interesting types.
class ExtensionGenerator {
 public:
  virtual ~ExtensionGenerator() = default;

  virtual void Generate(io::Printer* printer) = 0;

  // Returns an estimate of the number of bytes the printed code will compile
  // to
  virtual int GenerateNonNestedInitializationCode(io::Printer* printer) = 0;

  // Returns an estimate of the number of bytes the printed code will compile
  // to
  virtual int GenerateRegistrationCode(io::Printer* printer) = 0;

 protected:
  static void InitTemplateVars(
      const FieldDescriptor* descriptor, const std::string& scope,
      bool immutable, ClassNameResolver* name_resolver,
      absl::flat_hash_map<absl::string_view, std::string>* vars_pointer,
      Context* context);
};

class ServiceGenerator {
 public:
  explicit ServiceGenerator(const ServiceDescriptor* descriptor)
      : descriptor_(descriptor) {}
  virtual ~ServiceGenerator() = default;

  ServiceGenerator(const ServiceGenerator&) = delete;
  ServiceGenerator& operator=(const ServiceGenerator&) = delete;

  virtual void Generate(io::Printer* printer) = 0;

  enum RequestOrResponse { REQUEST, RESPONSE };
  enum IsAbstract { IS_ABSTRACT, IS_CONCRETE };

 protected:
  const ServiceDescriptor* descriptor_;
};

// An interface to create generators for a given descriptor.  This interface
// is implemented for every variant of the Java API (Mutable, Immutable, Lite).
class GeneratorFactory {
 public:
  virtual ~GeneratorFactory() = default;

  virtual std::unique_ptr<MessageGenerator> NewMessageGenerator(
      const Descriptor* descriptor) const = 0;

  virtual std::unique_ptr<EnumGenerator> NewEnumGenerator(
      const EnumDescriptor* descriptor) const = 0;

  virtual std::unique_ptr<ExtensionGenerator> NewExtensionGenerator(
      const FieldDescriptor* descriptor) const = 0;

  virtual std::unique_ptr<ServiceGenerator> NewServiceGenerator(
      const ServiceDescriptor* descriptor) const = 0;
};

}  // namespace java
}  // namespace compiler
}  // namespace protobuf
}  // namespace google

#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_GENERATOR_FACTORY_H__
