// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package compile

import (
	"v.io/v23/vdl"
	"v.io/x/lib/toposort"
	"v.io/x/ref/lib/vdl/parse"
)

// compileInterfaces is the "entry point" to the rest of this file.  It takes
// the interfaces defined in pfiles and compiles them into Interfaces in pkg.
func compileInterfaces(pkg *Package, pfiles []*parse.File, env *Env) {
	id := ifaceDefiner{pkg, pfiles, env, make(map[string]*ifaceBuilder)}
	if id.Declare(); !env.Errors.IsEmpty() {
		return
	}
	id.SortAndDefine()
}

// ifaceDefiner defines interfaces in a package.  This is split into two phases:
// 1) Declare ensures local interface references can be resolved.
// 2) SortAndDefine sorts in dependency order, and evaluates and defines each
//    const.
//
// It holds a builders map from interface name to ifaceBuilder, where the
// ifaceBuilder is responsible for compiling and defining a single interface.
type ifaceDefiner struct {
	pkg      *Package
	pfiles   []*parse.File
	env      *Env
	builders map[string]*ifaceBuilder
}

type ifaceBuilder struct {
	def  *Interface
	pdef *parse.Interface
}

func printIfaceBuilderName(ibuilder interface{}) string {
	return ibuilder.(*ifaceBuilder).def.Name
}

// Declare creates builders for each interface defined in the package.
func (id ifaceDefiner) Declare() {
	for ix := range id.pkg.Files {
		file, pfile := id.pkg.Files[ix], id.pfiles[ix]
		for _, pdef := range pfile.Interfaces {
			export, err := validIdent(pdef.Name, reservedNormal)
			if err != nil {
				id.env.prefixErrorf(file, pdef.Pos, err, "interface %s invalid name", pdef.Name)
				continue // keep going to catch more errors
			}
			detail := identDetail("interface", file, pdef.Pos)
			if err := file.DeclareIdent(pdef.Name, detail); err != nil {
				id.env.prefixErrorf(file, pdef.Pos, err, "interface %s name conflict", pdef.Name)
				continue
			}
			def := &Interface{NamePos: NamePos(pdef.NamePos), Exported: export, File: file}
			id.builders[pdef.Name] = &ifaceBuilder{def, pdef}
		}
	}
}

// Sort and define interfaces.  We sort by dependencies on other interfaces in
// this package.  The sorting is to ensure there are no cycles.
func (id ifaceDefiner) SortAndDefine() {
	// Populate sorter with dependency information.  The sorting ensures that the
	// list of interfaces within each file is topologically sorted, and also
	// deterministic; in the absence of interface embeddings, interfaces are
	// listed in the same order they were defined in the parsed files.
	var sorter toposort.Sorter
	for _, pfile := range id.pfiles {
		for _, pdef := range pfile.Interfaces {
			b := id.builders[pdef.Name]
			sorter.AddNode(b)
			for _, dep := range id.getLocalDeps(b) {
				sorter.AddEdge(b, dep)
			}
		}
	}
	// Sort and check for cycles.
	sorted, cycles := sorter.Sort()
	if len(cycles) > 0 {
		cycleStr := toposort.DumpCycles(cycles, printIfaceBuilderName)
		first := cycles[0][0].(*ifaceBuilder)
		id.env.Errorf(first.def.File, first.def.Pos, "package %v has cyclic interfaces: %v", id.pkg.Name, cycleStr)
		return
	}
	// Define all interfaces.  Since we add the interfaces as we go and evaluate
	// in topological order, dependencies are guaranteed to be resolvable when we
	// get around to defining the interfaces that embed on them.
	for _, ibuilder := range sorted {
		b := ibuilder.(*ifaceBuilder)
		id.define(b)
		addIfaceDef(b.def)
	}
}

// addIfaceDef updates our various structures to add a new interface.
func addIfaceDef(def *Interface) {
	def.File.Interfaces = append(def.File.Interfaces, def)
	def.File.Package.ifaceDefs[def.Name] = def
}

// getLocalDeps returns the list of interface dependencies for b that are in
// this package.
func (id ifaceDefiner) getLocalDeps(b *ifaceBuilder) (deps []*ifaceBuilder) {
	for _, pe := range b.pdef.Embeds {
		// Embeddings of other interfaces in this package are all we care about.
		if dep := id.builders[pe.Name]; dep != nil {
			deps = append(deps, dep)
		}
	}
	return
}

func (id ifaceDefiner) define(b *ifaceBuilder) {
	id.defineEmbeds(b)
	id.defineMethods(b)
}

func (id ifaceDefiner) defineEmbeds(b *ifaceBuilder) {
	// TODO(toddw): Check for duplicate methods.
	def, file := b.def, b.def.File
	seen := make(map[string]*parse.NamePos)
	for _, pe := range b.pdef.Embeds {
		if dup := seen[pe.Name]; dup != nil {
			id.env.Errorf(file, pe.Pos, "interface %s duplicate embedding (previous at %s)", pe.Name, dup.Pos)
			continue // keep going to catch more errors
		}
		seen[pe.Name] = pe
		// Resolve the embedded interface.
		embed, matched := id.env.ResolveInterface(pe.Name, file)
		if embed == nil {
			id.env.Errorf(file, pe.Pos, "interface %s undefined", pe.Name)
			continue // keep going to catch more errors
		}
		if len(matched) < len(pe.Name) {
			id.env.Errorf(file, pe.Pos, "interface %s invalid (%s unmatched)", pe.Name, pe.Name[len(matched):])
			continue // keep going to catch more errors
		}
		def.Embeds = append(def.Embeds, embed)
	}
}

func (id ifaceDefiner) defineMethods(b *ifaceBuilder) {
	def, file := b.def, b.def.File
	seen := make(map[string]*parse.Method)
	for _, pm := range b.pdef.Methods {
		if dup := seen[pm.Name]; dup != nil {
			id.env.Errorf(file, pm.Pos, "method %s redefined (previous at %s)", pm.Name, dup.Pos)
			continue // keep going to catch more errors
		}
		seen[pm.Name] = pm
		if err := validExportedIdent(pm.Name, reservedFirstRuneLower); err != nil {
			id.env.Errorf(file, pm.Pos, "method %s name (%s)", pm.Name, err)
			continue // keep going to catch more errors
		}
		m := &Method{NamePos: NamePos(pm.NamePos)}
		m.InArgs = id.defineArgs(in, m.NamePos, pm.InArgs, file)
		m.OutArgs = id.defineArgs(out, m.NamePos, pm.OutArgs, file)
		m.InStream = id.defineStreamType(pm.InStream, file)
		m.OutStream = id.defineStreamType(pm.OutStream, file)
		m.Tags = id.defineTags(pm.Tags, file)
		def.Methods = append(def.Methods, m)
	}
}

type inout string

const (
	in  inout = "in"
	out inout = "out"
)

func (id ifaceDefiner) defineArgs(io inout, method NamePos, pargs []*parse.Field, file *File) (args []*Field) {
	seen := make(map[string]*parse.Field)
	for _, parg := range pargs {
		if dup := seen[parg.Name]; dup != nil && parg.Name != "" {
			id.env.Errorf(file, parg.Pos, "method %s arg %s duplicate name (previous at %s)", method.Name, parg.Name, dup.Pos)
			continue // keep going to catch more errors
		}
		seen[parg.Name] = parg
		switch {
		case io == in && parg.Name == "":
			id.env.Errorf(file, parg.Pos, "method %s in-arg unnamed (must name all in-args)", method.Name)
			continue // keep going to catch more errors
		case io == out && len(pargs) > 1 && parg.Name == "":
			id.env.Errorf(file, parg.Pos, "method %s out-arg unnamed (must name all out-args if there are more than 1)", method.Name)
			continue // keep going to catch more errors
		}
		if parg.Name != "" {
			if _, err := validIdent(parg.Name, reservedFirstRuneLower); err != nil {
				id.env.prefixErrorf(file, parg.Pos, err, "method %s invalid arg %s", method.Name, parg.Name)
				continue // keep going to catch more errors
			}
		}
		arg := &Field{NamePos(parg.NamePos), compileType(parg.Type, file, id.env)}
		args = append(args, arg)
	}
	return
}

func (id ifaceDefiner) defineStreamType(ptype parse.Type, file *File) *vdl.Type {
	if ptype == nil {
		return nil
	}
	if tn, ok := ptype.(*parse.TypeNamed); ok && tn.Name == "_" {
		// Special-case the _ placeholder, which means there's no stream type.
		return nil
	}
	return compileType(ptype, file, id.env)
}

func (id ifaceDefiner) defineTags(ptags []parse.ConstExpr, file *File) (tags []*vdl.Value) {
	for _, ptag := range ptags {
		if tag := compileConst("tag", nil, ptag, file, id.env); tag != nil {
			tags = append(tags, tag)
		}
	}
	return
}
