package mounttable

import (
	"container/list"
	"io"
	"strings"
	"time"

	"veyron/lib/glob"

	"veyron2/naming"
	"veyron2/vlog"
)

const mountTableGlobReplyStreamLength = 100

// globAtServer performs a Glob at a single server and adds any results to the list.  Paramters are:
//   server    the server to perform the glob at.  This may include multiple names for different
//             instances of the same server.
//   pelems    the pattern to match relative to the mounted subtree.
//   l         the list to add results to.
//   recursive true to continue below the matched pattern
// We return a bool foundRoot which indicates whether the empty name "" was found on a target server.
func (ns *namespace) globAtServer(server *naming.MountEntry, pattern *glob.Glob, l *list.List) (bool, error) {
	pstr := pattern.String()
	foundRoot := false
	vlog.VI(2).Infof("globAtServer(%v, %v)", *server, pstr)

	var lastErr error
	// Trying each instance till we get one that works.
	for _, s := range server.Servers {
		mtServers, err := ns.ResolveToMountTable(s.Server)
		if err != nil {
			lastErr = err
			continue
		}

		for _, s := range mtServers {
			call, err := ns.rt.Client().StartCall(s, "Glob", []interface{}{pstr}, callTimeout)
			if err != nil {
				lastErr = err
				continue // try another instance
			}
			// At this point we have a server that can handle the RPC.
			for {
				var e mountEntry
				err := call.Recv(&e)
				if err == io.EOF {
					return foundRoot, nil
				}
				if err != nil {
					return foundRoot, err
				}
				if e.Name == "" {
					foundRoot = true
				}

				// Prefix the results with the path of the mount point.
				e.Name = naming.Join(server.Name, e.Name)

				// Convert to the ever so slightly different name.MountTable version of a MountEntry
				// and add it to the list.
				l.PushBack(&naming.MountEntry{
					Name:    e.Name,
					Servers: convertServers(e.Servers),
				})
			}

			if err := call.Finish(); err != nil {
				return foundRoot, err
			}
			return foundRoot, nil
		}
	}

	return foundRoot, lastErr
}

// Glob implements naming.MountTable.Glob.
func (ns *namespace) Glob(pattern string) (chan naming.MountEntry, error) {
	g, err := glob.Parse(pattern)
	if err != nil {
		return nil, err
	}

	// Add constant components of pattern to the servers' addresses and
	// to the prefix.
	var prefixElements []string
	prefixElements, g = g.SplitFixedPrefix()
	prefix := strings.Join(prefixElements, "/")

	// Start a thread to get the results and return the reply channel to the caller.
	servers := ns.rootName(prefix)
	if len(servers) == 0 {
		return nil, naming.ErrNoMountTable
	}
	reply := make(chan naming.MountEntry, 100)
	go ns.globLoop(servers, prefix, g, reply)
	return reply, nil
}

func convertStringsToServers(servers []string) (ret []naming.MountedServer) {
	for _, s := range servers {
		ret = append(ret, naming.MountedServer{Server: s})
	}
	return
}

// TODO(p):  I may just give up and assume that these two will always be the same.  For
// now this lets me make the RPC interface and the model's MountTable structs be arbitrarily
// different.
func convertServers(servers []mountedServer) []naming.MountedServer {
	var reply []naming.MountedServer
	for _, s := range servers {
		reply = append(reply, naming.MountedServer{Server: s.Server, TTL: time.Duration(s.TTL) * time.Second})
	}
	return reply
}

// depth returns the directory depth of a given name.
func depth(name string) int {
	name = strings.Trim(name, "/")
	if name == "" {
		return 0
	}
	return strings.Count(name, "/") - strings.Count(name, "//") + 1
}

func (ns *namespace) globLoop(servers []string, prefix string, pattern *glob.Glob, reply chan naming.MountEntry) {
	defer close(reply)

	l := list.New()
	l.PushBack(&naming.MountEntry{Name: "", Servers: convertStringsToServers(servers)})

	// Perform a breadth first search of the name graph.
	for le := l.Front(); le != nil; le = l.Front() {
		l.Remove(le)
		e := le.Value.(*naming.MountEntry)

		// Get the pattern elements below the current path.
		suffix := pattern.Split(depth(e.Name))

		// Perform a glob at the server.
		foundRoot, err := ns.globAtServer(e, suffix, l)

		// We want to output this entry if:
		// 1. There was a real error, we return whatever name gave us the error.
		if err != nil && !notAnMT(err) {
			x := *e
			x.Name = naming.Join(prefix, x.Name)
			x.Error = err
			reply <- x
		}

		// 2. The current name fullfills the pattern and further servers did not respond
		//    with "".  That is, we want to prefer foo/ over foo.
		if suffix.Len() == 0 && !foundRoot {
			x := *e
			x.Name = naming.Join(prefix, x.Name)
			reply <- x
		}
	}
}
