package resourcename

import "strings"

// RevisionSeparator is the separator character used to separate resource IDs from revision IDs.
const RevisionSeparator = '@'

// Segment is a segment of a resource name or a resource name pattern.
//
// EBNF
//
//	Segment  = Literal | Variable ;
//	Variable = "{" Literal "}" ;
type Segment string

// IsVariable reports whether the segment is a variable segment.
func (s Segment) IsVariable() bool {
	return len(s) > 2 && s[0] == '{' && s[len(s)-1] == '}'
}

// Literal returns the literal value of the segment.
// For variables, the literal value is the name of the variable.
func (s Segment) Literal() Literal {
	switch {
	case s.IsVariable():
		return Literal(s[1 : len(s)-1])
	default:
		return Literal(s)
	}
}

// IsWildcard reports whether the segment is a wildcard.
func (s Segment) IsWildcard() bool {
	return s == Wildcard
}

// Literal is the literal part of a resource name segment.
//
// EBNF
//
//	Literal  = RESOURCE_ID | RevisionLiteral ;
//	RevisionLiteral = RESOURCE_ID "@" REVISION_ID ;
type Literal string

// ResourceID returns the literal's resource ID.
func (l Literal) ResourceID() string {
	if !l.HasRevision() {
		return string(l)
	}
	return string(l[:strings.IndexByte(string(l), RevisionSeparator)])
}

// RevisionID returns the literal's revision ID.
func (l Literal) RevisionID() string {
	if !l.HasRevision() {
		return ""
	}
	return string(l[strings.IndexByte(string(l), RevisionSeparator)+1:])
}

// HasRevision returns true if the literal has a valid revision.
func (l Literal) HasRevision() bool {
	revisionSeparatorIndex := strings.IndexByte(string(l), RevisionSeparator)
	if revisionSeparatorIndex < 1 || revisionSeparatorIndex >= len(l)-1 {
		return false // must have content on each side of the revision marker
	}
	if strings.IndexByte(string(l[revisionSeparatorIndex+1:]), RevisionSeparator) != -1 {
		return false // multiple revision markers means no valid revision
	}
	return true
}
