ViewProteinTypesCommandHandler.kt

package de.pflugradts.passbird.application.commandhandling.handler.protein
import de.pflugradts.kotlinextensions.Option
import de.pflugradts.passbird.application.UserInterfaceAdapterPort
import de.pflugradts.passbird.application.commandhandling.CommandExecutionTracker
import de.pflugradts.passbird.application.commandhandling.capabilities.CanPrintInfo
import de.pflugradts.passbird.application.commandhandling.command.ViewProteinTypesCommand
import de.pflugradts.passbird.application.commandhandling.handler.TypedCommandHandler
import de.pflugradts.passbird.domain.model.shell.Shell
import de.pflugradts.passbird.domain.model.transfer.Output
import de.pflugradts.passbird.domain.service.password.PasswordService
class ViewProteinTypesCommandHandler constructor(
    private val canPrintInfo: CanPrintInfo,
    private val passwordService: PasswordService,
    private val userInterfaceAdapterPort: UserInterfaceAdapterPort,
    private val commandExecutionTracker: CommandExecutionTracker,
) : TypedCommandHandler<ViewProteinTypesCommand>(ViewProteinTypesCommand::class.java) {
    override fun handleCommand(command: ViewProteinTypesCommand) {
        passwordService.viewProteinTypes(command.argument).orNull()?.also { proteinTypes ->
            try {
                userInterfaceAdapterPort.send(*outputsOfHeader())
                proteinTypes.forEachIndexed { index, proteinType -> userInterfaceAdapterPort.send(*outputsOf(index, proteinType)) }
            } finally {
                proteinTypes.forEach { it.ifPresent(Shell::scramble) }
            }
        } ?: commandExecutionTracker.markFailure()
        command.invalidateInput()
        userInterfaceAdapterPort.sendLineBreak()
    }
    private fun outputsOfHeader(): Array<Output> = with(canPrintInfo) {
        arrayOf(out("\n"), outBold(SLOT_HEADER), outBold("Type".padded()), outBold(SEP), outBold("Structure".padded()))
    }
    private fun outputsOf(index: Int, proteinType: Option<Shell>): Array<Output> = with(canPrintInfo) {
        arrayOf(
            out(padded(index)),
            out(proteinType.map { it.asString() }.orElse("---").padded()),
            out(SEP),
            out(proteinType.map { "*****" }.orElse("---").padded()),
        )
    }
}
private const val SEP = " | "
private const val SLOT_HEADER = "Slot "
private fun String.padded() = padEnd(20, ' ')
private fun padded(index: Int) = "$index:".padEnd(SLOT_HEADER.length, ' ')