package pov

const testVersion = 2

type Graph struct {
	leaves []Node
}

func New() *Graph {
	g := new(Graph)
	return g
}

func (g *Graph) GetNode(lbl string) *Node {
	for i := range g.leaves {
		if n := g.leaves[i].GetNode(lbl); n != nil {
			return n
		}
	}
	return nil
}

func (g *Graph) AddNode(lbl string) {
	g.leaves = append(g.leaves, Node{label: lbl})
}

func (g *Graph) addRealNode(n *Node) {
	g.leaves = append(g.leaves, n)
}

func (g *Graph) AddArc(from, to string) {
	if n := g.GetNode(to); n != nil {
		n.AddNode(from)
	}
}

func (g *Graph) ArcList() []string {
	var ret []string
	for i := range g.leaves {
		ret = append(ret, g.leaves[i].ArcList()...)
	}
	return ret
}

func (g *Graph) ChangeRoot(oldRoot, newRoot string) *Graph {
	// First of all, find the newRoot node
	ret := New()
	// The new graph will start with newRoot and have newRoot's leaves
	if rt := g.GetNode(newRoot); rt == nil {
		return ret
	}
	// It'll have one more leaf, it's parent node
	ret.AddNode(rt)
	return g
}

func (g *Graph) getPath(from, to string) []string {
	var ret []string
	// Get the 'from' node
	frNode := g.GetNode(from)
	if frNode == nil {
		// Couldn't find the starting node
		return ret
	}
	// Just in case we got the same value for both
	if from == to {
		return []string{from}
	}
	// Found it
	return frNode.getPath(to)
}

type Node struct {
	label  string
	leaves []Node
}

func (n *Node) AddNode(lbl string) {
	n.leaves = append(n.leaves, Node{label: lbl})
}

func (n *Node) GetNode(lbl string) *Node {
	if n.label == lbl {
		return n
	}
	for i := range n.leaves {
		if r := n.leaves[i].GetNode(lbl); r != nil {
			return r
		}
	}
	return nil
}

func (n *Node) ArcList() []string {
	var ret []string
	for i := range n.leaves {
		ret = append(ret, n.leaves[i].label+" -> "+n.label)
		ret = append(ret, n.leaves[i].ArcList()...)
	}
	return ret
}

func (n *Node) getPath(to string) []string {
	ret := []string{n.label}
	if n.label == to {
		return ret
	}
	var i int
	var found bool
	for i = range n.leaves {
		if n.leaves[i].GetNode(to) != nil {
			found = true
			break
		}
	}
	if !found {
		// We didn't find a path... :(
		return ret
	}
	// n.leaves[i] should be the right leaf now
	return append(ret, n.leaves[i].getPath(to)...)
}
