func buildEnumDescriptorProto(f *surface_v1.Field) *dpb.EnumDescriptorProto {
	enumDescriptor := &dpb.EnumDescriptorProto{Name: &f.NativeType}
	for enumCtr, value := range f.EnumValues {
		num := int32(enumCtr)
		name := strings.ToUpper(value)
		valueDescriptor := &dpb.EnumValueDescriptorProto{
			Name:   &name,
			Number: &num,
		}
		enumDescriptor.Value = append(enumDescriptor.Value, valueDescriptor)
	}
	return enumDescriptor
}
buildEnumDescriptorProto builds the necessary descriptor to render a enum. (https://developers.google.com/protocol-buffers/docs/proto3#enum)
package generator
import (
	"log"
	"strings"
	dpb "github.com/golang/protobuf/protoc-gen-go/descriptor"
	surface_v1 "github.com/google/gnostic/surface"
	"google.golang.org/protobuf/types/descriptorpb"
)
var protoBufScalarTypes = getProtobufTypes()
var generatedMessages = make(map[string]string, 0)
func buildAllMessageDescriptors(renderer *Renderer) (messageDescriptors []*dpb.DescriptorProto, err error) {
	for _, surfaceType := range renderer.Model.Types {
		message := &dpb.DescriptorProto{}
		message.Name = &surfaceType.TypeName
		for i, surfaceField := range surfaceType.Fields {
			if strings.Contains(surfaceField.NativeType, "map[string][]") {
				continue
			}
			if isRequestParameter(surfaceType) {
				validateRequestParameter(surfaceField)
			}
			addFieldDescriptor(message, surfaceField, i, renderer.Package)
			addEnumDescriptorIfNecessary(message, surfaceField)
		}
		messageDescriptors = append(messageDescriptors, message)
		generatedMessages[*message.Name] = renderer.Package + "." + *message.Name
	}
	return messageDescriptors, nil
}
func isRequestParameter(sufaceType *surface_v1.Type) bool {
	if strings.Contains(sufaceType.Description, sufaceType.GetName()+" holds parameters to") {
		return true
	}
	return false
}
func validateRequestParameter(field *surface_v1.Field) {
	if field.Position == surface_v1.Position_PATH {
		validatePathParameter(field)
	}
	if field.Position == surface_v1.Position_QUERY {
		validateQueryParameter(field)
	}
}
func validatePathParameter(field *surface_v1.Field) {
	if field.Kind != surface_v1.FieldKind_SCALAR {
		log.Println("The path parameter with the Name " + field.Name + " is invalid. " +
			"The path template may refer to one or more fields in the gRPC request message, as" +
			" long as each field is a non-repeated field with a primitive (non-message) type. " +
			"See: https://github.com/googleapis/googleapis/blob/master/google/api/http.proto#L62 for more information.")
	}
}
func validateQueryParameter(field *surface_v1.Field) {
	_, isScalar := protoBufScalarTypes[field.NativeType]
	if !(field.Kind == surface_v1.FieldKind_SCALAR ||
		(field.Kind == surface_v1.FieldKind_ARRAY && isScalar) ||
		(field.Kind == surface_v1.FieldKind_REFERENCE)) {
		log.Println("The query parameter with the Name " + field.Name + " is invalid. " +
			"Note that fields which are mapped to URL query parameters must have a primitive type or" +
			" a repeated primitive type or a non-repeated message type. " +
			"See: https://github.com/googleapis/googleapis/blob/master/google/api/http.proto#L118 for more information.")
	}
}
func addFieldDescriptor(message *dpb.DescriptorProto, surfaceField *surface_v1.Field, idx int, packageName string) {
	count := int32(idx + 1)
	fieldDescriptor := &dpb.FieldDescriptorProto{Number: &count, Name: &surfaceField.FieldName}
	fieldDescriptor.Type = getFieldDescriptorType(surfaceField.NativeType, surfaceField.EnumValues)
	fieldDescriptor.Label = getFieldDescriptorLabel(surfaceField)
	fieldDescriptor.TypeName = getFieldDescriptorTypeName(*fieldDescriptor.Type, surfaceField, packageName)
	addMapDescriptorIfNecessary(surfaceField, fieldDescriptor, message)
	message.Field = append(message.Field, fieldDescriptor)
}
func getFieldDescriptorType(nativeType string, enumValues []string) *dpb.FieldDescriptorProto_Type {
	protoType := dpb.FieldDescriptorProto_TYPE_MESSAGE
	if protoType, ok := protoBufScalarTypes[nativeType]; ok {
		return &protoType
	}
	if enumValues != nil {
		protoType := dpb.FieldDescriptorProto_TYPE_ENUM
		return &protoType
	}
	return &protoType
}
func getFieldDescriptorTypeName(fieldDescriptorType descriptorpb.FieldDescriptorProto_Type, field *surface_v1.Field, packageName string) *string {
	if fieldHasAReferenceToAMessageInAnotherDependency(field, fieldDescriptorType) {
		t := generatedMessages[field.NativeType]
		return &t
	}
	typeName := ""
	if fieldDescriptorType == dpb.FieldDescriptorProto_TYPE_MESSAGE {
		typeName = packageName + "." + field.NativeType
	}
	if fieldDescriptorType == dpb.FieldDescriptorProto_TYPE_ENUM {
		typeName = field.NativeType
	}
	return &typeName
}
func fieldHasAReferenceToAMessageInAnotherDependency(field *surface_v1.Field, fieldDescriptorType descriptorpb.FieldDescriptorProto_Type) bool {
	_, messageExists := generatedMessages[field.NativeType]
	return fieldDescriptorType == dpb.FieldDescriptorProto_TYPE_MESSAGE && messageExists
}
func getFieldDescriptorLabel(f *surface_v1.Field) *dpb.FieldDescriptorProto_Label {
	label := dpb.FieldDescriptorProto_LABEL_OPTIONAL
	if f.Kind == surface_v1.FieldKind_ARRAY || strings.Contains(f.NativeType, "map") {
		label = dpb.FieldDescriptorProto_LABEL_REPEATED
	}
	return &label
}
func addMapDescriptorIfNecessary(f *surface_v1.Field, fieldDescriptor *dpb.FieldDescriptorProto, message *dpb.DescriptorProto) {
	if f.Kind == surface_v1.FieldKind_MAP {
		mapDescriptor := buildMapDescriptor(f)
		fieldDescriptor.TypeName = mapDescriptor.Name
		message.NestedType = append(message.NestedType, mapDescriptor)
	}
}
func buildMapDescriptor(field *surface_v1.Field) *dpb.DescriptorProto {
	isMapEntry := true
	n := field.FieldName + "Entry"
	mapDP := &dpb.DescriptorProto{
		Name:    &n,
		Field:   buildKeyValueFields(field),
		Options: &dpb.MessageOptions{MapEntry: &isMapEntry},
	}
	return mapDP
}
func buildKeyValueFields(field *surface_v1.Field) []*dpb.FieldDescriptorProto {
	k, v := "key", "value"
	var n1, n2 int32 = 1, 2
	l := dpb.FieldDescriptorProto_LABEL_OPTIONAL
	t := dpb.FieldDescriptorProto_TYPE_STRING
	keyField := &dpb.FieldDescriptorProto{
		Name:   &k,
		Number: &n1,
		Label:  &l,
		Type:   &t,
	}
	valueType := field.NativeType[11:]  
	valueField := &dpb.FieldDescriptorProto{
		Name:     &v,
		Number:   &n2,
		Label:    &l,
		Type:     getFieldDescriptorType(valueType, field.EnumValues),
		TypeName: getTypeNameForMapValueType(valueType),
	}
	return []*dpb.FieldDescriptorProto{keyField, valueField}
}
func getTypeNameForMapValueType(valueType string) *string {
	if _, ok := protoBufScalarTypes[valueType]; ok {
		return nil  
	}
	typeName := valueType
	return &typeName
}
func addEnumDescriptorIfNecessary(message *dpb.DescriptorProto, f *surface_v1.Field) {
	if f.EnumValues != nil {
		message.EnumType = append(message.EnumType, buildEnumDescriptorProto(f))
	}
}