extern crate std;
use std::collections::HashMap;
use compiler::parser;
use compiler::parser::Property;
use fetcher;
use hook;
use cmd;
use std::ops::Deref;
pub struct Config {
map: HashMap<String, Box<Property>>,
visits: std::cell::RefCell<HashMap<String, ()>>,
}
impl Config {
pub fn new() -> Config {
Config {
map: HashMap::new(),
visits: std::cell::RefCell::new(HashMap::new()),
}
}
#[cfg_attr(feature = "cargo-clippy", allow(borrowed_box))]
pub fn get(&self, key: &str) -> Option<&Box<Property>>
{
if let Some(data) = self.map.get(key) {
let mut visits = self.visits.borrow_mut();
let visit_key = String::from(key);
{
let mut iter = visit_key.as_str();
let mut index_increment = 0;
while let Some(index) = iter.find('/') {
let subkey = &visit_key[0..index_increment+index+1];
visits.insert(String::from(subkey), ());
iter = &iter[index+1..];
index_increment += index + 1;
}
}
visits.insert(visit_key, ());
Some(data)
} else {
None
}
}
pub fn set(&mut self, key: String, prop: Box<Property>) {
trace!("Inserting key {} in config", key);
self.map.insert(key, prop);
}
pub fn collect_components(&self) -> Result<Vec<String>, parser::Error> {
let sub_key = "/subcomponents/";
if ! self.map.contains_key(&sub_key.to_string()) {
error!("The \"subcomponents\" block is mandatory, but it is not defined.");
return Err(parser::Error::NoSubcomponents);
}
let sub_key_len = sub_key.len();
let mut components = Vec::new();
for key in self.map.keys() {
if key.contains(sub_key) && (key.len() > sub_key_len) {
let slice = &key[sub_key_len..];
if let Some(index) = slice.find('/') {
if index + 1 == slice.len() {
let id = &slice[0..index];
components.push(String::from(id));
}
}
}
}
Ok(components)
}
pub fn get_hooks_for_component(&self, component: &str) -> Result<Vec<String>, parser::Error> {
let mut hooks: Vec<String> = Vec::new();
let cmd_list = cmd::get_commands_list();
for key in self.map.keys() {
if ! key.ends_with('/') {
continue;
}
let start_key = format!("/subcomponents/{}/", component);
if ! key.starts_with(start_key.as_str()) {
continue;
}
let mut iter = key.split('/');
if let Some(hook_name) = iter.nth(3) {
if iter.nth(4).is_some() {
continue;
}
let mut process_hook = true;
for cmd in &cmd_list {
if hook_name == "fetch" {
process_hook = false;
} else if hook_name == *cmd {
error!("Hook name '{}' is reserved", hook_name);
return Err(parser::Error::ReservedHook);
}
}
if process_hook && ! hook_name.is_empty() {
debug!("Registering hook '{}' for component '{}'",
hook_name, component);
hooks.push(String::from(hook_name));
}
}
}
Ok(hooks)
}
pub fn check_unused(&self) -> Result<(), parser::Error> {
let visits = self.visits.borrow();
let mut ret = Ok(());
for key in self.map.keys() {
if visits.get(key).is_none() {
error!("Unknown propery {}", key);
ret = Err(parser::Error::InvalidPropertyName);
}
}
ret
}
pub fn get_fetch_property(&self, component: &str, method: &str, prop: &str) -> Option<parser::PropertyValue> {
let key = format!("/subcomponents/{}/fetch/{}/{}",
component, method, prop);
if let Some(data) = self.get(&key) {
Some(data.deref().value_get())
} else {
None
}
}
}
pub struct Component {
id: String,
name: String,
path: String,
fetch: Vec<Box<fetcher::Method>>,
dependencies: Vec<String>,
hooks: Vec<hook::Hook>,
}
impl Component {
pub fn new(id: String, name: String, path: String, dependencies: Vec<String>, hooks: Vec<hook::Hook>) -> Component {
Component {
id: id,
name: name,
path: path,
fetch: Vec::new(),
dependencies: dependencies,
hooks: hooks,
}
}
pub fn id_get(&self) -> &String {
&self.id
}
pub fn fetch_method_add(&mut self, method: Box<fetcher::Method>) {
self.fetch.push(method);
}
pub fn hooks_get(&self) -> &Vec<hook::Hook> {
&self.hooks
}
pub fn fetch_methods_get(&self) -> &Vec<Box<fetcher::Method>> {
&self.fetch
}
#[cfg_attr(feature = "cargo-clippy", allow(borrowed_box))]
pub fn fetch_method_get(&self, name: &str) -> &Box<fetcher::Method> {
for method in &self.fetch {
if method.name_get() == name {
return method;
}
}
panic!("Uhhh... corrupted database?");
}
pub fn path_get(&self) -> &String {
&self.path
}
pub fn name_get(&self) -> &String {
&self.name
}
}