use std::collections::HashMap;
use crate::phighlighter::{
pactionhighlight::PActionHighLight, pfileparser::PFileParserIter, phighlighter::PHighlighterGetUntilReplace, phighlither_configuration::{
PHighlighterGetUntil,
PHighlighterSequence,
}
};
#[derive(Debug,Clone)]
struct PNodeHighlightIter<'a>{
p_current_node: &'a PNodeHighLight,
}
impl<'a> PNodeHighlightIter<'a> {
fn new(node_highlight: &'a PNodeHighLight) -> Self{
PNodeHighlightIter{
p_current_node: node_highlight,
}
}
fn next(&mut self, current_char: u8) -> bool{
if self.p_current_node.is_oneof() {
let str_char = String::from(current_char as char);
if self.p_current_node.p_pattern.contains(&str_char) {
return true; }
}
match self.p_current_node.p_map_sequence.get(¤t_char) {
Some(child) => { self.p_current_node = child;
true
},
None => {
false
}
}
}
}
#[derive(Debug,Clone)]
struct PVecNodeHighlightIter<'a>{
p_vec_possible_node: Vec<PNodeHighlightIter<'a>>,
}
impl<'a> PVecNodeHighlightIter<'a> {
fn new(node_highlight: &'a PNodeHighLight) -> Self{
let mut other = PVecNodeHighlightIter{
p_vec_possible_node: vec![],
};
other.p_vec_possible_node.push(PNodeHighlightIter::new(node_highlight));
for oneof_node in node_highlight.p_vec_oneof.iter(){
other.p_vec_possible_node.push(PNodeHighlightIter::new(oneof_node));
}
return other;
}
fn next(&mut self, current_char: u8) -> Option<usize>{
let mut vec_remaning_oneof: Vec<PNodeHighlightIter<'a>> = vec![];
let mut vec_available_action_index: Vec<usize> = vec![];
for node in self.p_vec_possible_node.iter_mut() {
if node.next(current_char) {
vec_remaning_oneof.push(node.clone());
for child_oneof in node.p_current_node.p_vec_oneof.iter() {
vec_remaning_oneof.push(PNodeHighlightIter::new(child_oneof));
}
}else{
match node.p_current_node.p_action_index {
Some(action_index) => vec_available_action_index.push(action_index),
None => {}
}
}
}
if vec_remaning_oneof.is_empty() {
return match vec_available_action_index.first() {
Some(first_action) => Some(*first_action),
None => Some(0)
};
}
self.p_vec_possible_node = vec_remaning_oneof;
return None;
}
fn highlight(&mut self, body: &mut String, current_match_token: &mut String, it: &mut PFileParserIter, vec_action: &Vec<PActionHighLight>,
token_charset: &String)
{
while !it.is_end_of_file() {
match it.get_current_char() {
Some(current_char) => {
match self.next(current_char) {
Some(action_index) => {
highlight_run_action(action_index, current_char, body, current_match_token, it, vec_action, token_charset);
break; },
None => { it.next(); *current_match_token += &String::from(current_char as char); }
}
},
None => {} };
}
}
}
fn highlight_run_action(action_index: usize, current_char: u8, body: &mut String, current_match_token: &mut String, it: &mut PFileParserIter, vec_action: &Vec<PActionHighLight>, token_charset: &String){
match vec_action.get(action_index) {
Some(action) => {
if current_match_token.len() == 0 { *body += &String::from(current_char as char);
it.next(); }else{
*body += &action.run(it, ¤t_match_token, token_charset);
*current_match_token = String::from(""); }
},
None => panic!("highlight_run_action : no action {} to be performed at {}", action_index, it.get_location())
}
}
fn create_vec_is_required(sequence: &PHighlighterSequence) -> Vec<bool>{
let mut is_last_required: bool = false;
let mut vec_is_required: Vec<bool> = vec![];
for step in sequence.vec_step.iter().rev() {
match &step.token {
Some(_) => {
vec_is_required.push(is_last_required);
is_last_required = true;
},
None => match &step.keyword {
Some(_) => {
vec_is_required.push(is_last_required);
is_last_required = true;
},
None => match &step.oneof {
Some(_) => {
vec_is_required.push(is_last_required);
},
None => {}
}
}
}
}
vec_is_required.reverse();
return vec_is_required;
}
#[derive(Debug,Default,Clone)]
pub struct PNodeHighLight{
p_action_index: Option<usize>,
p_pattern: String,
p_map_sequence: HashMap<u8, PNodeHighLight>,
p_vec_oneof: Vec<PNodeHighLight>,
}
impl PNodeHighLight {
pub fn new(action_index: &Option<usize>, pattern: &String) -> Self{
PNodeHighLight{
p_action_index: action_index.clone(),
p_pattern: pattern.clone(),
p_map_sequence: HashMap::default(),
p_vec_oneof: vec![]
}
}
pub fn is_oneof(&self) -> bool{
return !self.p_pattern.is_empty();
}
pub fn add_token(&mut self, token: &String, action_index: &Option<usize>){
let vec_byte: Vec<u8> = Vec::from(token.clone().into_bytes());
self.add_vec_u8(&vec_byte, action_index);
}
pub fn add_vec_u8(&mut self, token: &Vec<u8>, action_index: &Option<usize>){
let mut last_node = self;
for ch in token.iter() {
let map_sequence = &mut last_node.p_map_sequence;
if !map_sequence.contains_key(ch) {
let node: PNodeHighLight = Default::default();
map_sequence.insert(*ch, node);
}
last_node = map_sequence.get_mut(ch).unwrap();
}
last_node.p_action_index = action_index.clone();
}
pub fn add_getuntil(&mut self, getuntil: &PHighlighterGetUntil, action_index: usize){
let vec_byte: Vec<u8> = Vec::from(getuntil.start_token.clone().into_bytes());
self.add_vec_u8(&vec_byte, &Some(action_index));
}
pub fn add_getuntilreplace(&mut self, getuntilreplace: &PHighlighterGetUntilReplace, action_index: usize){
let vec_byte: Vec<u8> = Vec::from(getuntilreplace.start_token.clone().into_bytes());
self.add_vec_u8(&vec_byte, &Some(action_index));
}
pub fn add_sequence(&mut self, sequence: &PHighlighterSequence, action_index: &Option<usize>){
let vec_is_required: Vec<bool> = create_vec_is_required(sequence);
let mut last_node = self;
for (step, is_last_required) in sequence.vec_step.iter().zip(vec_is_required.iter()){
match &step.token {
Some(token) => {
let vec_byte: Vec<u8> = Vec::from(token.clone().into_bytes());
last_node = last_node.get_child_mut(&vec_byte);
if *is_last_required {
last_node.p_action_index = None; }else{
last_node.p_action_index = action_index.clone();
}
},
None => match &step.keyword {
Some(keyword) => {
let vec_byte: Vec<u8> = Vec::from(keyword.clone().into_bytes());
last_node = last_node.get_child_mut(&vec_byte);
if *is_last_required {
last_node.p_action_index = None; }else{
last_node.p_action_index = action_index.clone();
}
},
None => match &step.oneof {
Some(oneof) => {
let node_action: Option<usize> = if *is_last_required {
None }else{
action_index.clone()
};
let oneof_node = PNodeHighLight::new(&node_action, oneof);
last_node.p_vec_oneof.push(oneof_node);
last_node = last_node.p_vec_oneof.last_mut().unwrap();
},
None => {}
}
}
};
}
}
fn get_child_mut(&mut self, token: &Vec<u8>) -> &mut PNodeHighLight{
let mut last_node = self;
for ch in token.iter() {
let map_sequence = &mut last_node.p_map_sequence;
if !map_sequence.contains_key(ch) {
let node: PNodeHighLight = Default::default();
map_sequence.insert(*ch, node);
}
last_node = map_sequence.get_mut(ch).unwrap();
}
return last_node;
}
pub fn highlight(&self, body: &mut String, current_match_token: &mut String, it: &mut PFileParserIter,
vec_action: &Vec<PActionHighLight>, token_charset: &String)
{
let mut vec_node_iter = PVecNodeHighlightIter::new(self);
vec_node_iter.highlight(body, current_match_token, it, vec_action, token_charset);
return;
}
}