pub mod category;
pub mod message;
pub mod uap;
pub mod uap_json;
use std::collections::BTreeMap;
use std::fs;
use thiserror::Error;
use self::category::{Category, CategoryIndex, CategoryKey};
use self::uap::providers::Provider;
use self::uap_json::errors::ParseError;
use self::uap_json::loader::Loader;
use self::uap_json::structures::{DataRecord, Edition};
#[derive(Error, Debug)]
pub enum ContextErrors {
#[error("Definition folder for UAPs could not be loaded")]
UAPDefinitionFolderCouldNotBeLoaded,
#[error("unknown error")]
Unknown,
}
pub struct DataBlock {
pub records: Vec<DataRecord>
}
type CategoryMap = BTreeMap<CategoryKey, Category>;
type UapMap = BTreeMap<CategoryKey, DataRecord>;
pub struct Context {
pub categories: CategoryMap,
pub uap_definitions: UapMap
}
impl Context {
const UAPS_FOLDER: &'static str = "./resources/uaps";
pub fn new() -> anyhow::Result<Context> {
let (categories, uap_defs) = Context::load()?;
Ok(Context {
categories: categories,
uap_definitions: uap_defs
})
}
fn find_uap_definition_files() -> anyhow::Result<Vec<String>> {
let uap_files = match fs::read_dir(Context::UAPS_FOLDER) {
Ok(read_dir) => {
let mut files = Vec::<String>::new();
for result in read_dir {
let path = match result {
Ok(dir_entry) => {
let filename =
match dir_entry.file_name().into_string() {
Ok(s) => s,
Err(_) => { return Err(ContextErrors::UAPDefinitionFolderCouldNotBeLoaded.into()); },
};
filename
},
Err(e) => { return Err(e.into()); },
};
files.push(path);
};
files
},
Err(e) => { return Err(e.into()); },
};
Ok(uap_files)
}
fn load() -> anyhow::Result<(CategoryMap, UapMap)> {
let mut categories = CategoryMap::new();
let mut uap_defs = UapMap::new();
let uap_files = Context::find_uap_definition_files()?;
for file in uap_files {
let filepath_and_name = format!("{}/{}", Context::UAPS_FOLDER, file);
let uap_definition = Loader::load(&filepath_and_name)?;
let category_index =
match CategoryIndex::from_u8(uap_definition.number) {
Some(i) => i,
None => { return Err(ParseError::OpenUapJsonDefinitionError.into()) }
};
let category =
Category::new(
CategoryKey {
index: category_index,
edition: uap_definition.edition.clone(),
provider: Provider::Standard
},
uap_definition.title.as_str());
categories.insert(category.key.clone(), category.clone());
uap_defs.insert(category.key, uap_definition);
}
Ok((categories, uap_defs))
}
pub fn find_definition(&self, category_key: CategoryKey) -> anyhow::Result<DataRecord> {
let mut uap_def_opt: Option<DataRecord> = None;
for uap in &self.uap_definitions {
if uap.0 == &category_key {
uap_def_opt = Some(uap.1.clone())
}
}
if uap_def_opt.is_none() {
return Err(ParseError::CategoryNotYetSupported {
category_code: format!("{}", category_key.index.as_string()),
edition: format!("{}.{}", category_key.edition.major, category_key.edition.minor),
provider: category_key.provider.as_ref().to_owned(),
}.into());
}
Ok(uap_def_opt.unwrap())
}
fn find_newest_edition_for_category(&self, cat_idx: &CategoryIndex) -> anyhow::Result<Edition> {
let uap_defs:&Vec<&CategoryKey> = &self.uap_definitions
.keys()
.into_iter()
.filter(|x| x.index == *cat_idx).collect::<Vec<&CategoryKey>>();
if uap_defs.is_empty() {
return Err(ParseError::CategoryUapDefinitionNotFound { category_code: cat_idx.as_string()}.into());
}
let uap_def = *uap_defs.into_iter().max().unwrap();
Ok(uap_def.edition.clone())
}
}