// 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 mounttablelib

import (
	"container/list"
	"sync"
	"time"

	"v.io/v23/naming"
	vdltime "v.io/v23/vdlroot/time"

	"v.io/x/ref/lib/timekeeper"
)

type serverListManager struct {
	clock timekeeper.TimeKeeper
}

// server maintains the state of a single server.  Unless expires is refreshed before the
// time is reached, the entry will be removed.
type server struct {
	expires time.Time
	oa      string // object address of server
}

// serverList represents an ordered list of servers.
type serverList struct {
	sync.Mutex
	m *serverListManager
	l *list.List // contains entries of type *server
}

// newServerListManager starts a serverlist manager with a particular clock.
func newServerListManager(clock timekeeper.TimeKeeper) *serverListManager {
	return &serverListManager{clock: clock}
}

// SetServerListClock does what it says.
func (slm *serverListManager) setClock(clock timekeeper.TimeKeeper) {
	slm.clock = clock
}

// newServerList creates a synchronized list of servers.
func (slm *serverListManager) newServerList() *serverList {
	return &serverList{l: list.New(), m: slm}
}

func (sl *serverList) len() int {
	sl.Lock()
	defer sl.Unlock()
	return sl.l.Len()
}

func (sl *serverList) Front() *server {
	sl.Lock()
	defer sl.Unlock()
	return sl.l.Front().Value.(*server)
}

// add to the front of the list if not already in the list, otherwise,
// update the expiration time and move to the front of the list.  That
// way the most recently refreshed is always first.
func (sl *serverList) add(oa string, ttl time.Duration) {
	expires := sl.m.clock.Now().Add(ttl)
	sl.Lock()
	defer sl.Unlock()
	for e := sl.l.Front(); e != nil; e = e.Next() {
		s := e.Value.(*server)
		if s.oa == oa {
			s.expires = expires
			sl.l.MoveToFront(e)
			return
		}
	}
	s := &server{
		oa:      oa,
		expires: expires,
	}
	sl.l.PushFront(s) // innocent until proven guilty
}

// remove an element from the list.  Return the number of elements remaining.
func (sl *serverList) remove(oa string) int {
	sl.Lock()
	defer sl.Unlock()
	for e := sl.l.Front(); e != nil; e = e.Next() {
		s := e.Value.(*server)
		if s.oa == oa {
			sl.l.Remove(e)
			break
		}
	}
	return sl.l.Len()
}

// removeExpired removes any expired servers.
func (sl *serverList) removeExpired() (int, int) {
	sl.Lock()
	defer sl.Unlock()

	now := sl.m.clock.Now()
	var next *list.Element
	removed := 0
	for e := sl.l.Front(); e != nil; e = next {
		s := e.Value.(*server)
		next = e.Next()
		if now.After(s.expires) {
			sl.l.Remove(e)
			removed++
		}
	}
	return sl.l.Len(), removed
}

// copyToSlice returns the contents of the list as a slice of MountedServer.
func (sl *serverList) copyToSlice() []naming.MountedServer {
	sl.Lock()
	defer sl.Unlock()
	var slice []naming.MountedServer
	for e := sl.l.Front(); e != nil; e = e.Next() {
		s := e.Value.(*server)
		ms := naming.MountedServer{
			Server:   s.oa,
			Deadline: vdltime.Deadline{Time: s.expires},
		}
		slice = append(slice, ms)
	}
	return slice
}
