func (a *Action) HasOptionalParams() bool {
	for _, param := range a.Params {
		if !param.Mandatory {
			return true
		}
	}
	return false
}
HasOptionalParams returns true if the action takes optional parameters, false otherwise.
package gen
import (
	"fmt"
	"sort"
	"strconv"
	"strings"
)
type APIDescriptor struct {
	Version       string                      
	Resources     map[string]*Resource        
	Types         map[string]*ObjectDataType  
	ResourceNames []string                    
	TypeNames     []string                    
	NeedTime      bool                        
	NeedJSON      bool                        
}
func (d *APIDescriptor) Merge(other *APIDescriptor) error {
	if d.Version != other.Version {
		return fmt.Errorf("Can't merge API descriptors with different versions")
	}
	for _, name := range d.ResourceNames {
		for _, otherName := range other.ResourceNames {
			if name == otherName {
				return fmt.Errorf("%s is a resource that exists in multiple APIs, generate separate clients", name)
			}
		}
	}
	for _, name := range d.TypeNames {
		for i, otherName := range other.TypeNames {
			if name == otherName {
				newName := MakeUniq(otherName, append(d.TypeNames, other.TypeNames...))
				first := other.TypeNames[:i]
				last := append([]string{newName}, other.TypeNames[i+1:]...)
				other.TypeNames = append(first, last...)
				typ := other.Types[name]
				delete(other.Types, name)
				typ.TypeName = newName
				other.Types[newName] = typ
			}
		}
	}
	for name, resource := range other.Resources {
		d.Resources[name] = resource
	}
	for name, typ := range other.Types {
		d.Types[name] = typ
	}
	d.ResourceNames = append(d.ResourceNames, other.ResourceNames...)
	d.TypeNames = append(d.TypeNames, other.TypeNames...)
	return nil
}
func (d *APIDescriptor) FinalizeTypeNames(rawTypes map[string][]*ObjectDataType) {
	rawTypeNames := make([]string, len(rawTypes))
	idx := 0
	for n := range rawTypes {
		rawTypeNames[idx] = n
		idx++
	}
	sort.Strings(rawTypeNames)
	for _, tn := range rawTypeNames {
		types := rawTypes[tn]
		for rn := range d.Resources {
			if tn == rn {
				oldTn := tn
				if strings.HasSuffix(tn, "Param") {
					tn = fmt.Sprintf("%s2", tn)
				} else {
					tn = fmt.Sprintf("%sParam", tn)
				}
				for _, ty := range types {
					ty.TypeName = tn
				}
				rawTypes[tn] = types
				delete(rawTypes, oldTn)
			}
		}
	}
	idx = 0
	for n := range rawTypes {
		rawTypeNames[idx] = n
		idx++
	}
	sort.Strings(rawTypeNames)
	for _, tn := range rawTypeNames {
		types := rawTypes[tn]
		first := types[0]
		d.Types[tn] = first
		if len(types) > 1 {
			for i, ty := range types[1:] {
				found := false
				for j := 0; j < i+1; j++ {
					if ty.IsEquivalent(types[j]) {
						found = true
						break
					}
				}
				if !found {
					newName := d.uniqueTypeName(tn)
					ty.TypeName = newName
					d.Types[newName] = ty
					d.TypeNames = append(d.TypeNames, newName)
				}
			}
		}
	}
	idx = 0
	resourceNames := make([]string, len(d.Resources))
	for n := range d.Resources {
		resourceNames[idx] = n
		idx++
	}
	sort.Strings(resourceNames)
	d.ResourceNames = resourceNames
	typeNames := make([]string, len(d.Types))
	idx = 0
	for tn := range d.Types {
		typeNames[idx] = tn
		idx++
	}
	sort.Strings(typeNames)
	d.TypeNames = typeNames
}
func (d *APIDescriptor) uniqueTypeName(prefix string) string {
	u := fmt.Sprintf("%s%d", prefix, 2)
	taken := false
	for _, tn := range d.TypeNames {
		if tn == u {
			taken = true
			break
		}
	}
	idx := 3
	for taken {
		u = fmt.Sprintf("%s%d", prefix, idx)
		taken = false
		for _, tn := range d.TypeNames {
			if tn == u {
				taken = true
				break
			}
		}
		if taken {
			idx++
		}
	}
	return u
}
type Resource struct {
	Name        string             
	ClientName  string             
	Description string             
	Attributes  []*Attribute       
	Actions     []*Action          
	LocatorFunc string             
	Identifier  string             
	Links       map[string]string  
}
type Attribute struct {
	Name      string  
	FieldName string  
	FieldType string  
}
type Action struct {
	Name              string          
	MethodName        string          
	Description       string          
	ResourceName      string          
	PathPatterns      []*PathPattern  
	Payload           DataType        
	Params            []*ActionParam  
	LeafParams        []*ActionParam  
	Return            string          
	ReturnLocation    bool            
	PathParamNames    []string        
	QueryParamNames   []string        
	PayloadParamNames []string        
	HeaderParamNames  []string        
}
func (a *Action) MandatoryParams() []*ActionParam {
	m := make([]*ActionParam, len(a.Params))
	i := 0
	for _, p := range a.Params {
		if p.Mandatory {
			m[i] = p
			i++
		}
	}
	return m[:i]
}