package moe.nea.firmament.util.data import java.nio.file.Path import java.util.UUID import kotlinx.serialization.KSerializer import kotlin.io.path.createDirectories import kotlin.io.path.deleteExisting import kotlin.io.path.exists import kotlin.io.path.extension import kotlin.io.path.listDirectoryEntries import kotlin.io.path.nameWithoutExtension import kotlin.io.path.readText import kotlin.io.path.writeText import moe.nea.firmament.Firmament import moe.nea.firmament.util.SBData abstract class ProfileSpecificDataHolder( private val dataSerializer: KSerializer, val configName: String, private val configDefault: () -> S ) : IDataHolder { var allConfigs: MutableMap override val data: S? get() = SBData.profileId?.let { allConfigs.computeIfAbsent(it) { configDefault() } } init { allConfigs = readValues() IDataHolder.putDataHolder(this::class, this) } private val configDirectory: Path get() = Firmament.CONFIG_DIR.resolve("profiles").resolve(configName) private fun readValues(): MutableMap { if (!configDirectory.exists()) { configDirectory.createDirectories() } val profileFiles = configDirectory.listDirectoryEntries() return profileFiles .filter { it.extension == "json" } .mapNotNull { try { UUID.fromString(it.nameWithoutExtension) to Firmament.json.decodeFromString(dataSerializer, it.readText()) } catch (e: Exception) { /* Expecting IOException and SerializationException, but Kotlin doesn't allow multi catches*/ IDataHolder.badLoads.add(configName) Firmament.logger.error( "Exception during loading of profile specific config file $it ($configName). This will reset that profiles config.", e ) null } }.toMap().toMutableMap() } override fun save() { if (!configDirectory.exists()) { configDirectory.createDirectories() } val c = allConfigs configDirectory.listDirectoryEntries().forEach { if (it.nameWithoutExtension !in c.mapKeys { it.toString() }) { it.deleteExisting() } } c.forEach { (name, value) -> val f = configDirectory.resolve("$name.json") f.writeText(Firmament.json.encodeToString(dataSerializer, value)) } } override fun markDirty() { IDataHolder.markDirty(this::class) } override fun load() { allConfigs = readValues() } }