CommandFactory.kt
package de.pflugradts.passbird.application.commandhandling.factory
import de.pflugradts.kotlinextensions.tryCatching
import de.pflugradts.passbird.application.commandhandling.CommandType
import de.pflugradts.passbird.application.commandhandling.CommandVariant
import de.pflugradts.passbird.application.commandhandling.command.ChangeMasterPasswordCommand
import de.pflugradts.passbird.application.commandhandling.command.CustomSetCommand
import de.pflugradts.passbird.application.commandhandling.command.DiscardCommand
import de.pflugradts.passbird.application.commandhandling.command.ExportCommand
import de.pflugradts.passbird.application.commandhandling.command.GetCommand
import de.pflugradts.passbird.application.commandhandling.command.HelpCommand
import de.pflugradts.passbird.application.commandhandling.command.ImportCommand
import de.pflugradts.passbird.application.commandhandling.command.ListCommand
import de.pflugradts.passbird.application.commandhandling.command.NullCommand
import de.pflugradts.passbird.application.commandhandling.command.QuitCommand
import de.pflugradts.passbird.application.commandhandling.command.QuitReason.USER
import de.pflugradts.passbird.application.commandhandling.command.RenameCommand
import de.pflugradts.passbird.application.commandhandling.command.RepeatLastCommand
import de.pflugradts.passbird.application.commandhandling.command.ViewCommand
import de.pflugradts.passbird.application.commandhandling.command.base.Command
import de.pflugradts.passbird.application.failure.CommandFailure
import de.pflugradts.passbird.application.failure.reportFailure
import de.pflugradts.passbird.domain.model.transfer.Input
class CommandFactory constructor(
private val favoriteCommandFactory: FavoriteCommandFactory,
private val listCommandFactory: ListCommandFactory,
private val memoryCommandFactory: MemoryCommandFactory,
private val nestCommandFactory: NestCommandFactory,
private val proteinCommandFactory: ProteinCommandFactory,
private val setCommandFactory: SetCommandFactory,
) {
fun construct(commandType: CommandType, input: Input) = constructDirectly(commandType, input)
?: constructWithoutArguments(commandType, input)
?: constructViaSpecialFactory(commandType, input)
?: NullCommand()
private fun constructDirectly(commandType: CommandType, input: Input) = when (commandType) {
CommandType.CUSTOM_SET -> CustomSetCommand(input)
CommandType.DISCARD -> DiscardCommand(input)
CommandType.GET -> GetCommand(input)
CommandType.RENAME -> RenameCommand(input)
CommandType.VIEW -> ViewCommand(input)
else -> null
}
private fun constructWithoutArguments(commandType: CommandType, input: Input) = when (commandType) {
CommandType.EXPORT -> constructWithOptionalStarVariant(input) { ExportCommand(it) }
CommandType.HELP -> constructSafely(input) { HelpCommand() }
CommandType.IMPORT -> constructWithOptionalStarVariant(input) { ImportCommand(it) }
CommandType.KEYSTORE -> constructSafely(input) { ChangeMasterPasswordCommand() }
CommandType.QUIT -> constructSafely(input) { QuitCommand(quitReason = USER) }
CommandType.REPEAT -> constructSafely(input) { RepeatLastCommand() }
else -> null
}
private fun constructViaSpecialFactory(commandType: CommandType, input: Input) = when (commandType) {
CommandType.FAVORITE -> constructSafely(favoriteCommandFactory, input)
CommandType.LIST -> constructSafely(listCommandFactory, input)
CommandType.MEMORY -> constructSafely(memoryCommandFactory, input)
CommandType.NEST -> constructSafely(nestCommandFactory, input)
CommandType.PROTEIN -> constructSafely(proteinCommandFactory, input)
CommandType.SET -> constructSafely(setCommandFactory, input)
else -> null
}
private fun constructSafely(factory: SpecialCommandFactory, input: Input) = tryCatching { factory.constructFromInput(input) }
.onFailure { reportFailure(CommandFailure(it)) }
.getOrElse(NullCommand())
private fun constructSafely(input: Input, supplier: () -> Command) = tryCatching {
require(input.command.size == 1 && input.data.isEmpty) {
"Parameter for command '${input.command.getChar(0)}' not supported: ${unsupportedParameter(input)}"
}
supplier()
}.onFailure { reportFailure(CommandFailure(it)) }
.getOrElse(NullCommand())
private fun constructWithOptionalStarVariant(input: Input, supplier: (Boolean) -> Command) = tryCatching {
require(input.data.isEmpty) {
"Parameter for command '${input.command.getChar(0)}' not supported: ${unsupportedParameter(input)}"
}
require(
input.command.size == 1 ||
(input.command.size == 2 && input.command.getChar(1) == CommandVariant.SHOW_ALL.value),
) {
"Parameter for command '${input.command.getChar(0)}' not supported: ${unsupportedParameter(input)}"
}
supplier(input.command.size == 2)
}.onFailure { reportFailure(CommandFailure(it)) }
.getOrElse(NullCommand())
private fun unsupportedParameter(input: Input) = buildString {
append(input.command.slice(1).asString())
append(input.data.asString())
}
}