use std::collections::HashMap;
use serde_json::{Value, Map};
use crate::method::method_callable::MethodCallable;
use crate::method::method_manager::MethodManager;
use crate::method::method_structure::{Method, MethodArgument, MethodArguments, MethodResult};
use crate::method::response_formatter::{JsonResponseFormatter, ResponseFormatter};
pub struct HelpCommand {
methods: HashMap<String, Method>,
}
impl HelpCommand {
pub fn new(methods: HashMap<String, Method>) -> Self {
Self {
methods
}
}
pub fn self_register(method_manager: &mut Box<dyn MethodManager>) {
let callable: Box<dyn MethodCallable> = Box::new(Self::new(method_manager.get_methods()));
method_manager.add_method(Method {
name: String::from("help"),
description: String::from("Shows help for this application or a given method"),
help: String::from("help [method]"),
arguments: vec![
MethodArgument {
name: String::from("method"),
description: String::from("Sets the name of the method for that the help should be displayed"),
help: String::from("The name of the method where you need help for leave blank to show list of available methods"),
value: None,
required: true,
}
],
}, callable);
}
fn get_method_list(&self) -> MethodResult {
let mut list = vec![];
for name in self.methods.keys() {
list.push(Value::from(name.clone()));
}
let mut formatter = JsonResponseFormatter::new();
formatter.add_markdown(&String::from("# Available commands"));
formatter.add_list(list);
formatter.as_result(0)
}
fn get_method_arguments(&self, method: &Method) -> Vec<Map<String, Value>> {
let mut arguments = vec![];
for argument in &method.arguments {
arguments.push(self.get_method_argument(&argument))
}
arguments
}
fn get_method_argument(&self, argument: &MethodArgument) -> Map<String, Value> {
let mut map = Map::new();
map.insert(String::from("name"), Value::from(String::from(argument.name.clone())));
map.insert(String::from("description"), Value::from(String::from(argument.description.clone())));
map.insert(String::from("help"), Value::from(String::from(argument.help.clone())));
map.insert(String::from("required"), Value::from(argument.required.clone()));
if argument.value.is_some() {
map.insert(String::from("value"), argument.value.clone().unwrap());
}
map
}
}
impl MethodCallable for HelpCommand {
fn call(&self, arguments: MethodArguments) -> MethodResult {
let method_result = arguments.get_argument(&String::from("method"));
if method_result.is_none() || method_result.as_ref().unwrap().is_null() {
return self.get_method_list();
}
let method_name = method_result.unwrap();
if !method_name.is_string() {
let mut formatter = JsonResponseFormatter::new();
formatter.add_error(&String::from("Argument 'method' has to be of type String"));
return formatter.as_result(1);
}
let method_definition = self.methods.get(method_name.as_str().unwrap());
if method_definition.is_none() {
return JsonResponseFormatter::error(&String::from("Method not found"));
}
let mut data: Map<String, Value> = Map::new();
data.insert(String::from("name"), Value::from(String::from(method_definition.unwrap().name.clone())));
data.insert(String::from("description"), Value::from(String::from(method_definition.unwrap().description.clone())));
data.insert(String::from("help"), Value::from(String::from(method_definition.unwrap().help.clone())));
data.insert(String::from("arguments"), Value::from(self.get_method_arguments(method_definition.unwrap())));
JsonResponseFormatter::table(data)
}
}