use logisheets_base::{SheetId, index_to_column_label};
use crate::block_manager::schema_manager::{SchemaManager, schema::Schema};
use crate::navigator::Navigator;
use super::ChartBlockSource;
pub struct ResolvedBlockRefs {
pub cat_ref: Option<String>,
pub series: Vec<(String, String)>,
}
pub fn resolve_block_refs(
navigator: &Navigator,
schemas: &SchemaManager,
sheet_id: SheetId,
sheet_name: &str,
source: &ChartBlockSource,
) -> Option<ResolvedBlockRefs> {
let bp = navigator
.get_block_place(&sheet_id, &source.block_id)
.ok()?;
let (row_start, col_start) = navigator
.fetch_normal_cell_idx(&sheet_id, &bp.master)
.ok()?;
let schema = schemas.schemas.get(&(sheet_id, source.block_id))?;
let fields_are_columns = match schema {
Schema::RowSchema(_) => true,
Schema::ColSchema(_) => false,
Schema::RandomSchema(_) => return None,
};
let record_cnt = if fields_are_columns {
bp.rows.len()
} else {
bp.cols.len()
};
if record_cnt == 0 {
return None;
}
let field_offset = |name: &str| -> Option<usize> {
let id = schema_resolve_field_id(schema, name)?;
if fields_are_columns {
bp.cols.iter().position(|c| *c == id)
} else {
bp.rows.iter().position(|r| *r == id)
}
};
let range_for = |field_offset: usize| -> String {
let (sr, er, sc, ec) = if fields_are_columns {
(
row_start,
row_start + record_cnt - 1,
col_start + field_offset,
col_start + field_offset,
)
} else {
(
row_start + field_offset,
row_start + field_offset,
col_start,
col_start + record_cnt - 1,
)
};
format!(
"{}!${}${}:${}${}",
quote_sheet(sheet_name),
index_to_column_label(sc),
sr + 1,
index_to_column_label(ec),
er + 1,
)
};
let cat_ref = source
.category_field
.as_deref()
.and_then(field_offset)
.map(range_for);
let series = source
.value_fields
.iter()
.filter_map(|name| field_offset(name).map(|o| (name.clone(), range_for(o))))
.collect::<Vec<_>>();
if series.is_empty() {
return None;
}
Some(ResolvedBlockRefs { cat_ref, series })
}
fn schema_resolve_field_id(schema: &Schema, name: &str) -> Option<u32> {
match schema {
Schema::RowSchema(s) => s.field_axis_by_name(name),
Schema::ColSchema(s) => s.field_axis_by_name(name),
Schema::RandomSchema(_) => None,
}
}
fn quote_sheet(name: &str) -> String {
let needs = name.is_empty()
|| name
.chars()
.any(|c| !(c.is_alphanumeric() || c == '_' || c == '.'))
|| name.chars().next().is_some_and(|c| c.is_ascii_digit());
if needs {
format!("'{}'", name.replace('\'', "''"))
} else {
name.to_string()
}
}