func (he *HistoryEventVertex) SetIsStrictOnNextVertex(
	isStrict bool,
) {
	he.isStrictOnNextVertex = isStrict
}
Equals compares two vertex
func (he *HistoryEventVertex) Equals(
v Vertex,
) bool {

return strings.EqualFold(he.name, v.GetName()) && he.data == v.GetData()
}
SetIsStrictOnNextVertex sets if a vertex can be added between the current vertex and its child Vertices
package testing
import (
	"math/rand"
)
const (
	emptyCandidateIndex = -1
	defaultVersion      = int64(100)
)
var (
	defaultBatchFunc = func(batch []Vertex, history []Vertex) bool {
		return len(batch) == 0
	}
)
type (
	HistoryEventVertex struct {
		name                 string
		isStrictOnNextVertex bool
		maxNextGeneration    int
		dataFunc             func(...interface{}) interface{}
		data                 interface{}
	}
	HistoryEventModel struct {
		edges []Edge
	}
	EventGenerator struct {
		connections         map[string][]Edge
		previousVertices    []Vertex
		leafVertices        []Vertex
		entryVertices       []Vertex
		exitVertices        map[string]bool
		randomEntryVertices []Vertex
		dice                *rand.Rand
		seed                int64
		canDoBatch          func([]Vertex, []Vertex) bool
		version             int64
	}
	HistoryEventEdge struct {
		startVertex Vertex
		endVertex   Vertex
		condition   func(...interface{}) bool
		action      func()
	}
	RevokeFunc struct {
		methodName string         
		input      []interface{}  
	}
)
func NewEventGenerator(
	seed int64,
) Generator {
	return &EventGenerator{
		connections:         make(map[string][]Edge),
		previousVertices:    make([]Vertex, 0),
		leafVertices:        make([]Vertex, 0),
		entryVertices:       make([]Vertex, 0),
		exitVertices:        make(map[string]bool),
		randomEntryVertices: make([]Vertex, 0),
		dice:                rand.New(rand.NewSource(seed)),
		seed:                seed,
		canDoBatch:          defaultBatchFunc,
		version:             defaultVersion,
	}
}
func (g *EventGenerator) AddInitialEntryVertex(
	entry ...Vertex,
) {
	g.entryVertices = append(
		g.entryVertices,
		entry...)
}
func (g *EventGenerator) AddExitVertex(
	exit ...Vertex,
) {
	for _, v := range exit {
		g.exitVertices[v.GetName()] = true
	}
}
func (g *EventGenerator) AddRandomEntryVertex(
	exit ...Vertex,
) {
	g.randomEntryVertices = append(g.randomEntryVertices, exit...)
}
func (g *EventGenerator) AddModel(
	model Model,
) {
	for _, e := range model.ListEdges() {
		if _, ok := g.connections[e.GetStartVertex().GetName()]; !ok {
			g.connections[e.GetStartVertex().GetName()] = make([]Edge, 0)
		}
		g.connections[e.GetStartVertex().GetName()] = append(g.connections[e.GetStartVertex().GetName()], e)
	}
}
func (g EventGenerator) ListGeneratedVertices() []Vertex {
	return g.previousVertices
}
func (g *EventGenerator) HasNextVertex() bool {
	for _, prev := range g.previousVertices {
		if _, ok := g.exitVertices[prev.GetName()]; ok {
			return false
		}
	}
	return len(g.leafVertices) > 0 || (len(g.previousVertices) == 0 && len(g.entryVertices) > 0)
}
func (g *EventGenerator) GetNextVertices() []Vertex {
	if !g.HasNextVertex() {
		panic("Generator reached to a terminate state.")
	}
	batch := make([]Vertex, 0)
	for g.HasNextVertex() && g.canDoBatch(batch, g.previousVertices) {
		res := g.generateNextEventBatch()
		g.updateContext(res)
		batch = append(batch, res...)
	}
	return batch
}
func (g *EventGenerator) Reset() {
	g.leafVertices = make([]Vertex, 0)
	g.previousVertices = make([]Vertex, 0)
	g.version = defaultVersion
}
func (g *EventGenerator) DeepCopy() Generator {
	return &EventGenerator{
		connections:         copyConnections(g.connections),
		previousVertices:    copyVertex(g.previousVertices),
		leafVertices:        copyVertex(g.leafVertices),
		entryVertices:       copyVertex(g.entryVertices),
		exitVertices:        copyExitVertices(g.exitVertices),
		randomEntryVertices: copyVertex(g.randomEntryVertices),
		dice:                rand.New(rand.NewSource(g.seed)),
		seed:                g.seed,
		canDoBatch:          g.canDoBatch,
		version:             g.version,
	}
}
func (g *EventGenerator) SetBatchGenerationRule(
	canDoBatchFunc func([]Vertex, []Vertex) bool,
) {
	g.canDoBatch = canDoBatchFunc
}
func (g *EventGenerator) SetVersion(version int64) {
	g.version = version
}
func (g *EventGenerator) GetVersion() int64 {
	return g.version
}
func (g *EventGenerator) generateNextEventBatch() []Vertex {
	batch := make([]Vertex, 0)
	switch {
	case len(g.previousVertices) == 0:
		batch = append(batch, g.getEntryVertex())
	case len(g.randomEntryVertices) > 0 && g.dice.Intn(len(g.connections)) == 0:
		batch = append(batch, g.getRandomVertex())
	default:
		idx := g.getVertexCandidate()
		batch = append(batch, g.randomNextVertex(idx)...)
		g.leafVertices = append(g.leafVertices[:idx], g.leafVertices[idx+1:]...)
	}
	return batch
}
func (g *EventGenerator) updateContext(
	batch []Vertex,
) {
	g.leafVertices = append(g.leafVertices, batch...)
	g.previousVertices = append(g.previousVertices, batch...)
}
func (g *EventGenerator) getEntryVertex() Vertex {
	if len(g.entryVertices) == 0 {
		panic("No possible start vertex to go to next step")
	}
	nextRange := len(g.entryVertices)
	nextIdx := g.dice.Intn(nextRange)
	vertex := g.entryVertices[nextIdx].DeepCopy()
	vertex.GenerateData(nil)
	return vertex
}
func (g *EventGenerator) getRandomVertex() Vertex {
	if len(g.randomEntryVertices) == 0 {
		panic("No possible vertex to go to next step")
	}
	nextRange := len(g.randomEntryVertices)
	nextIdx := g.dice.Intn(nextRange)
	vertex := g.randomEntryVertices[nextIdx].DeepCopy()
	parentEvent := g.previousVertices[len(g.previousVertices)-1]
	vertex.GenerateData(parentEvent.GetData(), parentEvent.GetData(), g.version)
	return vertex
}
func (g *EventGenerator) getVertexCandidate() int {
	if len(g.leafVertices) == 0 {
		panic("No possible vertex to go to next step")
	}
	nextRange := len(g.leafVertices)
	notAvailable := make(map[int]bool)
	var nextVertexIdx int
	for len(notAvailable) < nextRange {
		nextVertexIdx = g.dice.Intn(nextRange)
		if _, ok := notAvailable[nextVertexIdx]; ok {
			continue
		}
		isAccessible, nextVertexIdx := g.findAccessibleVertex(nextVertexIdx)
		if isAccessible {
			return nextVertexIdx
		}
		notAvailable[nextVertexIdx] = true
	}
	panic("cannot find available history event to proceed. please check your model")
}
func (g *EventGenerator) findAccessibleVertex(
	vertexIndex int,
) (bool, int) {
	candidate := g.leafVertices[vertexIndex]
	if g.leafVertices[len(g.leafVertices)-1].IsStrictOnNextVertex() {
		vertexIndex = len(g.leafVertices) - 1
		candidate = g.leafVertices[vertexIndex]
	}
	neighbors := g.connections[candidate.GetName()]
	for _, nextV := range neighbors {
		if nextV.GetCondition() == nil || nextV.GetCondition()(g.previousVertices) {
			return true, vertexIndex
		}
	}
	return false, emptyCandidateIndex
}
func (g *EventGenerator) randomNextVertex(
	nextVertexIdx int,
) []Vertex {
	nextVertex := g.leafVertices[nextVertexIdx]
	count := g.dice.Intn(nextVertex.GetMaxNextVertex()) + 1
	res := make([]Vertex, 0)
	latestVertex := g.previousVertices[len(g.previousVertices)-1]
	for i := 0; i < count; i++ {
		endVertex := g.pickRandomVertex(nextVertex)
		endVertex.GenerateData(nextVertex.GetData(), latestVertex.GetData(), g.version)
		latestVertex = endVertex
		res = append(res, endVertex)
		if _, ok := g.exitVertices[endVertex.GetName()]; ok {
			res = []Vertex{endVertex}
			return res
		}
	}
	return res
}
func (g *EventGenerator) pickRandomVertex(
	nextVertex Vertex,
) Vertex {
	neighbors := g.connections[nextVertex.GetName()]
	neighborsRange := len(neighbors)
	nextIdx := g.dice.Intn(neighborsRange)
	for neighbors[nextIdx].GetCondition() != nil && !neighbors[nextIdx].GetCondition()(g.previousVertices) {
		nextIdx = g.dice.Intn(neighborsRange)
	}
	newConnection := neighbors[nextIdx]
	endVertex := newConnection.GetEndVertex()
	if newConnection.GetAction() != nil {
		newConnection.GetAction()()
	}
	return endVertex.DeepCopy()
}
func (g *EventGenerator) shouldBumpVersion() bool {
	return false
}
func NewHistoryEventEdge(
	start Vertex,
	end Vertex,
) Edge {
	return &HistoryEventEdge{
		startVertex: start,
		endVertex:   end,
	}
}
func (c *HistoryEventEdge) SetStartVertex(
	start Vertex,
) {
	c.startVertex = start
}
func (c HistoryEventEdge) GetStartVertex() Vertex {
	return c.startVertex
}
func (c *HistoryEventEdge) SetEndVertex(end Vertex) {
	c.endVertex = end
}
func (c HistoryEventEdge) GetEndVertex() Vertex {
	return c.endVertex
}
func (c *HistoryEventEdge) SetCondition(
	condition func(...interface{}) bool,
) {
	c.condition = condition
}
func (c HistoryEventEdge) GetCondition() func(...interface{}) bool {
	return c.condition
}
func (c HistoryEventEdge) SetAction(action func()) {
	c.action = action
}
func (c HistoryEventEdge) GetAction() func() {
	return c.action
}
func (c *HistoryEventEdge) DeepCopy() Edge {
	return &HistoryEventEdge{
		startVertex: c.startVertex.DeepCopy(),
		endVertex:   c.endVertex.DeepCopy(),
		condition:   c.condition,
		action:      c.action,
	}
}
func NewHistoryEventVertex(
	name string,
) Vertex {
	return &HistoryEventVertex{
		name:                 name,
		isStrictOnNextVertex: false,
		maxNextGeneration:    1,
	}
}
func (he HistoryEventVertex) GetName() string {
	return he.name
}
func (he *HistoryEventVertex) SetName(
	name string,
) {
	he.name = name
}