use std::convert::TryInto;
use std::fs;
use countries::Country;
use fred_api::Fred;
use keytree::{
KeyTree,
KeyTreeRef,
};
use crate::{
DataSpec,
DataType,
SeriesId,
SeriesSpec,
};
use crate::parser::{ FredSpec, ParserSpec };
use crate::error::*;
pub fn countries_with_data() -> Vec<Country> {
vec!(
Country::Australia,
Country::Austria,
Country::Belgium,
Country::Canada,
Country::Chile,
Country::CzechRepublic,
Country::Denmark,
Country::Estonia,
Country::Finland,
Country::France,
Country::Germany,
Country::Greece,
Country::Ireland,
Country::Israel,
Country::Italy,
Country::Japan,
Country::Latvia,
Country::Netherlands,
Country::NewZealand,
Country::Norway,
Country::Poland,
Country::Serbia,
Country::SouthKorea,
Country::Spain,
Country::Sweden,
Country::Switzerland,
Country::UnitedKingdom,
Country::UnitedStates,
)
}
pub fn fred_country(country: Country) -> String {
match country {
Country::SouthKorea => "korea".into(),
Country::UnitedStates => "usa".into(),
_ => country.to_string().to_lowercase(),
}
}
pub struct DataSelector(Vec<TagSelector>);
impl DataSelector {
pub fn from_file(path: &str) -> Self {
let data_selector = fs::read_to_string(path).unwrap();
let kt = KeyTree::parse(&data_selector).unwrap();
kt.to_ref().try_into().unwrap()
}
pub fn into_data_spec(&self) -> Result<DataSpec, Error> {
let mut data_spec = DataSpec::new();
for tag_selector in &self.0 {
println!("");
println!("{} {}", tag_selector.country, tag_selector.data_type);
let series_items = match Fred::tags_series(&tag_selector.tag()) {
Ok(tags_series) => {
tags_series.seriess
},
Err(e) => { return Err(err( file!(), line!(), &e.to_string())) },
};
for series_item in series_items.iter() {
let series_id = SeriesId::new(&series_item.id.clone());
if tag_selector.is_selected(series_item) {
println!(" {} {}", series_item.id, series_item.title);
let series_spec = SeriesSpec {
data_type: tag_selector.data_type,
country: Some(tag_selector.country),
series_id: series_id,
transforms: Vec::new(),
parser: ParserSpec::FredSpec(FredSpec::empty()),
};
println!(" {} {}", series_item.id, series_item.title);
data_spec.insert(&series_spec);
} else {
println!("drop: {} {}", series_item.id, series_item.title);
}
}
}
Ok(data_spec)
}
pub fn resume_into_data_spec(&self, country: Country, data_type: DataType) -> Result<DataSpec, Error> {
let mut data_spec = DataSpec::new();
for tag_selector in self.0.iter().skip_while(|tag_selector| {
tag_selector.country != country||
tag_selector.data_type != data_type
}) {
println!("{} {}", tag_selector.country, tag_selector.data_type);
let series_items = match Fred::tags_series(&tag_selector.tag()) {
Ok(tags_series) => {
tags_series.seriess
},
Err(e) => { return Err(err(file!(), line!(), &e.to_string())) },
};
for series_item in series_items.iter() {
let series_id = SeriesId::new(&series_item.id.clone());
if tag_selector.is_selected(series_item) {
println!(" {} {}", series_item.id, series_item.title);
let series_spec = SeriesSpec {
country: Some(tag_selector.country),
data_type: tag_selector.data_type,
series_id: series_id,
transforms: Vec::new(),
parser: ParserSpec::FredSpec(FredSpec::empty()),
};
println!(" {} {}", series_item.id, series_item.title);
data_spec.insert(&series_spec);
}
}
}
Ok(data_spec)
}
}
impl<'a> TryInto<DataSelector> for KeyTreeRef<'a> {
type Error = keytree::Error;
fn try_into(self) -> Result<DataSelector, Self::Error> {
let v: Vec<TagSelector> = self.vec_at("selectors::series")?;
Ok(DataSelector(v))
}
}
#[derive(Debug)]
pub struct TagSelector {
country: Country,
data_type: DataType,
tags: Vec<String>,
enumerate: Vec<String>,
exclude: Vec<String>,
require: Vec<String>,
}
impl TagSelector {
pub fn tag(&self) -> String {
let mut s = String::new();
for tag in &self.tags {
s.push_str(&tag.trim());
s.push(';');
}
s.push_str(&fred_country(self.country));
s
}
pub fn is_selected(&self, series_item: &fred_api::SeriesItem) -> bool {
let title = &series_item.title.clone();
if !self.enumerate.is_empty() &&
!self.enumerate.iter().any(|enum_title| enum_title == title)
{
return false
}
if !self.exclude.is_empty() &&
self.exclude.iter().any(|exclusion| title.contains(exclusion))
{
return false
}
if !self.require.is_empty() &&
self.require.iter().any(|requirement| !title.contains(requirement))
{
return false
}
true
}
}
impl<'a> TryInto<TagSelector> for KeyTreeRef<'a> {
type Error = keytree::Error;
fn try_into(self) -> Result<TagSelector, Self::Error> {
Ok(
TagSelector {
country: self.value("series::country")?,
data_type: self.value("series::data_type")?,
tags: self.opt_vec_value("series::tag")?,
enumerate: self.opt_vec_value("series::enumerate")?,
exclude: self.opt_vec_value("series::exclude")?,
require: self.opt_vec_value("series::require")?,
}
)
}
}