use crate::data::error_info::ErrorInfo;
use crate::data::position::Position;
use crate::data::primitive::PrimitiveObject;
use crate::data::{ArgsType, Interval, Literal};
use crate::interpreter::json_to_literal;
use nom::lib::std::collections::HashMap;
use std::collections::HashSet;
trait ArithmeticOperation {
fn get_type(value: &serde_json::Value) -> String;
fn add(
lhs: &serde_json::Value,
rhs: &serde_json::Value,
interval: &Interval,
) -> Result<serde_json::Value, ErrorInfo>;
}
impl ArithmeticOperation for serde_json::Value {
fn get_type(value: &serde_json::Value) -> String {
match value {
serde_json::Value::Null => "Null".to_string(),
serde_json::Value::Bool(_) => String::from("Bool"),
serde_json::Value::Number(_) => String::from("Number"),
serde_json::Value::String(_) => String::from("String"),
serde_json::Value::Array(_) => String::from("Array"),
serde_json::Value::Object(_) => String::from("Object"),
}
}
fn add(
lhs: &serde_json::Value,
rhs: &serde_json::Value,
interval: &Interval,
) -> Result<serde_json::Value, ErrorInfo> {
match (lhs, rhs) {
(serde_json::Value::Null, serde_json::Value::Null) => Ok(serde_json::Value::Null),
(serde_json::Value::Bool(lhs), serde_json::Value::Bool(rhs)) => {
Ok(serde_json::Value::Bool(lhs | rhs))
}
(serde_json::Value::Number(lhs), serde_json::Value::Number(rhs)) => {
if let (Some(lhs), Some(rhs)) = (lhs.as_i64(), rhs.as_i64()) {
if let Some(value) = lhs.checked_add(rhs) {
return Ok(serde_json::Value::Number(serde_json::Number::from(value)));
}
}
if let (Some(lhs), Some(rhs)) = (lhs.as_f64(), rhs.as_f64()) {
let a = lhs as i64;
let b = rhs as i64;
if a.checked_add(b).is_some() {
if let Some(value) = serde_json::Number::from_f64(lhs + rhs) {
return Ok(serde_json::Value::Number(value));
}
}
}
if let (Some(lhs), Some(rhs)) = (lhs.as_i64(), rhs.as_f64()) {
let b = rhs as i64;
if lhs.checked_add(b).is_some() {
if let Some(value) = serde_json::Number::from_f64(lhs as f64 + rhs) {
return Ok(serde_json::Value::Number(value));
}
}
}
if let (Some(lhs), Some(rhs)) = (lhs.as_f64(), rhs.as_i64()) {
let a = lhs as i64;
if a.checked_add(rhs).is_some() {
if let Some(value) = serde_json::Number::from_f64(lhs + rhs as f64) {
return Ok(serde_json::Value::Number(value));
}
}
}
Err(ErrorInfo::new(
Position::new(*interval),
"Illegal operation: overflow".to_string(),
))
}
(serde_json::Value::String(lhs), serde_json::Value::String(rhs)) => {
Ok(serde_json::Value::String(lhs.to_string() + rhs))
}
(serde_json::Value::Array(lhs), serde_json::Value::Array(rhs)) => {
let mut lhs = lhs.to_owned();
lhs.extend(rhs.to_owned());
Ok(serde_json::Value::Array(lhs))
}
(serde_json::Value::Object(lhs), serde_json::Value::Object(rhs)) => {
let mut lhs = lhs.to_owned();
lhs.extend(rhs.to_owned());
Ok(serde_json::Value::Object(lhs))
}
(serde_json::Value::String(lhs), serde_json::Value::Array(rhs)) => {
let mut rhs = rhs.to_owned();
rhs.push(serde_json::Value::String(lhs.to_owned()));
Ok(serde_json::Value::Array(rhs))
}
(serde_json::Value::Array(lhs), serde_json::Value::String(rhs)) => {
let mut lhs = lhs.to_owned();
lhs.push(serde_json::Value::String(rhs.to_owned()));
Ok(serde_json::Value::Array(lhs))
}
(_, _) => Err(ErrorInfo::new(
Position::new(*interval),
format!(
"Type Error expecting {} type but {} type was found",
serde_json::Value::get_type(rhs),
serde_json::Value::get_type(lhs),
),
)),
}
}
}
fn create_default_object(
object: &serde_json::Map<String, serde_json::Value>,
interval: &Interval,
) -> Result<serde_json::Value, ErrorInfo> {
if let Some(serde_json::Value::String(result)) = object.get("type") {
return match result.as_str() {
"Null" => Ok(serde_json::Value::Null),
"Bool" => Ok(serde_json::Value::Bool(false)),
"Number" => Ok(serde_json::Value::Number(serde_json::Number::from(0))),
"String" => Ok(serde_json::Value::String(String::default())),
"Array" => Ok(serde_json::Value::Array(Vec::default())),
"Object" => Ok(serde_json::Value::Object(serde_json::Map::default())),
_ => Err(ErrorInfo::new(
Position::new(*interval),
format!("type '{}' is unknown", result),
)),
};
}
return Err(ErrorInfo::new(
Position::new(*interval),
"type value must exist on all keys".to_string(),
));
}
fn is_parameter_required(object: &serde_json::Map<String, serde_json::Value>) -> bool {
let mut result = false;
if let Some(serde_json::Value::Bool(value)) = object.get("required") {
result = *value;
}
result
}
fn get_index_of_key(key: &str, array: &[serde_json::Value]) -> Option<usize> {
for (index, object) in array.iter().enumerate() {
if let Some(object) = object.as_object() {
for value in object.keys() {
if key == value {
return Some(index);
}
}
}
}
None
}
fn get_parameter(index_of_key: usize, key: &str, args: &ArgsType) -> Option<serde_json::Value> {
if let Some(value) = args.get(key, index_of_key) {
return Some(value.primitive.to_json());
}
None
}
fn actions_exist(object: &serde_json::Map<String, serde_json::Value>) -> Option<()> {
match (object.get("default_value"), object.get("add_value")) {
(Some(default), Some(add)) => match (default.as_array(), add.as_array()) {
(Some(default), Some(add)) => {
if default.is_empty() && add.is_empty() {
None
} else {
Some(())
}
}
(None, Some(value)) | (Some(value), None) => {
if value.is_empty() {
None
} else {
Some(())
}
}
(None, None) => None,
},
(None, Some(value)) | (Some(value), None) => {
if let Some(value) = value.as_array() {
if value.is_empty() {
None
} else {
Some(())
}
} else {
Some(())
}
}
(None, None) => None,
}
}
fn get_result(
name: &str,
is_custom_component: bool,
hashmap: &HashMap<String, Literal>,
interval: Interval,
) -> Literal {
let mut result = PrimitiveObject::get_literal(&hashmap, interval);
if is_custom_component {
result.set_content_type(&format!("Component.{}", name.to_lowercase()));
} else {
result.set_content_type(&name.to_lowercase());
}
result
}
fn get_default_object(
key: &str,
object: &serde_json::Map<String, serde_json::Value>,
array: &[serde_json::Value],
args: &ArgsType,
interval: &Interval,
memoization: &mut HashMap<String, serde_json::Value>,
recursion: &mut HashSet<String>,
) -> Result<serde_json::Value, ErrorInfo> {
let mut result = create_default_object(object, interval)?;
if let Some(serde_json::Value::Array(default_value)) = object.get(key) {
for function in default_value.iter() {
if let serde_json::Value::Object(function) = function {
if let Some(serde_json::Value::String(dependency)) = function.get("$_get") {
match memoization.get(dependency) {
Some(value) => {
result = serde_json::Value::add(&result, &value, interval)?;
}
None => {
if recursion.contains(dependency) {
return Err(ErrorInfo::new(
Position::new(*interval),
"GENERIC_COMPONENT_CIRCULAR_DEPENDENCY".to_string(),
));
}
let value = &get_object(
dependency,
array,
args,
interval,
memoization,
recursion,
)?;
if let Some(value) = value {
memoization.insert(dependency.to_string(), value.to_owned());
result = serde_json::Value::add(&result, value, interval)?;
}
}
}
}
if let Some(dependency) = function.get("$_set") {
result = serde_json::Value::add(&result, dependency, interval)?;
}
}
}
}
Ok(result)
}
fn get_object(
key: &str,
array: &[serde_json::Value],
args: &ArgsType,
interval: &Interval,
memoization: &mut HashMap<String, serde_json::Value>,
recursion: &mut HashSet<String>,
) -> Result<Option<serde_json::Value>, ErrorInfo> {
if !recursion.insert(key.to_string()) {
eprintln!("SHOULD NEVER HAPPEN !");
unreachable!();
}
if let Some(index_of_key) = get_index_of_key(key, array) {
if let Some(serde_json::Value::Object(object)) = array[index_of_key].get(key) {
return match (
get_parameter(index_of_key, key, args),
is_parameter_required(object),
) {
(Some(param), _) => Ok(Some(serde_json::Value::add(
¶m,
&get_default_object(
"add_value",
object,
array,
args,
interval,
memoization,
recursion,
)?,
interval,
)?)),
(None, true) => {
Err(ErrorInfo::new(
Position::new(*interval),
format!("{} is a required parameter", key),
))
}
(None, false) => {
if actions_exist(object).is_none() {
Ok(None)
} else {
Ok(Some(serde_json::Value::add(
&get_default_object(
"default_value",
object,
array,
args,
interval,
memoization,
recursion,
)?,
&get_default_object(
"add_value",
object,
array,
args,
interval,
memoization,
recursion,
)?,
interval,
)?))
}
}
};
}
}
Ok(None)
}
pub fn gen_generic_component(
name: &str,
is_custom_component: bool,
interval: &Interval,
args: &ArgsType,
component: &serde_json::Value,
) -> Result<Literal, ErrorInfo> {
let mut hashmap: HashMap<String, Literal> = HashMap::new();
let mut memoization: HashMap<String, serde_json::Value> = HashMap::new();
if let Some(object) = component.as_object() {
if let Some(serde_json::Value::Array(array)) = object.get("params") {
for object in array.iter() {
if let Some(object) = object.as_object() {
for key in object.keys() {
if let Some(result) = memoization.get(key) {
hashmap.insert(
key.to_owned(),
json_to_literal(&result.to_owned(), *interval)?,
);
} else {
let result = get_object(
key,
array,
args,
interval,
&mut memoization,
&mut HashSet::new(),
)?;
if let Some(result) = result {
hashmap.insert(
key.to_owned(),
json_to_literal(&result.to_owned(), *interval)?,
);
}
}
}
}
}
args.populate_json_to_literal(&mut hashmap, array, interval.to_owned())?;
}
}
Ok(get_result(name, is_custom_component, &hashmap, *interval))
}