// Copyright 2016 John D. Hume
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

extern crate csv;

use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;

fn main() {
    let out_dir = env::var("OUT_DIR").unwrap();
    let dest_path = Path::new(&out_dir).join("generated_currency_data");
    let mut f = File::create(&dest_path).unwrap();
    let mut reader = csv::Reader::from_file("./MoneyData.csv").unwrap();
    let records: Vec<(String, isize, isize, String)> = reader.decode().map(|r| r.unwrap()).collect();
    for &(ref code, ref num_code, ref dec_places, _) in records.iter() {
        if dec_places < &0 || code.starts_with("#") {
            continue;
        }
        f.write_all(
            format!("pub const {}: Currency = Currency {{ code_base26: {}, numeric_code_and_decimal_places: {}{} }};\n",
                code, code_to_base26(code.as_str()), num_code, dec_places)
                .as_bytes())
            .unwrap();
    }
    f.write_all(br"lazy_static!{
        static ref CURRENCIES_BY_CODE: HashMap<String, Currency> = {
        let mut m = HashMap::new();
        ").unwrap();
    for &(ref code, _, ref dec_places, _) in records.iter() {
        if dec_places < &0 || code.starts_with("#") {
            continue;
        }
        f.write_all(format!("m.insert({0}.code(), {0});", code).as_bytes()).unwrap();
    }
    f.write_all(br"
        m
        };

        static ref CURRENCIES_BY_NUMERIC_CODE: HashMap<u16, Currency> = {
        let mut m = HashMap::new();
        ").unwrap();
    for &(ref code, _, ref dec_places, _) in records.iter() {
        if dec_places < &0 || code.starts_with("#") {
            continue;
        }
        f.write_all(format!("m.insert({0}.numeric_code(), {0});", code).as_bytes()).unwrap();
    }
    f.write_all(br"m
        };
        }").unwrap();
}

// TODO find a way to share this with the prod base26 module
const A_OFFSET: u8 = 65;
const CODE_POS_1_MULTIPLIER: u16 = 26 * 26;
const CODE_POS_2_MULTIPLIER: u16 = 26;

fn code_to_base26(code: &str) -> u16 {
    assert_eq!(3, code.len(), "Code must be three upper-case letters");
    let bytes = code.as_bytes();
    for b in bytes {
        assert!(A_OFFSET <= *b && *b <= (A_OFFSET + 26));
    }
    (((bytes[0] - A_OFFSET) as u16) * CODE_POS_1_MULTIPLIER) +
    (((bytes[1] - A_OFFSET) as u16) * CODE_POS_2_MULTIPLIER) + (bytes[2] - A_OFFSET) as u16
}
