use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use once_cell::sync::Lazy;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CameoCode {
pub code: String,
pub description: String,
pub quad_class: Option<u8>,
pub goldstein_scale: Option<f64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CountryCode {
pub code: String,
pub name: String,
pub fips: Option<String>,
pub iso: Option<String>,
}
pub static QUAD_CLASSES: Lazy<HashMap<u8, &'static str>> = Lazy::new(|| {
let mut m = HashMap::new();
m.insert(1, "Verbal Cooperation");
m.insert(2, "Material Cooperation");
m.insert(3, "Verbal Conflict");
m.insert(4, "Material Conflict");
m
});
pub static ROOT_CODES: Lazy<Vec<CameoCode>> = Lazy::new(|| {
vec![
CameoCode { code: "01".to_string(), description: "Make public statement".to_string(), quad_class: Some(1), goldstein_scale: Some(0.0) },
CameoCode { code: "02".to_string(), description: "Appeal".to_string(), quad_class: Some(1), goldstein_scale: Some(3.0) },
CameoCode { code: "03".to_string(), description: "Express intent to cooperate".to_string(), quad_class: Some(1), goldstein_scale: Some(4.0) },
CameoCode { code: "04".to_string(), description: "Consult".to_string(), quad_class: Some(1), goldstein_scale: Some(1.0) },
CameoCode { code: "05".to_string(), description: "Engage in diplomatic cooperation".to_string(), quad_class: Some(2), goldstein_scale: Some(3.5) },
CameoCode { code: "06".to_string(), description: "Engage in material cooperation".to_string(), quad_class: Some(2), goldstein_scale: Some(6.0) },
CameoCode { code: "07".to_string(), description: "Provide aid".to_string(), quad_class: Some(2), goldstein_scale: Some(7.0) },
CameoCode { code: "08".to_string(), description: "Yield".to_string(), quad_class: Some(2), goldstein_scale: Some(5.0) },
CameoCode { code: "09".to_string(), description: "Investigate".to_string(), quad_class: Some(1), goldstein_scale: Some(-0.5) },
CameoCode { code: "10".to_string(), description: "Demand".to_string(), quad_class: Some(3), goldstein_scale: Some(-5.0) },
CameoCode { code: "11".to_string(), description: "Disapprove".to_string(), quad_class: Some(3), goldstein_scale: Some(-2.0) },
CameoCode { code: "12".to_string(), description: "Reject".to_string(), quad_class: Some(3), goldstein_scale: Some(-4.0) },
CameoCode { code: "13".to_string(), description: "Threaten".to_string(), quad_class: Some(3), goldstein_scale: Some(-6.0) },
CameoCode { code: "14".to_string(), description: "Protest".to_string(), quad_class: Some(3), goldstein_scale: Some(-6.5) },
CameoCode { code: "15".to_string(), description: "Exhibit force posture".to_string(), quad_class: Some(4), goldstein_scale: Some(-7.0) },
CameoCode { code: "16".to_string(), description: "Reduce relations".to_string(), quad_class: Some(4), goldstein_scale: Some(-4.0) },
CameoCode { code: "17".to_string(), description: "Coerce".to_string(), quad_class: Some(4), goldstein_scale: Some(-7.0) },
CameoCode { code: "18".to_string(), description: "Assault".to_string(), quad_class: Some(4), goldstein_scale: Some(-9.0) },
CameoCode { code: "19".to_string(), description: "Fight".to_string(), quad_class: Some(4), goldstein_scale: Some(-10.0) },
CameoCode { code: "20".to_string(), description: "Use unconventional mass violence".to_string(), quad_class: Some(4), goldstein_scale: Some(-10.0) },
]
});
pub static ACTOR_TYPE_CODES: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| {
let mut m = HashMap::new();
m.insert("GOV", "Government");
m.insert("MIL", "Military");
m.insert("REB", "Rebels");
m.insert("OPP", "Opposition");
m.insert("PTY", "Political Party");
m.insert("AGR", "Agriculture");
m.insert("BUS", "Business");
m.insert("CRM", "Criminal");
m.insert("CVL", "Civilian");
m.insert("DEV", "Development");
m.insert("EDU", "Education");
m.insert("ELI", "Elite");
m.insert("ENV", "Environment");
m.insert("HLH", "Health");
m.insert("HRI", "Human Rights");
m.insert("IGO", "Intergovernmental Organization");
m.insert("JUD", "Judiciary");
m.insert("LAB", "Labor");
m.insert("LEG", "Legislature");
m.insert("MED", "Media");
m.insert("MNC", "Multinational Corporation");
m.insert("NGO", "Non-Governmental Organization");
m.insert("REF", "Refugees");
m.insert("REL", "Religion");
m.insert("SPY", "Intelligence");
m.insert("UAF", "Unaligned Armed Forces");
m
});
pub static MAJOR_COUNTRIES: Lazy<Vec<CountryCode>> = Lazy::new(|| {
vec![
CountryCode { code: "US".to_string(), name: "United States".to_string(), fips: Some("US".to_string()), iso: Some("USA".to_string()) },
CountryCode { code: "CH".to_string(), name: "China".to_string(), fips: Some("CH".to_string()), iso: Some("CHN".to_string()) },
CountryCode { code: "RS".to_string(), name: "Russia".to_string(), fips: Some("RS".to_string()), iso: Some("RUS".to_string()) },
CountryCode { code: "UK".to_string(), name: "United Kingdom".to_string(), fips: Some("UK".to_string()), iso: Some("GBR".to_string()) },
CountryCode { code: "FR".to_string(), name: "France".to_string(), fips: Some("FR".to_string()), iso: Some("FRA".to_string()) },
CountryCode { code: "GM".to_string(), name: "Germany".to_string(), fips: Some("GM".to_string()), iso: Some("DEU".to_string()) },
CountryCode { code: "JA".to_string(), name: "Japan".to_string(), fips: Some("JA".to_string()), iso: Some("JPN".to_string()) },
CountryCode { code: "IN".to_string(), name: "India".to_string(), fips: Some("IN".to_string()), iso: Some("IND".to_string()) },
CountryCode { code: "BR".to_string(), name: "Brazil".to_string(), fips: Some("BR".to_string()), iso: Some("BRA".to_string()) },
CountryCode { code: "CA".to_string(), name: "Canada".to_string(), fips: Some("CA".to_string()), iso: Some("CAN".to_string()) },
CountryCode { code: "AU".to_string(), name: "Australia".to_string(), fips: Some("AS".to_string()), iso: Some("AUS".to_string()) },
CountryCode { code: "IT".to_string(), name: "Italy".to_string(), fips: Some("IT".to_string()), iso: Some("ITA".to_string()) },
CountryCode { code: "SP".to_string(), name: "Spain".to_string(), fips: Some("SP".to_string()), iso: Some("ESP".to_string()) },
CountryCode { code: "MX".to_string(), name: "Mexico".to_string(), fips: Some("MX".to_string()), iso: Some("MEX".to_string()) },
CountryCode { code: "KS".to_string(), name: "South Korea".to_string(), fips: Some("KS".to_string()), iso: Some("KOR".to_string()) },
CountryCode { code: "SA".to_string(), name: "Saudi Arabia".to_string(), fips: Some("SA".to_string()), iso: Some("SAU".to_string()) },
CountryCode { code: "TU".to_string(), name: "Turkey".to_string(), fips: Some("TU".to_string()), iso: Some("TUR".to_string()) },
CountryCode { code: "IR".to_string(), name: "Iran".to_string(), fips: Some("IR".to_string()), iso: Some("IRN".to_string()) },
CountryCode { code: "IS".to_string(), name: "Israel".to_string(), fips: Some("IS".to_string()), iso: Some("ISR".to_string()) },
CountryCode { code: "EG".to_string(), name: "Egypt".to_string(), fips: Some("EG".to_string()), iso: Some("EGY".to_string()) },
]
});
pub fn lookup_code(code: &str) -> Option<&'static CameoCode> {
let root = if code.len() >= 2 { &code[0..2] } else { code };
ROOT_CODES.iter().find(|c| c.code == root)
}
pub fn quad_class_description(class: u8) -> Option<&'static str> {
QUAD_CLASSES.get(&class).copied()
}
pub fn actor_type_description(code: &str) -> Option<&'static str> {
ACTOR_TYPE_CODES.get(code).copied()
}
pub fn lookup_country(code: &str) -> Option<&'static CountryCode> {
let code_upper = code.to_uppercase();
MAJOR_COUNTRIES.iter().find(|c| c.code == code_upper || c.fips.as_deref() == Some(&code_upper) || c.iso.as_deref() == Some(&code_upper))
}
pub fn search_codes(pattern: &str) -> Vec<&'static CameoCode> {
let pattern_lower = pattern.to_lowercase();
ROOT_CODES
.iter()
.filter(|c| c.description.to_lowercase().contains(&pattern_lower))
.collect()
}