use crate::config::{get_rule_dir, get_target_dir, get_temp_dir};
use crate::gerber_processor;
use crate::identifier::EDATool;
use crate::log;
use fancy_regex::RegexBuilder;
use rand::Rng;
use serde_yaml;
use std::collections::HashMap;
use std::error::Error;
use std::fs;
use std::path::Path;
pub fn process_files_with_rule(yaml_name: &str, eda_tool: &EDATool) -> Result<(), Box<dyn Error>> {
let rule_path = get_rule_dir().join(yaml_name);
let rule_content = fs::read_to_string(&rule_path)?;
let rules: HashMap<String, String> = serde_yaml::from_str(&rule_content)?;
let temp_dir = get_temp_dir();
let target_dir = get_target_dir();
for (logical_name, pattern) in rules {
let regex = RegexBuilder::new(&pattern).case_insensitive(true).build()?;
for entry in fs::read_dir(&temp_dir)? {
let path = entry?.path();
if path.is_file() {
if let Some(file_name) = path.file_name().and_then(|n| n.to_str()) {
if regex.is_match(file_name)? {
process_single_file(&path, &target_dir, &logical_name, eda_tool)?;
}
}
}
}
}
Ok(())
}
fn process_single_file(
src_path: &Path,
target_dir: &Path,
logical_name: &str,
eda_tool: &EDATool,
) -> Result<(), Box<dyn Error>> {
let dest_name = get_final_filename(logical_name);
let dest_path = target_dir.join(dest_name);
if logical_name.contains("Drill") {
fs::copy(src_path, &dest_path)?;
log::log(&format!(
"+ Copied '{}' -> '{}'",
src_path.file_name().unwrap().to_str().unwrap(),
dest_path.display()
));
return Ok(());
}
let mut content = fs::read_to_string(src_path)?;
let mut rng = rand::rng();
let name = if rng.random_bool(0.5) {
"EasyEDA Pro"
} else {
"EasyEDA"
};
let major = rng.random_range(2..=3);
let minor = rng.random_range(1..=5);
let patch = rng.random_range(1..=42);
let build = rng.random_range(0..=2);
let version = format!("v{}.{}.{}.{}", major, minor, patch, build);
let now = chrono::Local::now();
content = format!(
"G04 {} {}, {}*\nG04 Gerber Generator version 0.3*\n{}",
name,
version,
now.format("%Y-%m-%d %H:%M:%S"),
content.replace("\r\n", "\n")
);
if matches!(eda_tool, EDATool::KiCad) {
content = gerber_processor::normalize_kicad_d_codes(content);
}
content = gerber_processor::inject_fingerprint_into_gerber(content, false)?;
fs::write(&dest_path, content)?;
log::log(&format!(
"+ Processed '{}' -> '{}'",
src_path.file_name().unwrap().to_str().unwrap(),
dest_path.display()
));
Ok(())
}
fn get_final_filename(logical_name: &str) -> String {
match logical_name {
"Gerber_TopSolderMaskLayer" => "Gerber_TopSolderMaskLayer.GTS".to_string(),
"Gerber_TopSilkscreenLayer" => "Gerber_TopSilkscreenLayer.GTO".to_string(),
"Gerber_TopPasteMaskLayer" => "Gerber_TopPasteMaskLayer.GTP".to_string(),
"Gerber_TopLayer" => "Gerber_TopLayer.GTL".to_string(),
"Gerber_InnerLayer1" => "Gerber_InnerLayer1.G1".to_string(),
"Gerber_InnerLayer2" => "Gerber_InnerLayer2.G2".to_string(),
"Gerber_InnerLayer3" => "Gerber_InnerLayer3.G3".to_string(),
"Gerber_InnerLayer4" => "Gerber_InnerLayer4.G4".to_string(),
"Gerber_InnerLayer5" => "Gerber_InnerLayer5.G5".to_string(),
"Gerber_InnerLayer6" => "Gerber_InnerLayer6.G6".to_string(),
"Gerber_BottomSolderMaskLayer" => "Gerber_BottomSolderMaskLayer.GBS".to_string(),
"Gerber_BottomSilkscreenLayer" => "Gerber_BottomSilkscreenLayer.GBO".to_string(),
"Gerber_BottomPasteMaskLayer" => "Gerber_BottomPasteMaskLayer.GBP".to_string(),
"Gerber_BottomLayer" => "Gerber_BottomLayer.GBL".to_string(),
"Gerber_BoardOutlineLayer" => "Gerber_BoardOutlineLayer.GKO".to_string(),
"Drill_PTH_Through" => "Drill_PTH_Through.DRL".to_string(),
"Drill_PTH_Through_Via" => "Drill_PTH_Through_Via.DRL".to_string(),
"Drill_NPTH_Through" => "Drill_NPTH_Through.DRL".to_string(),
_ => format!("{}.{}", logical_name, "gbr"),
}
}