gen/api15gen/param_analyzer.go
func (p *ParamAnalyzer) Analyze() {
	// Order params using their length so "foo[bar]" is analyzed before "foo"
	params := p.rawParams
	paths := make([]string, len(params))
	i := 0
	for n := range params {
		paths[i] = n
		i++
	}
	sort.Strings(paths)
	sort.Sort(ByReverseLength(paths))
	rawLeafParams := []string{}
	for _, p := range paths {
		hasLeaf := false
		for _, r := range rawLeafParams {
			if strings.HasSuffix(r, "]") && strings.HasPrefix(r, p) {
				hasLeaf = true
				break
			}
		}
		if hasLeaf {
			continue
		}
		rawLeafParams = append(rawLeafParams, p)
	}
	sort.Strings(rawLeafParams)
	p.leafParamNames = rawLeafParams

	// Iterate through all params and build corresponding ActionParam structs
	p.parsed = map[string]*gen.ActionParam{}
	top := map[string]*gen.ActionParam{}
	for _, path := range paths {
		if strings.HasSuffix(path, "[*]") {
			// Cheat a little bit - there a couple of cases where parent type is
			// Hash instead of Enumerable, make that enumerable everywhere
			// There are also cases where there's no parent path, fix that up also
			matches := parentPathRegexp.FindStringSubmatch(path)
			if hashParam, ok := params[matches[1]].(map[string]interface{}); ok {
				hashParam["class"] = "Enumerable"
			} else {
				// Create parent
				rawParams := map[string]interface{}{}
				parentPath := matches[1]
				p.parsed[parentPath] = p.newParam(parentPath, rawParams,
					new(gen.EnumerableDataType))
				if parentPathRegexp.FindStringSubmatch(parentPath) == nil {
					top[parentPath] = p.parsed[parentPath]
				}
			}
			continue
		}
		var child *gen.ActionParam
		origPath := path
		origParam := params[path].(map[string]interface{})
		matches := parentPathRegexp.FindStringSubmatch(path)
		isTop := (matches == nil)
		if prev, ok := p.parsed[path]; ok {
			if isTop {
				top[path] = prev
			}
			continue
		}
		var branch []*gen.ActionParam
		for matches != nil {
			param := params[path].(map[string]interface{})
			parentPath := matches[1]
			var isArrayChild bool
			if strings.HasSuffix(parentPath, "[]") {
				isArrayChild = true
			}
			if parent, ok := p.parsed[parentPath]; ok {
				a, ok := parent.Type.(*gen.ArrayDataType)
				if ok {
					parent = a.ElemType
				}
				child = p.parseParam(path, param, child)
				if !parent.Mandatory {
					// Make required fields of optional hashes optional.
					child.Mandatory = false
				}
				branch = append(branch, child)
				if _, ok = parent.Type.(*gen.EnumerableDataType); !ok {
					o := parent.Type.(*gen.ObjectDataType)
					o.Fields = appendSorted(o.Fields, child)
					p.parsed[path] = child
				}
				break // No need to keep going back, we already have a parent
			} else {
				child = p.parseParam(path, param, child)
				branch = append(branch, child)
				p.parsed[path] = child
				if isArrayChild {
					// Generate array item as it's not listed explicitly in JSON
					itemPath := matches[1] + "[item]"
					typeName := p.typeName(matches[1])
					parent = p.newParam(itemPath, map[string]interface{}{},
						&gen.ObjectDataType{typeName, []*gen.ActionParam{child}})
					p.parsed[parentPath] = parent
					child = parent
					branch = append(branch, child)
					parentPath = parentPath[:len(parentPath)-2]
				}
			}
			path = parentPath
			matches = parentPathRegexp.FindStringSubmatch(path)
		}
		if isTop {
			if _, ok := p.parsed[path]; !ok {
				actionParam := p.parseParam(path, origParam, nil)
				p.parsed[path] = actionParam
			}
			top[path] = p.parsed[path]
		} else {
			matches := rootRegexp.FindStringSubmatch(origPath)
			rootPath := matches[1]
			if _, ok := p.parsed[rootPath]; !ok {
				p.parsed[rootPath] = p.parseParam(rootPath,
					params[rootPath].(map[string]interface{}), child)
			}
			actionParam, _ := p.parsed[rootPath]
			mandatory := actionParam.Mandatory
			if len(branch) > 0 {
				for i := len(branch) - 1; i >= 0; i-- {
					p := branch[i]
					if mandatory {
						if !p.Mandatory {
							mandatory = false
						}
					} else {
						p.Mandatory = false
					}
				}
			}
		}
	}
	// Now do a second pass on parsed params to generate their declarations
	p.ParamTypes = make(map[string]*gen.ObjectDataType)
	for _, param := range top {
		p.recordTypes(param.Type)
	}

	i = 0
	res := make([]*gen.ActionParam, len(top))
	for _, param := range top {
		res[i] = param
		i++
	}
	sort.Sort(gen.ByName(res))
	p.Params = res
}
func (p *ParamAnalyzer) Analyze() {
	// Order params using their length so "foo[bar]" is analyzed before "foo"
	params := p.rawParams
	paths := make([]string, len(params))
	i := 0
	for n := range params {
		paths[i] = n
		i++
	}
	sort.Strings(paths)
	sort.Sort(ByReverseLength(paths))
	rawLeafParams := []string{}
	for _, p := range paths {
		hasLeaf := false
		for _, r := range rawLeafParams {
			if strings.HasSuffix(r, "]") && strings.HasPrefix(r, p) {
				hasLeaf = true
				break
			}
		}
		if hasLeaf {
			continue
		}
		rawLeafParams = append(rawLeafParams, p)
	}
	sort.Strings(rawLeafParams)
	p.leafParamNames = rawLeafParams

	// Iterate through all params and build corresponding ActionParam structs
	p.parsed = map[string]*gen.ActionParam{}
	top := map[string]*gen.ActionParam{}
	for _, path := range paths {
		if strings.HasSuffix(path, "[*]") {
			// Cheat a little bit - there a couple of cases where parent type is
			// Hash instead of Enumerable, make that enumerable everywhere
			// There are also cases where there's no parent path, fix that up also
			matches := parentPathRegexp.FindStringSubmatch(path)
			if hashParam, ok := params[matches[1]].(map[string]interface{}); ok {
				hashParam["class"] = "Enumerable"
			} else {
				// Create parent
				rawParams := map[string]interface{}{}
				parentPath := matches[1]
				p.parsed[parentPath] = p.newParam(parentPath, rawParams,
					new(gen.EnumerableDataType))
				if parentPathRegexp.FindStringSubmatch(parentPath) == nil {
					top[parentPath] = p.parsed[parentPath]
				}
			}
			continue
		}
		var child *gen.ActionParam
		origPath := path
		origParam := params[path].(map[string]interface{})
		matches := parentPathRegexp.FindStringSubmatch(path)
		isTop := (matches == nil)
		if prev, ok := p.parsed[path]; ok {
			if isTop {
				top[path] = prev
			}
			continue
		}
		var branch []*gen.ActionParam
		for matches != nil {
			param := params[path].(map[string]interface{})
			parentPath := matches[1]
			var isArrayChild bool
			if strings.HasSuffix(parentPath, "[]") {
				isArrayChild = true
			}
			if parent, ok := p.parsed[parentPath]; ok {
				a, ok := parent.Type.(*gen.ArrayDataType)
				if ok {
					parent = a.ElemType
				}
				child = p.parseParam(path, param, child)
				if !parent.Mandatory {
					// Make required fields of optional hashes optional.
					child.Mandatory = false
				}
				branch = append(branch, child)
				if _, ok = parent.Type.(*gen.EnumerableDataType); !ok {
					o := parent.Type.(*gen.ObjectDataType)
					o.Fields = appendSorted(o.Fields, child)
					p.parsed[path] = child
				}
				break // No need to keep going back, we already have a parent
			} else {
				child = p.parseParam(path, param, child)
				branch = append(branch, child)
				p.parsed[path] = child
				if isArrayChild {
					// Generate array item as it's not listed explicitly in JSON
					itemPath := matches[1] + "[item]"
					typeName := p.typeName(matches[1])
					parent = p.newParam(itemPath, map[string]interface{}{},
						&gen.ObjectDataType{typeName, []*gen.ActionParam{child}})
					p.parsed[parentPath] = parent
					child = parent
					branch = append(branch, child)
					parentPath = parentPath[:len(parentPath)-2]
				}
			}
			path = parentPath
			matches = parentPathRegexp.FindStringSubmatch(path)
		}
		if isTop {
			if _, ok := p.parsed[path]; !ok {
				actionParam := p.parseParam(path, origParam, nil)
				p.parsed[path] = actionParam
			}
			top[path] = p.parsed[path]
		} else {
			matches := rootRegexp.FindStringSubmatch(origPath)
			rootPath := matches[1]
			if _, ok := p.parsed[rootPath]; !ok {
				p.parsed[rootPath] = p.parseParam(rootPath,
					params[rootPath].(map[string]interface{}), child)
			}
			actionParam, _ := p.parsed[rootPath]
			mandatory := actionParam.Mandatory
			if len(branch) > 0 {
				for i := len(branch) - 1; i >= 0; i-- {
					p := branch[i]
					if mandatory {
						if !p.Mandatory {
							mandatory = false
						}
					} else {
						p.Mandatory = false
					}
				}
			}
		}
	}
	// Now do a second pass on parsed params to generate their declarations
	p.ParamTypes = make(map[string]*gen.ObjectDataType)
	for _, param := range top {
		p.recordTypes(param.Type)
	}

	i = 0
	res := make([]*gen.ActionParam, len(top))
	for _, param := range top {
		res[i] = param
		i++
	}
	sort.Sort(gen.ByName(res))
	p.Params = res
}
// Analyze all parameters and categorize them
// Initialize all fields of ParamAnalyzer struct