package com.estateunified.panel import com.google.gson.Gson import com.google.gson.reflect.TypeToken import java.nio.charset.StandardCharsets import java.nio.file.Files import java.nio.file.Path import java.nio.file.Paths import java.util.UUID internal data class ClientCollectionDto( val id: String, val name: String, val listingIds: List, val notes: String = "", ) { fun copyListingIds(ids: List): ClientCollectionDto = copy(listingIds = ids) } internal class CollectionStore( private val gson: Gson, private val file: Path, ) { fun persistenceAbsolutePath(): String = file.toAbsolutePath().normalize().toString() private val lock = Any() fun list(): List = synchronized(lock) { loadMutable().toList() } fun get(id: String): ClientCollectionDto? = synchronized(lock) { loadMutable().find { it.id == id } } fun create(name: String): ClientCollectionDto? { val clean = name.trim() if (clean.isEmpty()) return null return synchronized(lock) { val list = loadMutable() val dto = ClientCollectionDto( id = UUID.randomUUID().toString(), name = clean, listingIds = emptyList(), notes = "", ) list.add(dto) persist(list) dto } } fun delete(id: String): Boolean = synchronized(lock) { val list = loadMutable() val removed = list.removeIf { it.id == id } if (removed) persist(list) removed } fun addListing( collectionId: String, listingId: String, ): ClientCollectionDto? = synchronized(lock) { val list = loadMutable() val i = list.indexOfFirst { it.id == collectionId } if (i < 0) return@synchronized null val cur = list[i] val next = if (listingId in cur.listingIds) { cur } else { cur.copyListingIds(cur.listingIds + listingId) } list[i] = next persist(list) next } fun removeListing( collectionId: String, listingId: String, ): ClientCollectionDto? = synchronized(lock) { val list = loadMutable() val i = list.indexOfFirst { it.id == collectionId } if (i < 0) return@synchronized null val cur = list[i] val next = cur.copyListingIds(cur.listingIds.filterNot { it == listingId }) list[i] = next persist(list) next } private fun loadMutable(): MutableList { if (!Files.isRegularFile(file)) return mutableListOf() return Files.newBufferedReader(file, StandardCharsets.UTF_8).use { reader -> gson.fromJson>(reader, listType) ?: ArrayList() } } private fun persist(rows: MutableList) { val parent = file.toAbsolutePath().parent ?: Paths.get(".").toAbsolutePath() Files.createDirectories(parent) Files.newBufferedWriter(file, StandardCharsets.UTF_8).use { writer -> gson.toJson(rows, writer) } } private companion object { val listType = object : TypeToken>() {}.type } }