package genproto

import (
	"github.com/golang/protobuf/proto"
	"github.com/golang/protobuf/protoc-gen-go/descriptor"

	pgs "github.com/lyft/protoc-gen-star"
)

// Message describes a proto message. Messages can be contained in either
// another Message or File, and may house further Messages and/or Enums. While
// all Fields technically live on the Message, some may be contained within
// OneOf blocks.
type Message struct {
	msg pgs.Message
}

var _ pgs.Message = (*Message)(nil)

// Name is the Name of the entity
func (m *Message) Name() pgs.Name {
	return m.msg.Name()
}

//FullyQualifiedName is the fully qualified name of the entity. For example, a message 'HelloRequest' in a 'helloworld' package takes the form of '.helloworld.HelloRequest'.
func (m *Message) FullyQualifiedName() string {
	return m.msg.FullyQualifiedName()
}

// Syntax identifies whether this entity is encoded with proto2 or proto3 syntax.
func (m *Message) Syntax() pgs.Syntax {
	return m.msg.Syntax()
}

// Package returns the container package for this entity.
func (m *Message) Package() pgs.Package {
	return m.msg.Package()
}

// File returns the File containing this entity.
func (m *Message) File() pgs.File {
	return m.msg.File()
}

// BuildTarget identifies whether or not generation should be performed on
// this entity. Use this flag to determine if the file was targeted in the
// protoc run or if it was loaded as an external dependency.
func (m *Message) BuildTarget() bool {
	return m.msg.BuildTarget()
}

// SourceCodeInfo returns the SourceCodeInfo associated with the entity.
// Primarily, this struct contains the comments associated with the Entity.
func (m *Message) SourceCodeInfo() pgs.SourceCodeInfo {
	return m.msg.SourceCodeInfo()
}

// Descriptor returns the underlying proto descriptor for this message
func (m *Message) Descriptor() *descriptor.DescriptorProto {
	return m.msg.Descriptor()
}

// Parent returns either the File or Message that directly contains this
// Message.
func (m *Message) Parent() pgs.ParentEntity {
	return m.msg.Parent()
}

// Enums returns the top-level enums from this entity. Nested enums
// are not included.
func (m *Message) Enums() []pgs.Enum {
	return m.msg.Enums()
}

// Messages returns the top-level messages from this entity. Nested
// messages are not included.
func (m *Message) Messages() []pgs.Message {
	return m.msg.Messages()
}

// Fields returns all fields on the message, including those contained within
// OneOf blocks.
func (m *Message) Fields() []pgs.Field {
	return m.msg.Fields()
}

// OneOfs returns the OneOfs contained within this Message.
func (m *Message) OneOfs() []pgs.OneOf {
	return m.msg.OneOfs()
}

// MapEntries returns the MapEntry message types contained within this
// Entity. These messages are not returned by the Messages or AllMessages
// methods. Map Entry messages are typically not exposed to the end user.
func (m *Message) MapEntries() []pgs.Message {
	return m.msg.MapEntries()
}

// NonOneOfFields returns all fields not contained within OneOf blocks.
func (m *Message) NonOneOfFields() []pgs.Field {
	return m.msg.NonOneOfFields()
}

// OneOfFields returns only the fields contained within OneOf blocks.
func (m *Message) OneOfFields() []pgs.Field {
	return m.msg.NonOneOfFields()
}

// Extensions returns all of the Extensions applied to this Message.
func (m *Message) Extensions() []pgs.Extension {
	return m.msg.Extensions()
}

// Dependents returns all of the messages where message is directly or
// transitively used.
func (m *Message) Dependents() []pgs.Message {
	return m.msg.Dependents()
}

// IsMapEntry identifies this message as a MapEntry. If true, this message is
// not generated as code, and is used exclusively when marshaling a map field
// to the wire format.
func (m *Message) IsMapEntry() bool {
	return m.msg.IsMapEntry()
}

// IsWellKnown identifies whether or not this Message is a WKT from the
// `google.protobuf` package. Most official plugins special case these types
// and they usually need to be handled differently.
func (m *Message) IsWellKnown() bool {
	return m.msg.IsWellKnown()
}

// WellKnownType returns the WellKnownType associated with this field. If
// IsWellKnown returns false, UnknownWKT is returned.
func (m *Message) WellKnownType() pgs.WellKnownType {
	return m.msg.WellKnownType()
}

// SetParent ...
func (m *Message) SetParent(p pgs.ParentEntity) {
	m.msg.SetParent(p)
}

// GetDependents ...
func (m *Message) GetDependents(set map[string]pgs.Message) {
	m.msg.GetDependents(set)
}

//AddDefExtension ...
func (m *Message) AddDefExtension(ext pgs.Extension) {
	m.msg.AddDefExtension(ext)
}

// Accept processes a Visitor
func (m *Message) Accept(v pgs.Visitor) error {
	return m.msg.Accept(v)
}

// AddField adds a Field to the message
func (m *Message) AddField(f pgs.Field) {
	m.msg.AddField(f)
}

// AddExtension ...
func (m *Message) AddExtension(e pgs.Extension) {
	m.msg.AddExtension(e)
}

// AddEnum ...
func (m *Message) AddEnum(e pgs.Enum) {
	m.msg.AddEnum(e)
}

// AddMessage ...
func (m *Message) AddMessage(msg pgs.Message) {
	m.msg.AddMessage(msg)
}

// AddOneOf ...
func (m *Message) AddOneOf(o pgs.OneOf) {
	m.msg.AddOneOf(o)
}

// AddMapEntry ...
func (m *Message) AddMapEntry(msg pgs.Message) {
	m.msg.AddMapEntry(msg)
}

// AddDependent ...
func (m *Message) AddDependent(msg pgs.Message) {
	m.msg.AddDependent(msg)
}

// ChildAtPath ...
func (m *Message) ChildAtPath(path []int32) pgs.Entity {
	return m.msg.ChildAtPath(path)
}

// AddSourceCodeInfo ...
func (m *Message) AddSourceCodeInfo(info pgs.SourceCodeInfo) {
	m.msg.AddSourceCodeInfo(info)
}

// AllEnums returns all top-level and nested enums from this entity.
func (m *Message) AllEnums() []pgs.Enum {
	return m.msg.AllEnums()
}

// AllMessages returns all the top-level and nested messages from this Entity.
func (m *Message) AllMessages() []pgs.Message {
	return m.msg.AllMessages()
}

// Imports includes external files directly required by this entity. Call
// TransitiveImports on File to get all transitive dependencies.
func (m *Message) Imports() (i []pgs.File) {
	return m.msg.Imports()
}

// DefinedExtensions returns all Extensions defined on this entity.
func (m *Message) DefinedExtensions() []pgs.Extension {
	return m.msg.DefinedExtensions()
}

// Extension extracts an extension from the entity's options, described by
// desc and populates the value ext. Ext must be a pointer type. An error
// will only be returned if there is a type mismatch between desc and ext.
// The ok value will be true if the extension was found. If the extension
// is NOT found, ok will be false and err will be nil.
func (m *Message) Extension(desc *proto.ExtensionDesc, ext interface{}) (bool, error) {
	return m.msg.Extension(desc, ext)
}

var _ pgs.Message = (*Message)(nil)