blob: 1b05e0205f9a0b0c15bb15972c4911f86ff5adc1 [file] [log] [blame]
/*
* Copyright (c) 2023 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.matter.controller.commands.common
import java.util.ArrayList
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.atomic.AtomicLong
/**
* @brief Matter Controller command
* @details The base class of all the commands the Matter Controller supports, which are actions
* that may be performed. Commands are verb-like, such as pair a Matter device or discover Matter
* devices from the environment.
*/
abstract class Command(val name: String, val helpText: String? = null) {
private val arguments = ArrayList<Argument>()
fun getArgumentName(index: Int): String {
return arguments[index].name
}
fun getArgumentsCount(): Int {
return arguments.size
}
fun getArgumentIsOptional(index: Int): Boolean {
return arguments[index].isOptional
}
/**
* @return A pointer to an Optional where the Attribute argument will be stored
* @brief Get attribute argument if it exists, there is at most one Attribute argument per command
*/
fun getAttribute(): String? {
return arguments.find { arg -> arg.type === ArgumentType.ATTRIBUTE }?.value as? String
}
/**
* @return A pointer to an Optional where the argument description will be stored
* @brief Get argument description if it exists
*/
fun getArgumentDescription(index: Int): String? {
return arguments[index].desc
}
fun addArgumentToList(arg: Argument) {
if (arg.isOptional || arguments.isEmpty()) {
// Safe to just append to the end of a list.
arguments.add(arg)
return
}
// mandatory arg needs to be inserted before the optional arguments.
var index = 0
while (index < arguments.size && !arguments[index].isOptional) {
index++
}
// Insert before the first optional arg.
arguments.add(index, arg)
}
/**
* @param name The name that will be displayed in the command help
* @param out A pointer to a AtomicBoolean where the argv value will be stored
* @param desc The description of the argument that will be displayed in the command help
* @param optional Indicate if an optional argument
* @return The number of arguments currently added to the command
* @brief Add a bool command argument
*/
fun addArgument(name: String, out: AtomicBoolean, desc: String?, optional: Boolean) {
val arg = Argument(name, out, desc, optional)
addArgumentToList(arg)
}
/**
* @param name The name that will be displayed in the command help
* @param min The minimum value of the argv value
* @param max The minimum value of the argv value
* @param out A pointer to a AtomicInteger where the argv value will be stored
* @param desc The description of the argument that will be displayed in the command help
* @param optional Indicate if an optional argument
* @return The number of arguments currently added to the command
* @brief Add a short command argument
*/
fun addArgument(
name: String,
min: Short,
max: Short,
out: AtomicInteger,
desc: String?,
optional: Boolean
) {
val arg = Argument(name, min, max, out, desc, optional)
addArgumentToList(arg)
}
/**
* @param name The name that will be displayed in the command help
* @param min The minimum value of the argv value
* @param max The minimum value of the argv value
* @param out A pointer to a AtomicInteger where the argv value will be stored
* @param desc The description of the argument that will be displayed in the command help
* @param optional Indicate if an optional argument
* @return The number of arguments currently added to the command
* @brief Add an int command argument
*/
fun addArgument(
name: String,
min: Int,
max: Int,
out: AtomicInteger,
desc: String?,
optional: Boolean
) {
val arg = Argument(name, min, max, out, desc, optional)
addArgumentToList(arg)
}
/**
* @param name The name that will be displayed in the command help
* @param min The minimum value of the argv value
* @param max The minimum value of the argv value
* @param out A pointer to a MutableInteger where the argv value will be stored
* @param desc The description of the argument that will be displayed in the command help
* @param optional Indicate if an optional argument
* @return The number of arguments currently added to the command
* @brief Add a long Integer command argument
*/
fun addArgument(
name: String,
min: Short,
max: Short,
out: AtomicLong,
desc: String?,
optional: Boolean
) {
val arg = Argument(name, min, max, out, desc, optional)
addArgumentToList(arg)
}
/**
* @param name The name that will be displayed in the command help
* @param min The minimum value of the argv value
* @param max The minimum value of the argv value
* @param out A pointer to a AtomicLong where the argv value will be stored
* @param desc The description of the argument that will be displayed in the command help
* @param optional Indicate if an optional argument
* @return The number of arguments currently added to the command
* @brief Add a long Integer command argument
*/
fun addArgument(
name: String,
min: Long,
max: Long,
out: AtomicLong,
desc: String?,
optional: Boolean
) {
val arg = Argument(name, min, max, out, desc, optional)
addArgumentToList(arg)
}
/**
* @param name The name that will be displayed in the command help
* @param out A pointer to a IPAddress where the argv value will be stored
* @param optional Indicate if an optional argument
* @return The number of arguments currently added to the command
* @brief Add an IP address command argument
*/
fun addArgument(name: String, out: IPAddress, optional: Boolean) {
val arg = Argument(name, out, optional)
addArgumentToList(arg)
}
/**
* @param name The name that will be displayed in the command help
* @param out A pointer to a StringBuffer where the argv value will be stored
* @param desc The description of the argument that will be displayed in the command help
* @param optional Indicate if an optional argument
* @return The number of arguments currently added to the command
* @brief Add a String command argument
*/
fun addArgument(name: String, out: StringBuffer, desc: String?, optional: Boolean) {
val arg = Argument(name, out, desc, optional)
addArgumentToList(arg)
}
/**
* @param args Supplied command-line arguments as an array of String objects.
* @brief Initialize command arguments
*/
fun setArgumentValues(args: Array<String>) {
val argc = args.size
var mandatoryArgsCount = 0
var currentIndex = 0
for (arg in arguments) {
if (!arg.isOptional) {
mandatoryArgsCount++
}
}
require(argc >= mandatoryArgsCount) {
"setArgumentValues: Wrong arguments number: $argc instead of $mandatoryArgsCount"
}
// Initialize mandatory arguments
for (i in 0 until mandatoryArgsCount) {
setArgumentValue(currentIndex++, args[i])
}
// Initialize optional arguments
// Optional arguments expect a name and a value, so it is increased by 2 on every step.
var i = mandatoryArgsCount
while (i < argc) {
// optional arguments starts with OPTIONAL_ARGUMENT_PREFIX
require(
!(args[i].length <= OPTIONAL_ARGUMENT_PREFIX_LENGTH &&
!args[i].startsWith(OPTIONAL_ARGUMENT_PREFIX))
) {
"setArgumentValues: Invalid optional argument: " + args[i]
}
if (args[i].substring(OPTIONAL_ARGUMENT_PREFIX_LENGTH) == arguments[currentIndex].name) {
require(i + 1 < argc) {
"setArgumentValues: Optional argument " + args[i] + " missing value"
}
setArgumentValue(currentIndex++, args[i + 1])
}
i += 2
}
}
private fun setArgumentValue(argIndex: Int, argValue: String) {
arguments[argIndex].setValue(argValue)
}
@Throws(Exception::class) abstract fun run()
companion object {
private const val OPTIONAL_ARGUMENT_PREFIX = "--"
private const val OPTIONAL_ARGUMENT_PREFIX_LENGTH = 2
}
}