ExportCommandHandler.kt
package de.pflugradts.passbird.application.commandhandling.handler
import de.pflugradts.passbird.application.UserInterfaceAdapterPort
import de.pflugradts.passbird.application.commandhandling.CommandExecutionTracker
import de.pflugradts.passbird.application.commandhandling.capabilities.CanListAvailableNests
import de.pflugradts.passbird.application.commandhandling.command.ExportCommand
import de.pflugradts.passbird.application.exchange.ImportExportService
import de.pflugradts.passbird.domain.model.shell.Shell.Companion.shellOf
import de.pflugradts.passbird.domain.model.slot.Slot
import de.pflugradts.passbird.domain.model.slot.Slot.Companion.slotAt
import de.pflugradts.passbird.domain.model.transfer.Output.Companion.outputOf
import de.pflugradts.passbird.domain.model.transfer.OutputFormatting.HIGHLIGHT
import de.pflugradts.passbird.domain.model.transfer.OutputFormatting.OPERATION_ABORTED
import de.pflugradts.passbird.domain.service.nest.NestService
class ExportCommandHandler constructor(
private val canListAvailableNests: CanListAvailableNests,
private val importExportService: ImportExportService,
private val nestService: NestService,
private val userInterfaceAdapterPort: UserInterfaceAdapterPort,
private val commandExecutionTracker: CommandExecutionTracker,
) : TypedCommandHandler<ExportCommand>(ExportCommand::class.java) {
override fun handleCommand(command: ExportCommand) {
if (command.selective) {
exportSelectedNests()
} else {
importExportService.exportEggs()
}
userInterfaceAdapterPort.sendLineBreak()
}
private fun exportSelectedNests() {
val availableNestSlots = availableNestSlots()
userInterfaceAdapterPort.send(outputOf(shellOf("\nAvailable Nests:\n"), HIGHLIGHT))
userInterfaceAdapterPort.send(outputOf(shellOf(canListAvailableNests.getAvailableNests(includeCurrent = true))))
val selectionMode = receiveSelectionMode() ?: return sendAbortMessage()
val selectedNestSlots = receiveSelectedNestSlots(availableNestSlots) ?: return sendAbortMessage()
val exportedNestSlots = when (selectionMode) {
ExportSelectionMode.SELECTED -> selectedNestSlots
ExportSelectionMode.EXCEPT_SELECTED -> availableNestSlots - selectedNestSlots
}
if (exportedNestSlots.isEmpty()) {
sendAbortMessage()
return
}
importExportService.exportEggs(exportedNestSlots)
}
private fun availableNestSlots() = nestService.all(includeDefault = true)
.filter { it.isPresent }
.map { it.get().slot }
.toList()
.toSet()
private fun receiveSelectionMode() = userInterfaceAdapterPort.receive(
outputOf(shellOf("\nInput 1 to export only selected Nests or 2 to export all Nests except selected Nests.\nYour input: ")),
).shell.asString().let {
when (it) {
"1" -> ExportSelectionMode.SELECTED
"2" -> ExportSelectionMode.EXCEPT_SELECTED
else -> null
}
}
private fun receiveSelectedNestSlots(availableNestSlots: Set<Slot>) = userInterfaceAdapterPort.receive(
outputOf(shellOf("Specify Nest Slots separated by ','.\nYour input: ")),
).shell.asString().split(',')
.map { it.trim() }
.takeIf { parts -> parts.isNotEmpty() && parts.all { part -> part.length == 1 && part[0].isDigit() } }
?.map { part -> slotAt(part) }
?.toSet()
?.takeIf { selectedSlots -> selectedSlots.all(availableNestSlots::contains) }
private fun sendAbortMessage() {
commandExecutionTracker.markAborted()
userInterfaceAdapterPort.send(outputOf(shellOf("Operation aborted."), OPERATION_ABORTED))
}
}
private enum class ExportSelectionMode { SELECTED, EXCEPT_SELECTED }