use seahorse::Context;
use dialoguer::theme::{ColorfulTheme};
use dialoguer::{Select, Input};
use std::fs::File;
use crate::util::{get_file, create_output_file, get_mappings_file};
use csv::{Reader, Writer, ReaderBuilder, StringRecord};
use crate::mapper::data::{HeaderEntry, Mappings};
use std::borrow::{BorrowMut, Borrow};
use std::io::BufReader;
use dialoguer::console::{Term, Style};
pub fn main(c: &Context) {
let source_file: File = get_file(c, "source");
let dest_file: File = get_file(c, "destination");
let output_file: File = create_output_file(c);
let mappings_file: Option<(Option<File>, String)> = get_mappings_file(c);
let mut reader_source: Reader<File> = ReaderBuilder::new().delimiter(b';').from_reader(source_file);
let mut reader_dest: Reader<File> = ReaderBuilder::new().delimiter(b';').from_reader(dest_file);
let writer_output: Writer<File> = csv::WriterBuilder::new().delimiter(b';').from_writer(output_file);
let dest_headers: Vec<String> = get_headers_from_file(reader_dest.headers().unwrap());
let source_headers: Vec<String> = get_headers_from_file(reader_source.headers().unwrap());
let mut header_mappings: Mappings;
let mut mappings_path: Option<String>;
match mappings_file {
Some(mappings) => {
match mappings.0 {
Some(mapping_file) => {
let reader_mappings:BufReader<File> = BufReader::new(mapping_file);
let mappings_res: Result<Mappings, serde_json::Error> = serde_json::from_reader(reader_mappings);
match mappings_res {
Ok(mappings) => {
header_mappings = mappings;
}
Err(_) => {
header_mappings = Mappings::new(dest_headers);
}
}
}
None => {
header_mappings = Mappings::new(dest_headers);
}
}
mappings_path = Some(mappings.1);
}
None => {
header_mappings = Mappings::new(dest_headers);
mappings_path = None;
}
}
let term = Term::stdout();
term.set_title("CSV mapper");
let theme = ColorfulTheme {
values_style: Style::new().yellow().dim(),
..ColorfulTheme::default()
};
loop {
term.clear_screen();
let next_menu = Select::with_theme(&theme)
.with_prompt("Choose action")
.default(0)
.item("Map")
.item("Save mapping file")
.item("Save as new mapping file")
.item("Cancel")
.item("Save and exit")
.interact().unwrap();
match next_menu {
0 => {
map_view(&term, &theme, header_mappings.borrow_mut(), &source_headers);
},
1 => {
let file_path;
match &mappings_path {
Some(path) => {
file_path = path.to_owned();
}
None => {
file_path = get_new_mappings_file_name(&theme);
mappings_path = Some(file_path.clone());
}
}
serde_json::to_writer_pretty(&File::create(&file_path).unwrap(), &header_mappings).unwrap();
},
2 => {
let new_file_path = get_new_mappings_file_name(&theme);
mappings_path = Some(new_file_path.clone());
serde_json::to_writer_pretty(&File::create(&new_file_path).unwrap(), &header_mappings).unwrap();
},
3 => {
term.clear_screen();
std::process::exit(0);
},
4 => {
term.clear_screen();
save_mapped_to_file(reader_source, reader_dest, writer_output, &header_mappings);
std::process::exit(0);
},
_ => {
term.clear_screen();
std::process::exit(0);
}
}
}
}
fn map_view(term: &Term, theme: &ColorfulTheme, header_mappings: &mut Mappings, header_source: &[String]) {
loop {
term.clear_screen();
let next_menu = Select::with_theme(theme)
.with_prompt("Mapping")
.default(0)
.item("Back")
.items(header_mappings.mappings.borrow())
.interact()
.unwrap();
match next_menu {
0 => {
break
},
_ => {
let position_dest = next_menu - 1;
match item_selector(&term, &theme, header_source, &header_mappings.mappings[position_dest].dest_entry.name) {
0 => {
},
1 => {
header_mappings.mappings[position_dest].set_source_entry(None);
},
pos_source => {
let position_source = pos_source - 2;
header_mappings.mappings[position_dest].set_source_entry(Option::from(HeaderEntry {
name: header_source[position_source].clone(),
position: position_source
}))
}
};
}
}
}
}
fn item_selector(term: &Term, theme: &ColorfulTheme, header_source: &[String], prompt_text: &str) -> usize {
term.clear_screen();
Select::with_theme(theme)
.with_prompt(format!("Map to {}", prompt_text))
.default(0)
.item("Back")
.item("Empty")
.items(header_source)
.interact()
.unwrap()
}
fn get_headers_from_file(headers: &StringRecord) -> Vec<String> {
let mut temp_header: Vec<String> = Vec::new();
for entry in headers {
temp_header.push(entry.to_string());
}
temp_header
}
fn save_mapped_to_file(mut source: Reader<File>, mut dest: Reader<File>, mut output: Writer<File>, header_mappings: &Mappings) {
output.write_record(dest.headers().unwrap());
for source_record in source.records() {
let record: StringRecord = source_record.unwrap();
let mut new_record: StringRecord = StringRecord::new();
for entry in &header_mappings.mappings {
match &entry.source_entry {
None => {
new_record.push_field("");
}
Some(dest) => {
new_record.push_field(&record[dest.position]);
}
}
}
output.write_record(&new_record);
}
output.flush();
}
fn get_new_mappings_file_name(theme: &ColorfulTheme) -> String {
Input::with_theme(theme)
.with_prompt("New mappings file name")
.default("mappings.json".to_string())
.interact()
.unwrap()
}