/*
 * Amsterdam Web Communities System
 * Copyright (c) 2025 Erbosoft Metaverse Design Solutions, All Rights Reserved
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

// Package util contains utility definitions.
package util

import (
	"strings"

	"github.com/bits-and-blooms/bitset"
)

// optionAlphabet is the alphabet from which OptionSets serialize to and from strings.
const optionAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$&()*+,-./:;<=>?@[]^_`{|}~"

// OptionSet is a bit set that can be persisted as a specially-constructed string.
type OptionSet struct {
	bits *bitset.BitSet
}

// Get retrieves the value of a bit from the given set.
func (s *OptionSet) Get(ndx uint) bool {
	return s.bits.Test(ndx)
}

// Set sets the value of a bit in the given set.
func (s *OptionSet) Set(ndx uint, v bool) {
	if v {
		s.bits = s.bits.Set(ndx)
	} else {
		s.bits = s.bits.Clear(ndx)
	}
}

// AsString returns the option set's value as a string.
func (s *OptionSet) AsString() string {
	var b strings.Builder
	for i, e := s.bits.NextSet(0); e; i, e = s.bits.NextSet(i + 1) {
		b.WriteByte(optionAlphabet[int(i)])
	}
	return b.String()
}

// Clone creates a clone of this OptionSet.
func (s *OptionSet) Clone() *OptionSet {
	return &OptionSet{bits: s.bits.Clone()}
}

// NewOptionSet creates and returns an empty option set.
func NewOptionSet() *OptionSet {
	return &OptionSet{bits: bitset.New(uint(len(optionAlphabet)))}
}

// OptionSetFromString converts a string into a corresponding OptionSet.
func OptionSetFromString(s string) *OptionSet {
	bs := bitset.New(uint(len(optionAlphabet)))
	for _, ch := range s {
		bs = bs.Set(uint(strings.IndexRune(optionAlphabet, ch)))
	}
	return &OptionSet{bits: bs}
}

// OptionCharFromIndex converts an integer into the matching character from the option alphabet.
func OptionCharFromIndex(ndx uint) string {
	if ndx > uint(len(optionAlphabet)) {
		return ""
	}
	return optionAlphabet[ndx : ndx+1]
}
