package gocode

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/token"
	"io"
	"reflect"
	"strings"
	"sync"
)

// decl.class
type decl_class int16

const (
	decl_invalid = decl_class(-1 + iota)

	// these are in a sorted order
	decl_const
	decl_func
	decl_import
	decl_package
	decl_type
	decl_var

	// this one serves as a temporary type for those methods that were
	// declared before their actual owner
	decl_methods_stub
)

func (this decl_class) String() string {
	switch this {
	case decl_invalid:
		return "PANIC"
	case decl_const:
		return "const"
	case decl_func:
		return "func"
	case decl_import:
		return "import"
	case decl_package:
		return "package"
	case decl_type:
		return "type"
	case decl_var:
		return "var"
	case decl_methods_stub:
		return "IF YOU SEE THIS, REPORT A BUG" // :D
	}
	panic("unreachable")
}

// decl.flags
type decl_flags int16

const (
	decl_foreign decl_flags = 1 << iota // imported from another package

	// means that the decl is a part of the range statement
	// its type is inferred in a special way
	decl_rangevar

	// decl of decl_type class is a type alias
	decl_alias

	// for preventing infinite recursions and loops in type inference code
	decl_visited
)

//-------------------------------------------------------------------------
// decl
//
// The most important data structure of the whole gocode project. It
// describes a single declaration and its children.
//-------------------------------------------------------------------------

type decl struct {
	// Name starts with '$' if the declaration describes an anonymous type.
	// '$s_%d' for anonymous struct types
	// '$i_%d' for anonymous interface types
	name  string
	typ   ast.Expr
	class decl_class
	flags decl_flags

	// functions for interface type, fields+methods for struct type
	children map[string]*decl

	// embedded types
	embedded []ast.Expr

	// if the type is unknown at AST building time, I'm using these
	value ast.Expr

	// if it's a multiassignment and the Value is a CallExpr, it is being set
	// to an index into the return value tuple, otherwise it's a -1
	value_index int

	// scope where this Decl was declared in (not its visibilty scope!)
	// Decl uses it for type inference
	scope *scope
}

func ast_decl_type(d ast.Decl) ast.Expr {
	switch t := d.(type) {
	case *ast.GenDecl:
		switch t.Tok {
		case token.CONST, token.VAR:
			c := t.Specs[0].(*ast.ValueSpec)
			return c.Type
		case token.TYPE:
			t := t.Specs[0].(*ast.TypeSpec)
			return t.Type
		}
	case *ast.FuncDecl:
		return t.Type
	}
	panic("unreachable")
}

func ast_decl_flags(d ast.Decl) decl_flags {
	switch t := d.(type) {
	case *ast.GenDecl:
		switch t.Tok {
		case token.TYPE:
			if isAliasTypeSpec(t.Specs[0].(*ast.TypeSpec)) {
				return decl_alias
			}
		}
	}
	return 0
}

func ast_decl_class(d ast.Decl) decl_class {
	switch t := d.(type) {
	case *ast.GenDecl:
		switch t.Tok {
		case token.VAR:
			return decl_var
		case token.CONST:
			return decl_const
		case token.TYPE:
			return decl_type
		}
	case *ast.FuncDecl:
		return decl_func
	}
	panic("unreachable")
}

func ast_decl_convertable(d ast.Decl) bool {
	switch t := d.(type) {
	case *ast.GenDecl:
		switch t.Tok {
		case token.VAR, token.CONST, token.TYPE:
			return true
		}
	case *ast.FuncDecl:
		return true
	}
	return false
}

func ast_field_list_to_decls(f *ast.FieldList, class decl_class, flags decl_flags, scope *scope, add_anonymous bool) map[string]*decl {
	count := 0
	for _, field := range f.List {
		count += len(field.Names)
	}

	decls := make(map[string]*decl, count)
	for _, field := range f.List {
		for _, name := range field.Names {
			if flags&decl_foreign != 0 && !ast.IsExported(name.Name) {
				continue
			}
			d := &decl{
				name:        name.Name,
				typ:         field.Type,
				class:       class,
				flags:       flags,
				scope:       scope,
				value_index: -1,
			}
			decls[d.name] = d
		}

		// add anonymous field as a child (type embedding)
		if class == decl_var && field.Names == nil && add_anonymous {
			tp := get_type_path(field.Type)
			if flags&decl_foreign != 0 && !ast.IsExported(tp.name) {
				continue
			}
			d := &decl{
				name:        tp.name,
				typ:         field.Type,
				class:       class,
				flags:       flags,
				scope:       scope,
				value_index: -1,
			}
			decls[d.name] = d
		}
	}
	return decls
}

func ast_field_list_to_embedded(f *ast.FieldList) []ast.Expr {
	count := 0
	for _, field := range f.List {
		if field.Names == nil || field.Names[0].Name == "?" {
			count++
		}
	}

	if count == 0 {
		return nil
	}

	embedded := make([]ast.Expr, count)
	i := 0
	for _, field := range f.List {
		if field.Names == nil || field.Names[0].Name == "?" {
			embedded[i] = field.Type
			i++
		}
	}

	return embedded
}

func ast_type_to_embedded(ty ast.Expr) []ast.Expr {
	switch t := ty.(type) {
	case *ast.StructType:
		return ast_field_list_to_embedded(t.Fields)
	case *ast.InterfaceType:
		return ast_field_list_to_embedded(t.Methods)
	}
	return nil
}

func ast_type_to_children(ty ast.Expr, flags decl_flags, scope *scope) map[string]*decl {
	switch t := ty.(type) {
	case *ast.StructType:
		return ast_field_list_to_decls(t.Fields, decl_var, flags, scope, true)
	case *ast.InterfaceType:
		return ast_field_list_to_decls(t.Methods, decl_func, flags, scope, false)
	}
	return nil
}

//-------------------------------------------------------------------------
// anonymous_id_gen
//
// ID generator for anonymous types (thread-safe)
//-------------------------------------------------------------------------

type anonymous_id_gen struct {
	sync.Mutex
	i int
}

func (a *anonymous_id_gen) gen() (id int) {
	a.Lock()
	defer a.Unlock()
	id = a.i
	a.i++
	return
}

var g_anon_gen anonymous_id_gen

//-------------------------------------------------------------------------

func check_for_anon_type(t ast.Expr, flags decl_flags, s *scope) ast.Expr {
	if t == nil {
		return nil
	}
	var name string

	switch t.(type) {
	case *ast.StructType:
		name = fmt.Sprintf("$s_%d", g_anon_gen.gen())
	case *ast.InterfaceType:
		name = fmt.Sprintf("$i_%d", g_anon_gen.gen())
	}

	if name != "" {
		anonymify_ast(t, flags, s)
		d := new_decl_full(name, decl_type, flags, t, nil, -1, s)
		s.add_named_decl(d)
		return ast.NewIdent(name)
	}
	return t
}

//-------------------------------------------------------------------------

func new_decl_full(name string, class decl_class, flags decl_flags, typ, v ast.Expr, vi int, s *scope) *decl {
	if name == "_" {
		return nil
	}
	d := new(decl)
	d.name = name
	d.class = class
	d.flags = flags
	d.typ = typ
	d.value = v
	d.value_index = vi
	d.scope = s
	d.children = ast_type_to_children(d.typ, flags, s)
	d.embedded = ast_type_to_embedded(d.typ)
	return d
}

func new_decl(name string, class decl_class, scope *scope) *decl {
	decl := new(decl)
	decl.name = name
	decl.class = class
	decl.value_index = -1
	decl.scope = scope
	return decl
}

func new_decl_var(name string, typ ast.Expr, value ast.Expr, vindex int, scope *scope) *decl {
	if name == "_" {
		return nil
	}
	decl := new(decl)
	decl.name = name
	decl.class = decl_var
	decl.typ = typ
	decl.value = value
	decl.value_index = vindex
	decl.scope = scope
	return decl
}

func method_of(d ast.Decl) string {
	if t, ok := d.(*ast.FuncDecl); ok {
		if t.Recv != nil && len(t.Recv.List) != 0 {
			switch t := t.Recv.List[0].Type.(type) {
			case *ast.StarExpr:
				if se, ok := t.X.(*ast.SelectorExpr); ok {
					return se.Sel.Name
				}
				if ident, ok := t.X.(*ast.Ident); ok {
					return ident.Name
				}
				return ""
			case *ast.Ident:
				return t.Name
			default:
				return ""
			}
		}
	}
	return ""
}

func (other *decl) deep_copy() *decl {
	d := new(decl)
	d.name = other.name
	d.class = other.class
	d.flags = other.flags
	d.typ = other.typ
	d.value = other.value
	d.value_index = other.value_index
	d.children = make(map[string]*decl, len(other.children))
	for key, value := range other.children {
		d.children[key] = value
	}
	if other.embedded != nil {
		d.embedded = make([]ast.Expr, len(other.embedded))
		copy(d.embedded, other.embedded)
	}
	d.scope = other.scope
	return d
}

func (d *decl) is_rangevar() bool {
	return d.flags&decl_rangevar != 0
}

func (d *decl) is_alias() bool {
	return d.flags&decl_alias != 0
}

func (d *decl) is_visited() bool {
	return d.flags&decl_visited != 0
}

func (d *decl) set_visited() {
	d.flags |= decl_visited
}

func (d *decl) clear_visited() {
	d.flags &^= decl_visited
}

func (d *decl) expand_or_replace(other *decl) {
	// expand only if it's a methods stub, otherwise simply keep it as is
	if d.class != decl_methods_stub && other.class != decl_methods_stub {
		return
	}

	if d.class == decl_methods_stub {
		d.typ = other.typ
		d.class = other.class
		d.flags = other.flags
	}

	if other.children != nil {
		for _, c := range other.children {
			d.add_child(c)
		}
	}

	if other.embedded != nil {
		d.embedded = other.embedded
		d.scope = other.scope
	}
}

func (d *decl) matches() bool {
	if strings.HasPrefix(d.name, "$") || d.class == decl_methods_stub {
		return false
	}
	return true
}

func (d *decl) pretty_print_type(out io.Writer, canonical_aliases map[string]string) {
	switch d.class {
	case decl_type:
		switch d.typ.(type) {
		case *ast.StructType:
			// TODO: not used due to anonymify?
			fmt.Fprintf(out, "struct")
		case *ast.InterfaceType:
			// TODO: not used due to anonymify?
			fmt.Fprintf(out, "interface")
		default:
			if d.typ != nil {
				pretty_print_type_expr(out, d.typ, canonical_aliases)
			}
		}
	case decl_var:
		if d.typ != nil {
			pretty_print_type_expr(out, d.typ, canonical_aliases)
		}
	case decl_func:
		pretty_print_type_expr(out, d.typ, canonical_aliases)
	}
}

func (d *decl) add_child(cd *decl) {
	if d.children == nil {
		d.children = make(map[string]*decl)
	}
	d.children[cd.name] = cd
}

func check_for_builtin_funcs(typ *ast.Ident, c *ast.CallExpr, scope *scope) (ast.Expr, *scope) {
	if strings.HasPrefix(typ.Name, "func(") {
		if t, ok := c.Fun.(*ast.Ident); ok {
			switch t.Name {
			case "new":
				if len(c.Args) > 0 {
					e := new(ast.StarExpr)
					e.X = c.Args[0]
					return e, scope
				}
			case "make":
				if len(c.Args) > 0 {
					return c.Args[0], scope
				}
			case "append":
				if len(c.Args) > 0 {
					t, scope, _ := infer_type(c.Args[0], scope, -1)
					return t, scope
				}
			case "complex":
				// TODO: fix it
				return ast.NewIdent("complex"), g_universe_scope
			case "closed":
				return ast.NewIdent("bool"), g_universe_scope
			case "cap":
				return ast.NewIdent("int"), g_universe_scope
			case "copy":
				return ast.NewIdent("int"), g_universe_scope
			case "len":
				return ast.NewIdent("int"), g_universe_scope
			}
			// TODO:
			// func recover() interface{}
			// func imag(c ComplexType) FloatType
			// func real(c ComplexType) FloatType
		}
	}
	return nil, nil
}

func func_return_type(f *ast.FuncType, index int) ast.Expr {
	if f.Results == nil {
		return nil
	}

	if index == -1 {
		return f.Results.List[0].Type
	}

	i := 0
	var field *ast.Field
	for _, field = range f.Results.List {
		n := 1
		if field.Names != nil {
			n = len(field.Names)
		}
		if i <= index && index < i+n {
			return field.Type
		}
		i += n
	}
	return nil
}

type type_path struct {
	pkg  string
	name string
}

func (tp *type_path) is_nil() bool {
	return tp.pkg == "" && tp.name == ""
}

// converts type expressions like:
// ast.Expr
// *ast.Expr
// $ast$go/ast.Expr
// to a path that can be used to lookup a type related Decl
func get_type_path(e ast.Expr) (r type_path) {
	if e == nil {
		return type_path{"", ""}
	}

	switch t := e.(type) {
	case *ast.Ident:
		r.name = t.Name
	case *ast.StarExpr:
		r = get_type_path(t.X)
	case *ast.SelectorExpr:
		if ident, ok := t.X.(*ast.Ident); ok {
			r.pkg = ident.Name
		}
		r.name = t.Sel.Name
	}
	return
}

func lookup_path(tp type_path, scope *scope) *decl {
	if tp.is_nil() {
		return nil
	}
	var decl *decl
	if tp.pkg != "" {
		decl = scope.lookup(tp.pkg)
		// return nil early if the package wasn't found but it's part
		// of the type specification
		if decl == nil {
			return nil
		}
	}

	if decl != nil {
		if tp.name != "" {
			return decl.find_child(tp.name)
		} else {
			return decl
		}
	}

	return scope.lookup(tp.name)
}

func lookup_pkg(tp type_path, scope *scope) string {
	if tp.is_nil() {
		return ""
	}
	if tp.pkg == "" {
		return ""
	}
	decl := scope.lookup(tp.pkg)
	if decl == nil {
		return ""
	}
	return decl.name
}

func type_to_decl(t ast.Expr, scope *scope) *decl {
	tp := get_type_path(t)
	d := lookup_path(tp, scope)
	if d != nil && d.class == decl_var {
		// weird variable declaration pointing to itself
		return nil
	}
	return d
}

func expr_to_decl(e ast.Expr, scope *scope) *decl {
	t, scope, _ := infer_type(e, scope, -1)
	return type_to_decl(t, scope)
}

//-------------------------------------------------------------------------
// Type inference
//-------------------------------------------------------------------------

type type_predicate func(ast.Expr) bool

func advance_to_type(pred type_predicate, v ast.Expr, scope *scope) (ast.Expr, *scope) {
	if pred(v) {
		return v, scope
	}

	decl := type_to_decl(v, scope)
	if decl == nil {
		return nil, nil
	}

	if decl.is_visited() {
		return nil, nil
	}
	decl.set_visited()
	defer decl.clear_visited()

	return advance_to_type(pred, decl.typ, decl.scope)
}

func advance_to_struct_or_interface(decl *decl) *decl {
	if decl.is_visited() {
		return nil
	}
	decl.set_visited()
	defer decl.clear_visited()

	if struct_interface_predicate(decl.typ) {
		return decl
	}

	decl = type_to_decl(decl.typ, decl.scope)
	if decl == nil {
		return nil
	}
	return advance_to_struct_or_interface(decl)
}

func struct_interface_predicate(v ast.Expr) bool {
	switch v.(type) {
	case *ast.StructType, *ast.InterfaceType:
		return true
	}
	return false
}

func chan_predicate(v ast.Expr) bool {
	_, ok := v.(*ast.ChanType)
	return ok
}

func index_predicate(v ast.Expr) bool {
	switch v.(type) {
	case *ast.ArrayType, *ast.MapType, *ast.Ellipsis:
		return true
	}
	return false
}

func star_predicate(v ast.Expr) bool {
	_, ok := v.(*ast.StarExpr)
	return ok
}

func func_predicate(v ast.Expr) bool {
	_, ok := v.(*ast.FuncType)
	return ok
}

func range_predicate(v ast.Expr) bool {
	switch t := v.(type) {
	case *ast.Ident:
		if t.Name == "string" {
			return true
		}
	case *ast.ArrayType, *ast.MapType, *ast.ChanType, *ast.Ellipsis:
		return true
	}
	return false
}

type anonymous_typer struct {
	flags decl_flags
	scope *scope
}

func (a *anonymous_typer) Visit(node ast.Node) ast.Visitor {
	switch t := node.(type) {
	case *ast.CompositeLit:
		t.Type = check_for_anon_type(t.Type, a.flags, a.scope)
	case *ast.MapType:
		t.Key = check_for_anon_type(t.Key, a.flags, a.scope)
		t.Value = check_for_anon_type(t.Value, a.flags, a.scope)
	case *ast.ArrayType:
		t.Elt = check_for_anon_type(t.Elt, a.flags, a.scope)
	case *ast.Ellipsis:
		t.Elt = check_for_anon_type(t.Elt, a.flags, a.scope)
	case *ast.ChanType:
		t.Value = check_for_anon_type(t.Value, a.flags, a.scope)
	case *ast.Field:
		t.Type = check_for_anon_type(t.Type, a.flags, a.scope)
	case *ast.CallExpr:
		t.Fun = check_for_anon_type(t.Fun, a.flags, a.scope)
	case *ast.ParenExpr:
		t.X = check_for_anon_type(t.X, a.flags, a.scope)
	case *ast.StarExpr:
		t.X = check_for_anon_type(t.X, a.flags, a.scope)
	case *ast.GenDecl:
		switch t.Tok {
		case token.VAR:
			for _, s := range t.Specs {
				vs := s.(*ast.ValueSpec)
				vs.Type = check_for_anon_type(vs.Type, a.flags, a.scope)
			}
		}
	}
	return a
}

func anonymify_ast(node ast.Node, flags decl_flags, scope *scope) {
	v := anonymous_typer{flags, scope}
	ast.Walk(&v, node)
}

// RETURNS:
// 	- type expression which represents a full name of a type
//	- bool whether a type expression is actually a type (used internally)
//	- scope in which type makes sense
func infer_type(v ast.Expr, scope *scope, index int) (ast.Expr, *scope, bool) {
	switch t := v.(type) {
	case *ast.CompositeLit:
		return t.Type, scope, true
	case *ast.Ident:
		if d := scope.lookup(t.Name); d != nil {
			if d.class == decl_package {
				return ast.NewIdent(t.Name), scope, false
			}
			typ, scope := d.infer_type()
			return typ, scope, d.class == decl_type
		}
	case *ast.UnaryExpr:
		switch t.Op {
		case token.AND:
			// &a makes sense only with values, don't even check for type
			it, s, _ := infer_type(t.X, scope, -1)
			if it == nil {
				break
			}

			e := new(ast.StarExpr)
			e.X = it
			return e, s, false
		case token.ARROW:
			// <-a makes sense only with values
			it, s, _ := infer_type(t.X, scope, -1)
			if it == nil {
				break
			}
			switch index {
			case -1, 0:
				it, s = advance_to_type(chan_predicate, it, s)
				return it.(*ast.ChanType).Value, s, false
			case 1:
				// technically it's a value, but in case of index == 1
				// it is always the last infer operation
				return ast.NewIdent("bool"), g_universe_scope, false
			}
		case token.ADD, token.NOT, token.SUB, token.XOR:
			it, s, _ := infer_type(t.X, scope, -1)
			if it == nil {
				break
			}
			return it, s, false
		}
	case *ast.BinaryExpr:
		switch t.Op {
		case token.EQL, token.NEQ, token.LSS, token.LEQ,
			token.GTR, token.GEQ, token.LOR, token.LAND:
			// logic operations, the result is a bool, always
			return ast.NewIdent("bool"), g_universe_scope, false
		case token.ADD, token.SUB, token.MUL, token.QUO, token.OR,
			token.XOR, token.REM, token.AND, token.AND_NOT:
			// try X, then Y, they should be the same anyway
			it, s, _ := infer_type(t.X, scope, -1)
			if it == nil {
				it, s, _ = infer_type(t.Y, scope, -1)
				if it == nil {
					break
				}
			}
			return it, s, false
		case token.SHL, token.SHR:
			// try only X for shifts, Y is always uint
			it, s, _ := infer_type(t.X, scope, -1)
			if it == nil {
				break
			}
			return it, s, false
		}
	case *ast.IndexExpr:
		// something[another] always returns a value and it works on a value too
		it, s, _ := infer_type(t.X, scope, -1)
		if it == nil {
			break
		}
		it, s = advance_to_type(index_predicate, it, s)
		switch t := it.(type) {
		case *ast.ArrayType:
			return t.Elt, s, false
		case *ast.Ellipsis:
			return t.Elt, s, false
		case *ast.MapType:
			switch index {
			case -1, 0:
				return t.Value, s, false
			case 1:
				return ast.NewIdent("bool"), g_universe_scope, false
			}
		}
	case *ast.SliceExpr:
		// something[start : end] always returns a value
		it, s, _ := infer_type(t.X, scope, -1)
		if it == nil {
			break
		}
		it, s = advance_to_type(index_predicate, it, s)
		switch t := it.(type) {
		case *ast.ArrayType:
			e := new(ast.ArrayType)
			e.Elt = t.Elt
			return e, s, false
		}
	case *ast.StarExpr:
		it, s, is_type := infer_type(t.X, scope, -1)
		if it == nil {
			break
		}
		if is_type {
			// if it's a type, add * modifier, make it a 'pointer of' type
			e := new(ast.StarExpr)
			e.X = it
			return e, s, true
		} else {
			it, s := advance_to_type(star_predicate, it, s)
			if se, ok := it.(*ast.StarExpr); ok {
				return se.X, s, false
			}
		}
	case *ast.CallExpr:
		// this is a function call or a type cast:
		// myFunc(1,2,3) or int16(myvar)
		it, s, is_type := infer_type(t.Fun, scope, -1)
		if it == nil {
			break
		}

		if is_type {
			// a type cast
			return it, scope, false
		} else {
			// it must be a function call or a built-in function
			// first check for built-in
			if ct, ok := it.(*ast.Ident); ok {
				ty, s := check_for_builtin_funcs(ct, t, scope)
				if ty != nil {
					return ty, s, false
				}
			}

			// then check for an ordinary function call
			it, scope = advance_to_type(func_predicate, it, s)
			if ct, ok := it.(*ast.FuncType); ok {
				return func_return_type(ct, index), s, false
			}
		}
	case *ast.ParenExpr:
		it, s, is_type := infer_type(t.X, scope, -1)
		if it == nil {
			break
		}
		return it, s, is_type
	case *ast.SelectorExpr:
		it, s, _ := infer_type(t.X, scope, -1)
		if it == nil {
			break
		}

		if d := type_to_decl(it, s); d != nil {
			c := d.find_child_and_in_embedded(t.Sel.Name)
			if c != nil {
				if c.class == decl_type {
					return t, scope, true
				} else {
					typ, s := c.infer_type()
					return typ, s, false
				}
			}
		}
	case *ast.FuncLit:
		// it's a value, but I think most likely we don't even care, cause we can only
		// call it, and CallExpr uses the type itself to figure out
		return t.Type, scope, false
	case *ast.TypeAssertExpr:
		if t.Type == nil {
			return infer_type(t.X, scope, -1)
		}
		switch index {
		case -1, 0:
			// converting a value to a different type, but return thing is a value
			it, _, _ := infer_type(t.Type, scope, -1)
			return it, scope, false
		case 1:
			return ast.NewIdent("bool"), g_universe_scope, false
		}
	case *ast.ArrayType, *ast.MapType, *ast.ChanType, *ast.Ellipsis,
		*ast.FuncType, *ast.StructType, *ast.InterfaceType:
		return t, scope, true
	default:
		_ = reflect.TypeOf(v)
		//fmt.Println(ty)
	}
	return nil, nil, false
}

// Uses Value, ValueIndex and Scope to infer the type of this
// declaration. Returns the type itself and the scope where this type
// makes sense.
func (d *decl) infer_type() (ast.Expr, *scope) {
	// special case for range vars
	if d.is_rangevar() {
		var scope *scope
		d.typ, scope = infer_range_type(d.value, d.scope, d.value_index)
		return d.typ, scope
	}

	switch d.class {
	case decl_package:
		// package is handled specially in inferType
		return nil, nil
	case decl_type:
		return ast.NewIdent(d.name), d.scope
	}

	// shortcut
	if d.typ != nil && d.value == nil {
		return d.typ, d.scope
	}

	// prevent loops
	if d.is_visited() {
		return nil, nil
	}
	d.set_visited()
	defer d.clear_visited()

	var scope *scope
	d.typ, scope, _ = infer_type(d.value, d.scope, d.value_index)
	return d.typ, scope
}

func (d *decl) type_dealias() *decl {
	if d.is_visited() {
		return nil
	}
	d.set_visited()
	defer d.clear_visited()

	dd := type_to_decl(d.typ, d.scope)
	if dd != nil && dd.is_alias() {
		return dd.type_dealias()
	}
	return dd
}

func (d *decl) find_child(name string) *decl {
	// type aliases don't really have any children on their own, but they
	// point to a different type, let's try to find one
	if d.is_alias() {
		dd := d.type_dealias()
		if dd != nil {
			return dd.find_child(name)
		}

		// note that type alias can also point to a type literal, something like
		// type A = struct { A int }
		// in this case we rely on "advance_to_struct_or_interface" below
	}

	if d.children != nil {
		if c, ok := d.children[name]; ok {
			return c
		}
	}

	decl := advance_to_struct_or_interface(d)
	if decl != nil && decl != d {
		if d.is_visited() {
			return nil
		}
		d.set_visited()
		defer d.clear_visited()

		return decl.find_child(name)
	}
	return nil
}

func (d *decl) find_child_and_in_embedded(name string) *decl {
	if d == nil {
		return nil
	}

	c := d.find_child(name)
	if c == nil {
		for _, e := range d.embedded {
			typedecl := type_to_decl(e, d.scope)
			c = typedecl.find_child_and_in_embedded(name)
			if c != nil {
				break
			}
		}
	}
	return c
}

// Special type inference for range statements.
// [int], [int] := range [string]
// [int], [value] := range [slice or array]
// [key], [value] := range [map]
// [value], [nil] := range [chan]
func infer_range_type(e ast.Expr, sc *scope, valueindex int) (ast.Expr, *scope) {
	t, s, _ := infer_type(e, sc, -1)
	t, s = advance_to_type(range_predicate, t, s)
	if t != nil {
		var t1, t2 ast.Expr
		var s1, s2 *scope
		s1 = s
		s2 = s

		switch t := t.(type) {
		case *ast.Ident:
			// string
			if t.Name == "string" {
				t1 = ast.NewIdent("int")
				t2 = ast.NewIdent("rune")
				s1 = g_universe_scope
				s2 = g_universe_scope
			} else {
				t1, t2 = nil, nil
			}
		case *ast.ArrayType:
			t1 = ast.NewIdent("int")
			s1 = g_universe_scope
			t2 = t.Elt
		case *ast.Ellipsis:
			t1 = ast.NewIdent("int")
			s1 = g_universe_scope
			t2 = t.Elt
		case *ast.MapType:
			t1 = t.Key
			t2 = t.Value
		case *ast.ChanType:
			t1 = t.Value
			t2 = nil
		default:
			t1, t2 = nil, nil
		}

		switch valueindex {
		case 0:
			return t1, s1
		case 1:
			return t2, s2
		}
	}
	return nil, nil
}

//-------------------------------------------------------------------------
// Pretty printing
//-------------------------------------------------------------------------

func get_array_len(e ast.Expr) string {
	switch t := e.(type) {
	case *ast.BasicLit:
		return string(t.Value)
	case *ast.Ellipsis:
		return "..."
	}
	return ""
}

func pretty_print_type_expr(out io.Writer, e ast.Expr, canonical_aliases map[string]string) {
	switch t := e.(type) {
	case *ast.StarExpr:
		fmt.Fprintf(out, "*")
		pretty_print_type_expr(out, t.X, canonical_aliases)
	case *ast.Ident:
		if strings.HasPrefix(t.Name, "$") {
			// beautify anonymous types
			switch t.Name[1] {
			case 's':
				fmt.Fprintf(out, "struct")
			case 'i':
				// ok, in most cases anonymous interface is an
				// empty interface, I'll just pretend that
				// it's always true
				fmt.Fprintf(out, "interface{}")
			}
		} else if !*g_debug && strings.HasPrefix(t.Name, "!") {
			// these are full package names for disambiguating and pretty
			// printing packages within packages, e.g.
			// !go/ast!ast vs. !github.com/nsf/my/ast!ast
			// another ugly hack, if people are punished in hell for ugly hacks
			// I'm screwed...
			emarkIdx := strings.LastIndex(t.Name, "!")
			path := t.Name[1:emarkIdx]
			alias := canonical_aliases[path]
			if alias == "" {
				alias = t.Name[emarkIdx+1:]
			}
			fmt.Fprintf(out, alias)
		} else {
			fmt.Fprintf(out, t.Name)
		}
	case *ast.ArrayType:
		al := ""
		if t.Len != nil {
			al = get_array_len(t.Len)
		}
		if al != "" {
			fmt.Fprintf(out, "[%s]", al)
		} else {
			fmt.Fprintf(out, "[]")
		}
		pretty_print_type_expr(out, t.Elt, canonical_aliases)
	case *ast.SelectorExpr:
		pretty_print_type_expr(out, t.X, canonical_aliases)
		fmt.Fprintf(out, ".%s", t.Sel.Name)
	case *ast.FuncType:
		fmt.Fprintf(out, "func(")
		pretty_print_func_field_list(out, t.Params, canonical_aliases)
		fmt.Fprintf(out, ")")

		buf := bytes.NewBuffer(make([]byte, 0, 256))
		nresults := pretty_print_func_field_list(buf, t.Results, canonical_aliases)
		if nresults > 0 {
			results := buf.String()
			if strings.IndexAny(results, ", ") != -1 {
				results = "(" + results + ")"
			}
			fmt.Fprintf(out, " %s", results)
		}
	case *ast.MapType:
		fmt.Fprintf(out, "map[")
		pretty_print_type_expr(out, t.Key, canonical_aliases)
		fmt.Fprintf(out, "]")
		pretty_print_type_expr(out, t.Value, canonical_aliases)
	case *ast.InterfaceType:
		fmt.Fprintf(out, "interface{}")
	case *ast.Ellipsis:
		fmt.Fprintf(out, "...")
		pretty_print_type_expr(out, t.Elt, canonical_aliases)
	case *ast.StructType:
		fmt.Fprintf(out, "struct")
	case *ast.ChanType:
		switch t.Dir {
		case ast.RECV:
			fmt.Fprintf(out, "<-chan ")
		case ast.SEND:
			fmt.Fprintf(out, "chan<- ")
		case ast.SEND | ast.RECV:
			fmt.Fprintf(out, "chan ")
		}
		pretty_print_type_expr(out, t.Value, canonical_aliases)
	case *ast.ParenExpr:
		fmt.Fprintf(out, "(")
		pretty_print_type_expr(out, t.X, canonical_aliases)
		fmt.Fprintf(out, ")")
	case *ast.BadExpr:
		// TODO: probably I should check that in a separate function
		// and simply discard declarations with BadExpr as a part of their
		// type
	default:
		// the element has some weird type, just ignore it
	}
}

func pretty_print_func_field_list(out io.Writer, f *ast.FieldList, canonical_aliases map[string]string) int {
	count := 0
	if f == nil {
		return count
	}
	for i, field := range f.List {
		// names
		if field.Names != nil {
			hasNonblank := false
			for j, name := range field.Names {
				if name.Name != "?" {
					hasNonblank = true
					fmt.Fprintf(out, "%s", name.Name)
					if j != len(field.Names)-1 {
						fmt.Fprintf(out, ", ")
					}
				}
				count++
			}
			if hasNonblank {
				fmt.Fprintf(out, " ")
			}
		} else {
			count++
		}

		// type
		pretty_print_type_expr(out, field.Type, canonical_aliases)

		// ,
		if i != len(f.List)-1 {
			fmt.Fprintf(out, ", ")
		}
	}
	return count
}

func ast_decl_names(d ast.Decl) []*ast.Ident {
	var names []*ast.Ident

	switch t := d.(type) {
	case *ast.GenDecl:
		switch t.Tok {
		case token.CONST:
			c := t.Specs[0].(*ast.ValueSpec)
			names = make([]*ast.Ident, len(c.Names))
			for i, name := range c.Names {
				names[i] = name
			}
		case token.TYPE:
			t := t.Specs[0].(*ast.TypeSpec)
			names = make([]*ast.Ident, 1)
			names[0] = t.Name
		case token.VAR:
			v := t.Specs[0].(*ast.ValueSpec)
			names = make([]*ast.Ident, len(v.Names))
			for i, name := range v.Names {
				names[i] = name
			}
		}
	case *ast.FuncDecl:
		names = make([]*ast.Ident, 1)
		names[0] = t.Name
	}

	return names
}

func ast_decl_values(d ast.Decl) []ast.Expr {
	// TODO: CONST values here too
	switch t := d.(type) {
	case *ast.GenDecl:
		switch t.Tok {
		case token.VAR:
			v := t.Specs[0].(*ast.ValueSpec)
			if v.Values != nil {
				return v.Values
			}
		}
	}
	return nil
}

func ast_decl_split(d ast.Decl) []ast.Decl {
	var decls []ast.Decl
	if t, ok := d.(*ast.GenDecl); ok {
		decls = make([]ast.Decl, len(t.Specs))
		for i, s := range t.Specs {
			decl := new(ast.GenDecl)
			*decl = *t
			decl.Specs = make([]ast.Spec, 1)
			decl.Specs[0] = s
			decls[i] = decl
		}
	} else {
		decls = make([]ast.Decl, 1)
		decls[0] = d
	}
	return decls
}

//-------------------------------------------------------------------------
// decl_pack
//-------------------------------------------------------------------------

type decl_pack struct {
	names  []*ast.Ident
	typ    ast.Expr
	values []ast.Expr
}

type foreach_decl_struct struct {
	decl_pack
	decl ast.Decl
}

func (f *decl_pack) value(i int) ast.Expr {
	if f.values == nil {
		return nil
	}
	if len(f.values) > 1 {
		return f.values[i]
	}
	return f.values[0]
}

func (f *decl_pack) value_index(i int) (v ast.Expr, vi int) {
	// default: nil value
	v = nil
	vi = -1

	if f.values != nil {
		// A = B, if there is only one name, the value is solo too
		if len(f.names) == 1 {
			return f.values[0], -1
		}

		if len(f.values) > 1 {
			// in case if there are multiple values, it's a usual
			// multiassignment
			if i >= len(f.values) {
				i = len(f.values) - 1
			}
			v = f.values[i]
		} else {
			// in case if there is one value, but many names, it's
			// a tuple unpack.. use index here
			v = f.values[0]
			vi = i
		}
	}
	return
}

func (f *decl_pack) type_value_index(i int) (ast.Expr, ast.Expr, int) {
	if f.typ != nil {
		// If there is a type, we don't care about value, just return the type
		// and zero value.
		return f.typ, nil, -1
	}

	// And otherwise we simply return nil type and a valid value for later inferring.
	v, vi := f.value_index(i)
	return nil, v, vi
}

type foreach_decl_func func(data *foreach_decl_struct)

func foreach_decl(decl ast.Decl, do foreach_decl_func) {
	decls := ast_decl_split(decl)
	var data foreach_decl_struct
	for _, decl := range decls {
		if !ast_decl_convertable(decl) {
			continue
		}
		data.names = ast_decl_names(decl)
		data.typ = ast_decl_type(decl)
		data.values = ast_decl_values(decl)
		data.decl = decl

		do(&data)
	}
}

//-------------------------------------------------------------------------
// Built-in declarations
//-------------------------------------------------------------------------

var g_universe_scope = new_scope(nil)

func init() {
	builtin := ast.NewIdent("built-in")

	add_type := func(name string) {
		d := new_decl(name, decl_type, g_universe_scope)
		d.typ = builtin
		g_universe_scope.add_named_decl(d)
	}
	add_type("bool")
	add_type("byte")
	add_type("complex64")
	add_type("complex128")
	add_type("float32")
	add_type("float64")
	add_type("int8")
	add_type("int16")
	add_type("int32")
	add_type("int64")
	add_type("string")
	add_type("uint8")
	add_type("uint16")
	add_type("uint32")
	add_type("uint64")
	add_type("int")
	add_type("uint")
	add_type("uintptr")
	add_type("rune")

	add_const := func(name string) {
		d := new_decl(name, decl_const, g_universe_scope)
		d.typ = builtin
		g_universe_scope.add_named_decl(d)
	}
	add_const("true")
	add_const("false")
	add_const("iota")
	add_const("nil")

	add_func := func(name, typ string) {
		d := new_decl(name, decl_func, g_universe_scope)
		d.typ = ast.NewIdent(typ)
		g_universe_scope.add_named_decl(d)
	}
	add_func("append", "func([]type, ...type) []type")
	add_func("cap", "func(container) int")
	add_func("close", "func(channel)")
	add_func("complex", "func(real, imag) complex")
	add_func("copy", "func(dst, src)")
	add_func("delete", "func(map[typeA]typeB, typeA)")
	add_func("imag", "func(complex)")
	add_func("len", "func(container) int")
	add_func("make", "func(type, len[, cap]) type")
	add_func("new", "func(type) *type")
	add_func("panic", "func(interface{})")
	add_func("print", "func(...interface{})")
	add_func("println", "func(...interface{})")
	add_func("real", "func(complex)")
	add_func("recover", "func() interface{}")

	// built-in error interface
	d := new_decl("error", decl_type, g_universe_scope)
	d.typ = &ast.InterfaceType{}
	d.children = make(map[string]*decl)
	d.children["Error"] = new_decl("Error", decl_func, g_universe_scope)
	d.children["Error"].typ = &ast.FuncType{
		Results: &ast.FieldList{
			List: []*ast.Field{
				{
					Type: ast.NewIdent("string"),
				},
			},
		},
	}
	g_universe_scope.add_named_decl(d)
}
