1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use crate::models::{Range, State, Token, WCode, WFuncVariant, WTokens};
use crate::parser::WParser;
use crate::utils::{Utils, WFunc};
use itertools::Itertools;

pub trait WEval {
    fn apply(&mut self, code: &str) -> Vec<WTokens>;
    fn wsection_eval(&mut self, data: Vec<WCode>) -> Vec<WTokens>;
    fn eval(&self, data: WTokens) -> WTokens;
    fn dissolve(&self, code: &mut WTokens, func: WFuncVariant, first_func_pos: usize, arr: WTokens);
}

impl WEval for State {
    fn apply(&mut self, code: &str) -> Vec<WTokens> {
        self.wsection_eval(self.parser(code))
    }

    fn wsection_eval(&mut self, data: Vec<WCode>) -> Vec<WTokens> {
        let mut result: Vec<WTokens> = Vec::new();

        for section in data {
            match section.container {
                Some(container) => {
                    let mut cases = vec![];

                    if let Some(container_cases) = section.cases {
                        cases.append(&mut container_cases.clone())
                    }

                    cases.push((vec![Token::Value(1.0)], section.default_case));

                    self.insert(container, cases);
                }
                None => result.push(self.eval(section.default_case)),
            }
        }

        result
    }

    fn eval(&self, data: WTokens) -> WTokens {
        let mut new_code = data.clone();

        while let Some((first_func_pos, func)) = new_code.last_function() {
            let first = new_code.first_special_instance("(".to_string());
            let second = match first {
                Some(x) => new_code.special_pairs(("(".to_string(), ")".to_string()), &x),
                None => None,
            };

            if let (Some(x), Some(y)) = (first, second) {
                let mut result = new_code[x + 1..y].to_vec();
                if let Some((first_func_pos, func)) = result.last_function() {
                    let code_to_evaluate = result[..first_func_pos].to_vec();
                    self.dissolve(&mut result, func, first_func_pos, code_to_evaluate);
                    result.skin_content();
                    new_code.splice(x + 1..y, result);
                } else {
                    new_code.splice(x..=y, result);
                }
            } else {
                let code_to_evaluate: WTokens = new_code[..first_func_pos].to_vec();
                self.dissolve(&mut new_code, func, first_func_pos, code_to_evaluate);
            }
        }

        new_code
    }

    fn dissolve(
        &self,
        code: &mut WTokens,
        func: WFuncVariant,
        first_func_pos: usize,
        arr: WTokens,
    ) {
        match func {
            WFuncVariant::Function(func) => {
                let result = func(arr);
                code.splice(..first_func_pos + 1, result);
            }
            WFuncVariant::Container(x) => {
                let mut case: WTokens = vec![];
                let mut container_acc: WTokens = vec![];

                for container_case in self.get(&x).unwrap() {
                    let mut joined = container_case.0.clone();
                    joined.append(&mut container_case.1.clone());
                    container_acc.append(&mut joined);

                    let case_prefix = self.eval(self.apply(&container_case.0, &arr));

                    if case_prefix[0] != Token::Value(0.0) {
                        case = container_case.1.clone();
                        break;
                    }
                }

                let expanded_range = container_acc
                    .iter()
                    .filter(|x| matches!(x, Token::Parameter(_)))
                    .map(|range| match range {
                        Token::Parameter(Range::Full(full)) => full.clone().collect::<Vec<_>>(),
                        Token::Parameter(Range::From(from)) => (0..=from.end).collect::<Vec<_>>(),
                        Token::Parameter(Range::To(to)) => {
                            (to.start..=arr.len() - 1).collect::<Vec<_>>()
                        }
                        _ => panic!(),
                    })
                    .flatten()
                    .unique()
                    .map(|wlang_index| arr.len() - (wlang_index + 1))
                    .sorted()
                    .rev()
                    .collect::<Vec<usize>>();

                let result = self.apply(&case, &arr);
                code.splice(first_func_pos..=first_func_pos, result);
                for n in expanded_range {
                    code.remove(n);
                }
            }
        }
    }
}