use crate::args::SvgArg;
use crate::tag::Tag;
use crate::unit::px;
use crate::write::{qcast, CDNum, SvgIO, SvgWrite};
use std::fmt::Debug;
use std::fs::File;
use std::path::{Path, PathBuf};
use std::process::Command;
pub struct Pages<NT: CDNum> {
flip: bool,
page_dims: Option<(NT, NT)>,
grid_shape: Option<(usize, usize)>,
card_size: Option<(NT, NT)>,
margin: NT,
}
impl<NT: CDNum> Pages<NT> {
pub fn build() -> Pages<NT> {
Pages {
flip: false,
page_dims: None,
grid_shape: None,
card_size: None,
margin: qcast(40),
}
}
pub fn flip(mut self) -> Self {
self.flip = true;
self
}
pub fn page_size(mut self, w: NT, h: NT) -> Self {
self.page_dims = Some((w, h));
self
}
pub fn with_margin(mut self, m: NT) -> Self {
self.margin = m;
self
}
pub fn grid_size(mut self, nw: usize, nh: usize) -> Self {
self.grid_shape = Some((nw, nh));
self
}
pub fn card_size(mut self, cw: NT, ch: NT) -> Self {
self.card_size = Some((cw, ch));
self
}
pub fn write_page<W, I, C, F, E, E2>(
&mut self,
svg: &mut W,
it: &mut I,
f: F,
) -> Result<usize, E2>
where
W: SvgWrite<Err = E>,
I: Iterator<Item = C>,
F: Fn(&mut dyn SvgWrite<Err = E>, NT, NT, C) -> Result<(), E2>,
C: Debug,
E2: From<E>,
{
self.write_page_with_init(svg, it, f, |_, _, _| -> Result<(), E2> { Ok(()) })
}
pub fn write_page_with_init<W, I, C, F, F2, E, E2>(
&mut self,
svg: &mut W,
it: &mut I,
f: F,
page_init: F2,
) -> Result<usize, E2>
where
W: SvgWrite<Err = E>,
I: Iterator<Item = C>,
F: Fn(&mut dyn SvgWrite<Err = E>, NT, NT, C) -> Result<(), E2>,
F2: Fn(&mut dyn SvgWrite<Err = E>, NT, NT) -> Result<(), E2>,
C: Debug,
E2: From<E>,
{
let (pw, ph) = self.page_dims.unwrap_or((a4_width(), a4_height()));
let (gw, gh) = self.grid_shape.unwrap_or((4, 4));
let (cw, ch) = self.card_size.unwrap_or({
let cw = (pw - self.margin) / qcast(gw);
let ch = (ph - self.margin) / qcast(gh);
(cw, ch)
});
let mw: NT = (pw - cw * qcast(gw)) / qcast(2);
let mh: NT = (ph - ch * qcast(gh)) / qcast(2);
let mut svg = Tag::start(svg, px(pw), px(ph))?;
page_init(&mut svg, pw, ph)?;
let max = gw * gh;
let mut i = 0;
while let Some(c) = it.next() {
let x: NT = if self.flip {
qcast(gw - (i % gw))
} else {
qcast(i % gw)
};
let y: NT = qcast(i / gw);
let mut c_loc = Tag::g().translate(mw + x * cw, mh + y * ch).wrap(&mut svg);
f(&mut c_loc, cw, ch, c)?;
i += 1;
if i == max {
return Ok(i);
}
}
Ok(i)
}
pub fn write_pages<S, I, F, C, E>(
&mut self,
f_base: S,
it: &mut I,
f: &F,
) -> Result<(usize, Vec<String>), E>
where
S: AsRef<str>,
I: Iterator<Item = C>,
F: Fn(&mut dyn SvgWrite<Err = std::io::Error>, NT, NT, C) -> Result<(), E>,
E: From<std::fmt::Error>,
E: From<std::io::Error>,
C: Debug,
{
let mut res = Vec::new();
let mut tot_printed = 0;
let (gw, gh) = self.grid_shape.unwrap_or((4, 4));
let cards_pp = gw * gh;
for i in 0.. {
let fname = format!("{}{}.svg", f_base.as_ref(), i);
let w = File::create(&fname)?;
let mut svg = SvgIO::new(w);
let printed = self.write_page(&mut svg, it, f)?;
if printed == 0 {
return Ok((tot_printed, res));
}
tot_printed += printed;
if printed < cards_pp {
return Ok((tot_printed, res));
}
res.push(fname);
}
Ok((tot_printed, res))
}
}
pub fn a4_width<T: CDNum>() -> T {
qcast(2480)
}
pub fn a4_height<T: CDNum>() -> T {
qcast(3508)
}
pub fn page_flip<T: Clone>(v: &Vec<T>, w: usize) -> Vec<T> {
let mut res: Vec<T> = Vec::new();
if v.len() == 0 {
return res;
}
let blank = v[0].clone();
let mut tmp = Vec::new();
for elem in v {
tmp.push(elem.clone());
if tmp.len() == w {
for e2 in tmp.into_iter().rev() {
res.push(e2);
}
tmp = Vec::new();
}
}
if tmp.len() > 0 {
for _ in 0..w - tmp.len() {
res.push(blank.clone());
}
for elem in tmp {
res.push(elem);
}
}
res
}
pub fn interlace<T: Clone>(a: Vec<T>, b: Vec<T>) -> Vec<T> {
let mut it_a = a.iter();
let mut it_b = b.iter();
let mut res: Vec<T> = Vec::new();
loop {
let mut done = 0;
match it_a.next() {
Some(t) => res.push(t.clone()),
None => done += 1,
}
match it_b.next() {
Some(t) => res.push(t.clone()),
None => done += 1,
}
if done == 2 {
return res;
}
}
}
pub fn unite_as_pdf<P: AsRef<Path>, Q: AsRef<Path>>(v: Vec<P>, fpath: Q) -> bool {
let mut pdv: Vec<String> = Vec::new();
for i in v {
let op = PathBuf::from(i.as_ref());
let mut pp = op.clone();
pp.set_extension("pdf");
let pps = pp.to_str().unwrap_or("cc.pdf");
print!("Creating : {}\n", pps);
let _output = Command::new("inkscape")
.arg(op)
.arg(&format!("--export-pdf={}", pps))
.output()
.expect("Could not run process");
pdv.push(pps.to_string());
}
pdv.push(fpath.as_ref().to_str().unwrap_or("pooyt4.pdf").to_string());
print!("Combining\n");
Command::new("pdfunite")
.args(pdv)
.output()
.expect("could not unite the pdfs");
true
}
#[cfg(test)]
mod page_test {
use super::*;
use crate::write::SvgFmt;
#[derive(Debug)]
pub struct NumCard(i32);
fn draw_card(
wr: &mut dyn SvgWrite<Err = std::fmt::Error>,
_w: i32,
_h: i32,
c: NumCard,
) -> std::fmt::Result {
wr.write(&c.0.to_string())
}
#[test]
pub fn test_closure_works_with_page_write() {
let mut s = String::new();
let mut svg = SvgFmt::new(&mut s);
let v = vec![NumCard(4050)];
Pages::build()
.write_page_with_init(
&mut svg,
&mut v.into_iter(),
draw_card,
|ref mut w, _pw, _ph| Tag::rect(0, 0, 5, 5).write(w),
)
.unwrap();
assert_eq!(s, "<?xml version=\"1.0\" ?>\n<svg width=\"2480px\" height=\"3508px\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" >\n <rect x=\"0\" y=\"0\" width=\"5\" height=\"5\" />\n <g transform=\"translate(20,20) \" >\n 4050\n </g>\n</svg>\n");
}
}