use crate::cells::{push_identity, push_money};
use crate::error::FormsError;
use crate::map::ScheduleBMap;
use crate::pdf;
use crate::verify::{verify_flat, FlatPlacement};
use btctax_core::tax::packet::ReturnHeader;
use btctax_core::tax::printed::ScheduleBLines;
const COL_PAYER: usize = 0;
const COL_AMOUNT: usize = 1;
const SCHEDULE_B_CLUSTERS: &[(f32, f32)] = &[(129.0, 461.0), (489.0, 576.0)];
const GRP_AMOUNTS: u32 = 0;
const GRP_PAYERS: u32 = 1;
pub fn fill_schedule_b_with_map(
lines: &ScheduleBLines,
header: &ReturnHeader,
map: &ScheduleBMap,
) -> Result<Vec<u8>, FormsError> {
if lines.part1_rows.len() > map.part1_rows.len() {
return Err(FormsError::Overflow {
part: "Schedule B Part I",
rows: lines.part1_rows.len(),
capacity: map.part1_rows.len(),
});
}
if lines.part2_rows.len() > map.part2_rows.len() {
return Err(FormsError::Overflow {
part: "Schedule B Part II",
rows: lines.part2_rows.len(),
capacity: map.part2_rows.len(),
});
}
let mut writes: Vec<(String, pdf::FieldValue)> = Vec::new();
let mut placements: Vec<FlatPlacement> = Vec::new();
let (mut amt_ord, mut payer_ord) = (0u32, 0u32);
for (row, cell) in lines.part1_rows.iter().zip(map.part1_rows.iter()) {
writes.push((cell.payer.clone(), pdf::FieldValue::Text(row.payer.clone())));
placements.push(FlatPlacement::cell(
cell.payer.clone(),
0,
COL_PAYER,
GRP_PAYERS,
payer_ord,
));
payer_ord += 1;
push_money(
&mut writes,
&mut placements,
&cell.amount,
row.amount,
COL_AMOUNT,
Some((GRP_AMOUNTS, amt_ord)),
);
amt_ord += 1;
}
for (cell, value) in [(&map.line2, lines.line2), (&map.line4, lines.line4)] {
push_money(
&mut writes,
&mut placements,
cell,
value,
COL_AMOUNT,
Some((GRP_AMOUNTS, amt_ord)),
);
amt_ord += 1;
}
for (row, cell) in lines.part2_rows.iter().zip(map.part2_rows.iter()) {
writes.push((cell.payer.clone(), pdf::FieldValue::Text(row.payer.clone())));
placements.push(FlatPlacement::cell(
cell.payer.clone(),
0,
COL_PAYER,
GRP_PAYERS,
payer_ord,
));
payer_ord += 1;
push_money(
&mut writes,
&mut placements,
&cell.amount,
row.amount,
COL_AMOUNT,
Some((GRP_AMOUNTS, amt_ord)),
);
amt_ord += 1;
}
push_money(
&mut writes,
&mut placements,
&map.line6,
lines.line6,
COL_AMOUNT,
Some((GRP_AMOUNTS, amt_ord)),
);
for (pair, answer) in [
(&map.line7a, lines.foreign_accounts_7a),
(&map.line8, lines.foreign_trust_8),
] {
let choice = if answer { &pair.yes } else { &pair.no };
writes.push((
choice.field.clone(),
pdf::FieldValue::Check {
on: choice.on.clone(),
},
));
placements.push(FlatPlacement::check(choice.field.clone(), 0));
}
let mut doc = pdf::load(pdf::schedule_b_pdf(map.year)?)?;
let blank_fields = pdf::collect_fields(&doc)?;
push_identity(
&mut writes,
&mut placements,
&map.identity,
&header.name_line,
&header.taxpayer.ssn,
&blank_fields,
)?;
if !lines.line7b_countries.is_empty() {
writes.push((
map.line7b_countries.clone(),
pdf::FieldValue::Text(lines.line7b_countries.clone()),
));
placements.push(FlatPlacement::free(
map.line7b_countries.clone(),
crate::cells::page_of(&map.line7b_countries),
));
}
let index = pdf::index(&blank_fields);
pdf::drop_xfa_and_set_needappearances(&mut doc)?;
pdf::apply_writes(&mut doc, &index, &writes)?;
pdf::strip_nondeterminism(&mut doc);
let bytes = pdf::save(&mut doc)?;
let check = pdf::load(&bytes)?;
let fields = pdf::collect_fields(&check)?;
verify_flat(&check, &fields, &placements, SCHEDULE_B_CLUSTERS)?;
Ok(bytes)
}