package httpsfv

import (
	
	
)

// Dictionary is an ordered map of name-value pairs.
// See https://httpwg.org/specs/rfc9651.html#dictionary
// Values can be:
//   * Item (Section 3.3.)
//   * Inner List (Section 3.1.1.)
type Dictionary struct {
	names  []string
	values map[string]Member
}

// ErrInvalidDictionaryFormat is returned when a dictionary value is invalid.
var ErrInvalidDictionaryFormat = errors.New("invalid dictionary format")

// NewDictionary creates a new ordered map.
func () *Dictionary {
	 := Dictionary{}
	.names = []string{}
	.values = map[string]Member{}

	return &
}

// Get retrieves a member.
func ( *Dictionary) ( string) (Member, bool) {
	,  := .values[]

	return , 
}

// Add appends a new member to the ordered list.
func ( *Dictionary) ( string,  Member) {
	if ,  := .values[]; ! {
		.names = append(.names, )
	}

	.values[] = 
}

// Del removes a member from the ordered list.
func ( *Dictionary) ( string) bool {
	if ,  := .values[]; ! {
		return false
	}

	for ,  := range .names {
		if  ==  {
			.names = append(.names[:], .names[+1:]...)

			break
		}
	}

	delete(.values, )

	return true
}

// Names retrieves the list of member names in the appropriate order.
func ( *Dictionary) () []string {
	return .names
}

func ( *Dictionary) ( *strings.Builder) error {
	 := len(.names) - 1

	for ,  := range .names {
		if  := marshalKey(, );  != nil {
			return 
		}

		 := .values[]

		if ,  := .(Item);  && .Value == true {
			if  := .Params.marshalSFV();  != nil {
				return 
			}
		} else {
			if  := .WriteByte('=');  != nil {
				return 
			}
			if  := .marshalSFV();  != nil {
				return 
			}
		}

		if  !=  {
			if ,  := .WriteString(", ");  != nil {
				return 
			}
		}
	}

	return nil
}

// UnmarshalDictionary parses a dictionary as defined in
// https://httpwg.org/specs/rfc9651.html#parse-dictionary.
func ( []string) (*Dictionary, error) {
	 := &scanner{
		data: strings.Join(, ","),
	}

	.scanWhileSp()

	,  := parseDictionary()
	if  != nil {
		return , 
	}

	return , nil
}

func parseDictionary( *scanner) (*Dictionary, error) {
	 := NewDictionary()

	for !.eof() {
		,  := parseKey()
		if  != nil {
			return nil, 
		}

		var  Member

		if !.eof() && .data[.off] == '=' {
			.off++
			,  = parseItemOrInnerList()

			if  != nil {
				return nil, 
			}
		} else {
			,  := parseParams()
			if  != nil {
				return nil, 
			}
			 = Item{true, }
		}

		.Add(, )
		.scanWhileOWS()

		if .eof() {
			return , nil
		}

		if .data[.off] != ',' {
			return nil, &UnmarshalError{.off, ErrInvalidDictionaryFormat}
		}
		.off++

		.scanWhileOWS()

		if .eof() {
			// there is a trailing comma
			return nil, &UnmarshalError{.off, ErrInvalidDictionaryFormat}
		}
	}

	return , nil
}