package com.infendro.cli.option import com.infendro.cli.exception.InvalidOptionName import com.infendro.cli.exception.InvalidRange import com.infendro.cli.exception.MissingOptionName import com.infendro.cli.parser.Parser import com.infendro.cli.util.Regex.OPTION sealed class Option( val parser: Parser, val fallback: T?, val names: List, val description: String?, val min: Int, val max: Int?, ) { val name: String get() = names.maxBy { it.length } val flag: Boolean get() = fallback != null val required: Boolean get() = min > 0 val optional: Boolean get() = !required val bounded: Boolean get() = max != null val unbounded: Boolean get() = !bounded val count: Int get() = max ?: Int.MAX_VALUE init { when { names.isEmpty() -> throw MissingOptionName() names.any { !it.matches(OPTION) } -> throw InvalidOptionName(name) min !in 0..count || max == 0 -> throw InvalidRange() } } class Required( parser: Parser, fallback: T?, names: List, description: String?, ) : Option(parser, fallback, names, description, min = 1, max = 1) { fun orElse(other: T) = OrElse(parser, fallback, names, description, other) fun orNull() = OrNull(parser, fallback, names, description) fun variable(min: Int = 0, max: Int? = null) = Variable(parser, fallback, names, description, min, max) } class OrElse( parser: Parser, fallback: T?, names: List, description: String?, val other: T, ) : Option(parser, fallback, names, description, min = 0, max = 1) class OrNull( parser: Parser, fallback: T?, names: List, description: String?, ) : Option(parser, fallback, names, description, min = 0, max = 1) class Variable( parser: Parser, fallback: T?, names: List, description: String?, min: Int, max: Int?, ) : Option(parser, fallback, names, description, min, max) }