use super::super::geom::{Cell, Cover, Rect};
use super::super::store::{Store, TagFilter};
use super::support::Rng;
use crate::engine::named_range::{NameScope, NamedDefinition};
use crate::engine::{Engine, EvalConfig};
use crate::reference::{CellRef, Coord, RangeRef};
use crate::test_workbook::TestWorkbook;
use formualizer_common::LiteralValue;
use formualizer_parse::parse;
pub const ROWS: u32 = 30;
pub const COLS: u32 = 10;
pub const MENU: &[&str] = &[
"=A{r}*2",
"=A{r}+B{p}",
"=SUM($A$1:A{r})",
"=SUM(A:A)",
"=Data!A{r}+1",
"=NCell+A{r}",
"=SUM(NRange)",
"=Loc*2",
"=NF*3",
"=SUM(T1[X])",
"=SUM(3:3)",
"=SUM(A{r}:B{n})",
"=IF(A{r}>0,B{r},D{p})",
"=INDIRECT(\"A1\")+A{r}",
"=MissingName+1",
"=SUM(Sheet1:Data!A1)",
"=D{r}+E{p}",
"=SUM($D$2:$D$6)*A{r}",
"=B$4+$C{r}",
"=Data!$B$2:$C$3",
"=SUM(Data!B:B)+{r}",
];
pub fn text(t: &str, row1: u32) -> String {
t.replace("{r}", &row1.to_string())
.replace("{p}", &(row1.max(2) - 1).to_string())
.replace("{n}", &(row1 + 1).to_string())
}
pub fn fixture_engine() -> Engine<TestWorkbook> {
let mut e = Engine::new(TestWorkbook::new(), EvalConfig::default());
e.add_sheet("Data").unwrap();
for sheet in ["Sheet1", "Data"] {
for r in 1..=ROWS {
e.set_cell_value(sheet, r, 1, LiteralValue::Number(f64::from(r)))
.unwrap();
e.set_cell_value(sheet, r, 2, LiteralValue::Number(f64::from(r) * 2.0))
.unwrap();
}
}
let s1 = e.graph.sheet_id("Sheet1").unwrap();
let data = e.graph.sheet_id("Data").unwrap();
let cell = |s, r, c| CellRef::new(s, Coord::new(r, c, true, true));
e.define_name(
"NCell",
NamedDefinition::Cell(cell(s1, 4, 0)),
NameScope::Workbook,
)
.unwrap();
e.define_name(
"NRange",
NamedDefinition::Range(RangeRef::new(cell(data, 1, 1), cell(data, 8, 2))),
NameScope::Workbook,
)
.unwrap();
e.define_name(
"Loc",
NamedDefinition::Cell(cell(data, 0, 0)),
NameScope::Sheet(s1),
)
.unwrap();
e.define_name(
"NF",
NamedDefinition::Formula {
ast: parse("=Sheet1!A2+SUM(Data!B3:B4)+NCell").unwrap(),
dependencies: vec![],
range_deps: vec![],
},
NameScope::Workbook,
)
.unwrap();
e.define_table(
"T1",
RangeRef::new(cell(data, 0, 4), cell(data, 9, 5)),
true,
vec!["X".into(), "Y".into()],
false,
)
.unwrap();
e
}
pub fn populate(e: &mut Engine<TestWorkbook>, g: &mut Rng) {
for (sheet, cols) in [("Sheet1", 3..=8u32), ("Data", 7..=9u32)] {
for col in cols {
let mut r = 1;
while r <= ROWS {
let t = MENU[g.below(MENU.len() as u32) as usize];
let run = if g.chance(60) { g.below(12) + 2 } else { 1 };
for rr in r..(r + run).min(ROWS + 1) {
if g.chance(85) {
let _ = e.set_cell_formula(sheet, rr, col, parse(text(t, rr)).unwrap());
}
}
r += run + g.below(3);
}
}
}
}
pub fn query_cells(e: &Engine<TestWorkbook>) -> Vec<Cell> {
let mut v = Vec::new();
for sheet in ["Sheet1", "Data"] {
let s = e.graph.sheet_id(sheet).unwrap();
for r in 0..ROWS + 3 {
for c in 0..COLS + 1 {
v.push((s, r, c));
}
}
v.push((s, 1_048_575, 0));
v.push((s, 2, 16_383));
}
v
}
pub fn rebuild_from_graph(e: &Engine<TestWorkbook>) -> Store {
Store::build(e.graph.authority_build_input())
}
pub fn store_direct(s: &Store, q: Cell, f: TagFilter) -> Vec<Cell> {
s.direct_grid_dependents(q.0, &Rect::cell(q.1, q.2), f)
.cells()
}
pub fn store_closure(s: &Store, q: Cell, f: TagFilter) -> Vec<Cell> {
s.dependents(&[(q.0, Rect::cell(q.1, q.2))], f)
.0
.cells()
.into_iter()
.filter(|c| c.0 != super::super::geom::SYMBOL_SHEET)
.collect()
}
pub fn store_precedent_cells(s: &Store, cell: Cell, f: TagFilter) -> Vec<Cell> {
let mut hits = Vec::new();
s.direct_grid_precedents(cell, f, &mut hits);
let mut cover = Cover::new();
for (_, sh, r) in hits {
if let Some(r) = r.intersect(&Rect::new(0, 0, ROWS, COLS)) {
cover.insert_rect(sh, &r);
}
}
cover.cells()
}