package vote

// NewContext creates a new vote context.
func NewContext(id string, initOpn Opinion) *Context {
	voteCtx := &Context{ID: id, Liked: likedInit}
	voteCtx.AddOpinion(initOpn)
	return voteCtx
}

const likedInit = -1

// Context is the context of votes from multiple rounds about a given item.
type Context struct {
	ID string
	// The percentage of OpinionGivers who liked this item on the last query.
	Liked float64
	// The number of voting rounds performed.
	Rounds int
	// Append-only list of opinions formed after each round.
	// the first opinion is the initial opinion when this vote context was created.
	Opinions []Opinion
}

// AddOpinion adds the given opinion to this vote context.
func (vc *Context) AddOpinion(opn Opinion) {
	vc.Opinions = append(vc.Opinions, opn)
}

// LastOpinion returns the last formed opinion.
func (vc *Context) LastOpinion() Opinion {
	return vc.Opinions[len(vc.Opinions)-1]
}

// IsFinalized tells whether this vote context is finalized by checking whether the opinion was held
// for finalizationThreshold number of rounds.
func (vc *Context) IsFinalized(coolingOffPeriod int, finalizationThreshold int) bool {
	// check whether we have enough opinions to say whether this vote context is finalized.
	// we start from the 2nd opinion since the first one is the initial opinion.
	if len(vc.Opinions[1:]) < coolingOffPeriod+finalizationThreshold {
		return false
	}

	// grab opinion which needs to be held for finalizationThreshold number of rounds
	candidateOpinion := vc.Opinions[len(vc.Opinions)-finalizationThreshold]

	// check whether it was held for the subsequent rounds
	for _, subsequentOpinion := range vc.Opinions[len(vc.Opinions)-finalizationThreshold+1:] {
		if subsequentOpinion != candidateOpinion {
			return false
		}
	}
	return true
}

// IsNew tells whether the vote context is new.
func (vc *Context) IsNew() bool {
	return vc.Liked == likedInit
}

// HadFirstRound tells whether the vote context just had its first round.
func (vc *Context) HadFirstRound() bool {
	return vc.Rounds == 1
}