package modules

import "sync"

// Node that store information about each Microservice
type MSNode struct {
	nodeName string //In demo, NodeName(nodeName) == IP Address(ipAddr)
	ipAddr   string
}

// return nodeName
func (node *MSNode) GetName() string {
	return node.nodeName
}

// return IP address
func (node *MSNode) GetIpaddr() string {
	return node.ipAddr
}

type NodeManager interface {
	GetIpaddr(nodeName string) (string, bool)
	AddMicroservice(node MSNode) bool
	RemoveMicroservice(nodeName string) bool
}

// Store information of all microservice
type MStable struct {
	NodeTable map[string]MSNode
	mu        sync.RWMutex
}

// Constructor of MStable
func NewMStable() *MStable {
	logger := NewMyLogger()
	defer logger.Sync()

	defer logger.Debug("node manager setting complete.")
	return &MStable{NodeTable: make(map[string]MSNode)}
}

// return IP address
func (manager *MStable) GetIpaddr(nodeName string) (string, bool) {
	//해당 이름의 노드이름이 존재하는지 확인
	// check whether the name exist
	node, exists := manager.NodeTable[nodeName]

	// If the name doesn't exist, return nil
	if !exists {
		return "", false
	} else {
		return node.ipAddr, true
	}
}

// add microservice
func (manager *MStable) AddMicroservice(node MSNode) bool {
	// check existance of the same microservice before add a new microservice
	manager.mu.RLock()
	_, exists := manager.NodeTable[node.GetName()]
	manager.mu.RUnlock()

	// If the microservice doesn't exist in MStable, add the microservice
	if exists {
		return false
	} else {
		manager.NodeTable[node.GetName()] = node
		return true
	}
}

// remove microservice
func (manager *MStable) RemoveMicroservice(nodeName string) bool {
	logger := NewMyLogger()
	defer logger.Sync()
	// check existance of the same microservice before add a new microservice
	_, exists := manager.NodeTable[nodeName]

	// If the microservice exist in MStable, remove the microservice
	if exists {
		delete(manager.NodeTable, nodeName)
		logger.Info("[" + nodeName + "] : service quit")
		return true
	} else {
		return false
	}
}
