use clap::{Parser, Subcommand};
use flour::{
bxcad::{
self,
qol::{IndexizedBCCAD, IndexizedBRCAD},
BXCADType, BXCADWrapper, BXCAD,
},
error::{Error, Result},
BCCAD, BRCAD,
};
use json_comments::{CommentSettings, StripComments};
use serde_json::Value;
use std::{
fs::File,
io::{Read, Write},
path::PathBuf,
};
#[derive(Parser, Debug)]
#[clap(
author,
version,
about = "Serializes and deserializes BCCAD/BRCAD files to and from JSON"
)]
struct Cli {
#[clap(subcommand)]
command: Command,
}
#[derive(Subcommand, Debug)]
enum Command {
#[clap(aliases = &["serialise", "s"])]
Serialize {
#[clap(parse(from_os_str))]
bxcad: PathBuf,
#[clap(parse(from_os_str))]
json: Option<PathBuf>,
#[clap(short = 'c', long)]
is_bccad: bool,
#[clap(short = 'r', long, conflicts_with = "is-bccad")]
is_brcad: bool,
#[clap(
short = 'a',
long,
conflicts_with = "is-brcad",
conflicts_with = "is-bccad"
)]
auto: bool,
#[clap(short, long, parse(from_os_str))]
labels: Option<PathBuf>,
#[clap(short, long, alias = "indexise")]
indexize: bool,
},
#[clap(aliases = &["deserialise", "d"])]
Deserialize {
#[clap(parse(from_os_str))]
json: PathBuf,
#[clap(parse(from_os_str))]
bxcad: Option<PathBuf>,
},
}
fn main() -> Result<()> {
let cli = Cli::parse();
match cli.command {
Command::Serialize {
bxcad,
json,
is_bccad,
is_brcad,
labels,
indexize,
..
} => {
let json = match json {
Some(c) => c,
None => {
let mut p = bxcad.clone();
p.set_extension("json");
p
}
};
let mut in_file = File::open(&bxcad)?;
let bxcad_type = if is_bccad {
BXCADType::BCCAD
} else if is_brcad {
BXCADType::BRCAD
} else {
bxcad::get_bxcad_type(&mut in_file)?.ok_or(Error::NotBXCAD)?
};
if labels.is_some() && bxcad_type != BXCADType::BRCAD {
Err(Error::LabelsOnNotBRCAD)?
}
let json_ = match bxcad_type {
BXCADType::BCCAD => {
let bccad = BCCAD::from_binary(&mut in_file)?;
if indexize {
let wrapper = BXCADWrapper::from_bxcad_indexize(bccad);
serde_json::to_string_pretty(&wrapper)
} else {
let wrapper = BXCADWrapper::from_bxcad(bccad);
serde_json::to_string_pretty(&wrapper)
}
}
BXCADType::BRCAD => {
let mut brcad = BRCAD::from_binary(&mut in_file)?;
if let Some(c) = labels {
let mut labels_file = File::open(c)?;
brcad.apply_labels(&mut labels_file)?;
}
if indexize {
let wrapper = BXCADWrapper::from_bxcad_indexize(brcad);
serde_json::to_string_pretty(&wrapper)
} else {
let wrapper = BXCADWrapper::from_bxcad(brcad);
serde_json::to_string_pretty(&wrapper)
}
}
c => Err(Error::NonImplementedFeature(format!("BXCAD type {:?}", c)))?,
}?;
let mut out_file = File::create(&json)?;
writeln!(out_file, "{}", json_)?;
println!(
"Serialized {:?} to {:?}",
bxcad.into_os_string(),
json.into_os_string()
);
}
Command::Deserialize { json, bxcad } => {
let in_file = File::open(&json)?;
let mut stripped = StripComments::with_settings(CommentSettings::c_style(), in_file);
let mut json_ = String::new();
stripped.read_to_string(&mut json_)?;
let value_wrapper: Value = serde_json::from_str(&json_)?;
let Some(bxcad_type) = value_wrapper.get("bxcad_type") else {
Err(Error::NotFlour)?
};
let Some(bxcad_type) = bxcad_type.as_str() else {
Err(Error::NotFlour)?
};
let bxcad_type: BXCADType = serde_json::from_str(&format!("\"{}\"", bxcad_type))?;
let bxcad = match bxcad {
Some(c) => c,
None => {
let mut p = json.clone();
p.set_extension(match &bxcad_type {
BXCADType::BCCAD => "bccad",
BXCADType::BRCAD => "brcad",
_ => unimplemented!(),
});
p
}
};
let indexized = if let Some(bxcad_type) = value_wrapper.get("indexize") {
let Some(c) = bxcad_type.as_bool() else {
Err(Error::NotFlour)?
};
c
} else {
false
};
let mut out_file;
match bxcad_type {
BXCADType::BCCAD => {
let bccad = if indexized {
let bxcad_wrapper: BXCADWrapper<IndexizedBCCAD> =
serde_json::from_str(&json_)?;
bxcad_wrapper.indexized_to_bxcad()?
} else {
let bxcad_wrapper: BXCADWrapper<BCCAD> = serde_json::from_str(&json_)?;
bxcad_wrapper.to_bxcad()?
};
out_file = File::create(&bxcad)?;
bccad.to_binary(&mut out_file)?;
}
BXCADType::BRCAD => {
let brcad = if indexized {
let bxcad_wrapper: BXCADWrapper<IndexizedBRCAD> =
serde_json::from_str(&json_)?;
bxcad_wrapper.indexized_to_bxcad()?
} else {
let bxcad_wrapper: BXCADWrapper<BRCAD> = serde_json::from_str(&json_)?;
bxcad_wrapper.to_bxcad()?
};
out_file = File::create(&bxcad)?;
brcad.to_binary(&mut out_file)?;
}
_ => unimplemented!(),
}
println!(
"Deserialized {:?} to {:?}",
json.into_os_string(),
bxcad.into_os_string()
);
}
}
Ok(())
}