package system

import "git.tebibyte.media/tomo/tomo"
import "git.tebibyte.media/tomo/backend/internal/util"

type attrHierarchy [T tomo.Attr] struct {
	fallback T
	style    util.Optional[T]
	user     util.Optional[T]
}

func (this *attrHierarchy[T]) SetFallback (fallback T) {
	this.fallback = fallback
}

func (this *attrHierarchy[T]) SetStyle (style T) (different bool) {
	styleEquals := false
	if previous, ok := this.style.Value(); ok {
		styleEquals = previous.Equals(style)
	}
	this.style.Set(style)
	return !styleEquals && !this.user.Exists()
}

func (this *attrHierarchy[T]) UnsetStyle () (different bool) {
	different = this.style.Exists()
	this.style.Unset()
	return different
}

func (this *attrHierarchy[T]) SetUser (user T) (different bool) {
	userEquals := false
	if previous, ok := this.user.Value(); ok {
		userEquals = previous.Equals(user)
	}
	this.user.Set(user)
	return !userEquals
}

func (this *attrHierarchy[T]) UnsetUser () (different bool) {
	different = this.user.Exists()
	this.user.Unset()
	return different
}

func (this *attrHierarchy[T]) Set (attr T, user bool) (different bool) {
	if user {
		return this.SetUser(attr)
	} else {
		return this.SetStyle(attr)
	}
}

func (this *attrHierarchy[T]) Unset (user bool) (different bool) {
	if user {
		return this.UnsetUser()
	} else {
		return this.UnsetStyle()
	}
}

func (this *attrHierarchy[T]) Value () T {
	if user, ok := this.user.Value(); ok {
		return user
	} else if style, ok := this.style.Value(); ok{
		return style
	} else {
		return this.fallback
	}
}