package protocol

import (
	"sync"
)

type ServerList struct {
	sync.RWMutex
	servers []*ServerSpec
}

func NewServerList() *ServerList {
	return &ServerList{}
}

func (this *ServerList) AddServer(server *ServerSpec) {
	this.Lock()
	defer this.Unlock()

	this.servers = append(this.servers, server)
}

func (this *ServerList) Size() uint32 {
	this.RLock()
	defer this.RUnlock()

	return uint32(len(this.servers))
}

func (this *ServerList) GetServer(idx uint32) *ServerSpec {
	this.RLock()
	defer this.RUnlock()

	for {
		if idx >= uint32(len(this.servers)) {
			return nil
		}

		server := this.servers[idx]
		if !server.IsValid() {
			this.RemoveServer(idx)
			continue
		}

		return server
	}
}

// @Private
func (this *ServerList) RemoveServer(idx uint32) {
	n := len(this.servers)
	this.servers[idx] = this.servers[n-1]
	this.servers = this.servers[:n-1]
}

type ServerPicker interface {
	PickServer() *ServerSpec
}

type RoundRobinServerPicker struct {
	sync.Mutex
	serverlist *ServerList
	nextIndex  uint32
}

func NewRoundRobinServerPicker(serverlist *ServerList) *RoundRobinServerPicker {
	return &RoundRobinServerPicker{
		serverlist: serverlist,
		nextIndex:  0,
	}
}

func (this *RoundRobinServerPicker) PickServer() *ServerSpec {
	this.Lock()
	defer this.Unlock()

	next := this.nextIndex
	server := this.serverlist.GetServer(next)
	if server == nil {
		next = 0
		server = this.serverlist.GetServer(0)
	}
	next++
	if next >= this.serverlist.Size() {
		next = 0
	}
	this.nextIndex = next

	return server
}