use super::linear::extract_numeric;
use crate::Result;
use crate::blocks::common::{BlockHeader, BlockParse, read_string_block};
use crate::blocks::conversion::base::ConversionBlock;
use crate::types::DecodedValue;
pub fn find_range_to_text_index(values: &[f64], raw: f64, inclusive_upper: bool) -> usize {
let len = values.len();
if len < 2 || !len.is_multiple_of(2) {
return 0;
}
let n = len / 2;
for i in 0..n {
let min = values[2 * i];
let max = values[2 * i + 1];
if inclusive_upper {
if raw >= min && raw <= max {
return i;
}
} else if raw >= min && raw < max {
return i;
}
}
n
}
pub fn apply_value_to_text(
block: &ConversionBlock,
value: DecodedValue,
file_data: &[u8],
) -> Result<DecodedValue> {
let raw = match extract_numeric(&value) {
Some(x) => x,
None => return Ok(value),
};
let idx = block
.values
.iter()
.position(|&k| k == raw)
.unwrap_or(block.values.len());
#[cfg(feature = "std")]
{
if let Some(resolved_text) = block.get_resolved_text(idx) {
return Ok(DecodedValue::String(resolved_text.clone()));
}
if let Some(resolved_conversion) = block.get_resolved_conversion(idx) {
return resolved_conversion.apply_decoded(value, &[]);
}
}
if idx >= block.values.len() {
if let Some(default_conversion) = block.get_default_conversion() {
return default_conversion.apply_decoded(value, &[]);
}
}
let link = *block.refs.get(idx).unwrap_or(&0);
if link == 0 {
if let Some(default_conversion) = block.get_default_conversion() {
return default_conversion.apply_decoded(value, &[]);
}
return Ok(DecodedValue::Unknown);
}
let off = link as usize;
if off + 24 > file_data.len() {
if let Some(default_conversion) = block.get_default_conversion() {
return default_conversion.apply_decoded(value, &[]);
}
return Ok(DecodedValue::Unknown);
}
let hdr = BlockHeader::from_bytes(&file_data[off..off + 24])?;
if hdr.id == "##TX" {
if let Some(txt) = read_string_block(file_data, link)? {
return Ok(DecodedValue::String(txt));
}
if let Some(default_conversion) = block.get_default_conversion() {
return default_conversion.apply_decoded(value, &[]);
}
return Ok(DecodedValue::Unknown);
}
if hdr.id == "##CC" {
let mut nested = ConversionBlock::from_bytes(&file_data[off..])?;
let _ = nested.resolve_formula(file_data);
return nested.apply_decoded(value, file_data);
}
if let Some(default_conversion) = block.get_default_conversion() {
return default_conversion.apply_decoded(value, &[]);
}
Ok(DecodedValue::Unknown)
}
pub fn apply_range_to_text(
block: &ConversionBlock,
value: DecodedValue,
file_data: &[u8],
) -> Result<DecodedValue> {
let raw = match extract_numeric(&value) {
Some(x) => x,
None => return Ok(value),
};
let inclusive_upper = matches!(
value,
DecodedValue::UnsignedInteger(_) | DecodedValue::SignedInteger(_)
);
let idx = find_range_to_text_index(&block.values, raw, inclusive_upper);
let n_ranges = block.values.len() / 2;
#[cfg(feature = "std")]
{
if let Some(resolved_text) = block.get_resolved_text(idx) {
return Ok(DecodedValue::String(resolved_text.clone()));
}
if let Some(resolved_conversion) = block.get_resolved_conversion(idx) {
return resolved_conversion.apply_decoded(value, &[]);
}
}
if idx >= n_ranges {
if let Some(default_conversion) = block.get_default_conversion() {
return default_conversion.apply_decoded(value, &[]);
}
}
let link = *block.refs.get(idx).unwrap_or(&0);
if link == 0 {
if let Some(default_conversion) = block.get_default_conversion() {
return default_conversion.apply_decoded(value, &[]);
}
return Ok(DecodedValue::Unknown);
}
let off = link as usize;
if off + 24 > file_data.len() {
if let Some(default_conversion) = block.get_default_conversion() {
return default_conversion.apply_decoded(value, &[]);
}
return Ok(DecodedValue::Unknown);
}
let hdr = BlockHeader::from_bytes(&file_data[off..off + 24])?;
if hdr.id == "##TX" {
return match read_string_block(file_data, link)? {
Some(txt) => Ok(DecodedValue::String(txt)),
None => {
if let Some(default_conversion) = block.get_default_conversion() {
default_conversion.apply_decoded(value, &[])
} else {
Ok(DecodedValue::Unknown)
}
}
};
}
if hdr.id == "##CC" {
let mut nested = ConversionBlock::from_bytes(&file_data[off..])?;
let _ = nested.resolve_formula(file_data);
return nested.apply_decoded(value, file_data);
}
if let Some(default_conversion) = block.get_default_conversion() {
return default_conversion.apply_decoded(value, &[]);
}
Ok(DecodedValue::Unknown)
}
pub fn apply_text_to_value(
block: &ConversionBlock,
value: DecodedValue,
file_data: &[u8],
) -> Result<DecodedValue> {
let input = match value {
DecodedValue::String(s) => s,
other => return Ok(other),
};
let n = block.refs.len();
#[cfg(feature = "std")]
if let Some(resolved_texts) = &block.resolved_texts {
for (i, resolved_text) in resolved_texts.iter() {
if *i < n && input == *resolved_text {
if *i < block.values.len() {
return Ok(DecodedValue::Float(block.values[*i]));
} else {
return Ok(DecodedValue::Unknown);
}
}
}
if block.values.len() > n {
return Ok(DecodedValue::Float(block.values[n]));
} else {
return Ok(DecodedValue::Unknown);
}
}
for i in 0..n {
let link = block.refs[i];
if link == 0 {
continue;
}
if let Some(key_str) = read_string_block(file_data, link)? {
if input == key_str {
if i < block.values.len() {
return Ok(DecodedValue::Float(block.values[i]));
} else {
return Ok(DecodedValue::Unknown);
}
}
}
}
if block.values.len() > n {
Ok(DecodedValue::Float(block.values[n]))
} else {
Ok(DecodedValue::Unknown)
}
}
pub fn apply_text_to_text(
block: &ConversionBlock,
value: DecodedValue,
file_data: &[u8],
) -> Result<DecodedValue> {
let input = match value {
DecodedValue::String(s) => s,
other => return Ok(other),
};
let pairs = block.refs.len().saturating_sub(1) / 2;
#[cfg(feature = "std")]
if let Some(resolved_texts) = &block.resolved_texts {
for i in 0..pairs {
let key_idx = 2 * i;
let output_idx = 2 * i + 1;
if let Some(key_str) = resolved_texts.get(&key_idx) {
if *key_str == input {
return if let Some(output_str) = resolved_texts.get(&output_idx) {
Ok(DecodedValue::String(output_str.clone()))
} else {
Ok(DecodedValue::String(input))
};
}
}
}
let default_idx = 2 * pairs;
if let Some(default_str) = resolved_texts.get(&default_idx) {
return Ok(DecodedValue::String(default_str.clone()));
} else {
return Ok(DecodedValue::String(input));
}
}
for i in 0..pairs {
let key_link = block.refs[2 * i];
let output_link = block.refs[2 * i + 1];
if let Some(key_str) = read_string_block(file_data, key_link)? {
if key_str == input {
return if output_link == 0 {
Ok(DecodedValue::String(input))
} else {
Ok(read_string_block(file_data, output_link)?
.map(DecodedValue::String)
.unwrap_or(DecodedValue::String(input)))
};
}
}
}
let default_link = *block.refs.get(2 * pairs).unwrap_or(&0);
if default_link == 0 {
Ok(DecodedValue::String(input))
} else {
Ok(read_string_block(file_data, default_link)?
.map(DecodedValue::String)
.unwrap_or(DecodedValue::String(input)))
}
}