use std::io::{Error, ErrorKind, Result};
use std::collections::HashMap;
use serde::de::DeserializeOwned;

use log::info;

pub const CFG_FILE_EXTENSION: &str  = ".toml";

pub trait AppDef {
    fn app_def<T>(&mut self, root_path:  String ); //  -> T;
}
pub trait FromFile {
    fn fix_root_path<T>(&mut self, root_path:  String ); //  -> T;
}
pub fn load_from_file<'a, T:  FromFile + DeserializeOwned>(file_cfg: &str, name: &str) -> Result<T> {
    let item_cfg: T;
    let file_path: String;
    if file_cfg.contains(CFG_FILE_EXTENSION) {
        file_path = file_cfg.to_string();
    } else { 
        file_path = format!("{}{}",file_cfg.to_string(),CFG_FILE_EXTENSION);
    }
    let config_content:  &'a str;
    match std::fs::read_to_string(&file_path) {
        Ok(cfgcontent) => config_content = Box::leak(cfgcontent.into_boxed_str()),
        Err(e) => 
            return Err(Error::new(
                ErrorKind::InvalidInput,
                format!("Error read {}: {}",&file_path,e)
            )),
    };
    match toml::from_str::<T>(&config_content) {
        Ok(cfg) => item_cfg = cfg, 
        Err(e) => return Err(Error::new(
            ErrorKind::InvalidInput,
            format!("Error loading config {}: {}",&file_path,e)
        )),
    };
    info!("Loaded {} config from: {}", &name, &file_path);
    Ok(item_cfg)
} 

pub trait DictFromFile {
    fn fix_root_path<T>(&mut self, root_path:  String ); //  -> T;
}
pub fn load_dict_from_file<'a, T: DictFromFile + DeserializeOwned>(file_cfg: &str, name: &str) -> Result<HashMap<String,T>> { 
    let item_cfg: HashMap<String,T>;
    let file_path: String;
    if file_cfg.contains(CFG_FILE_EXTENSION) {
        file_path = file_cfg.to_string();
    } else { 
        file_path = format!("{}{}",file_cfg.to_string(),CFG_FILE_EXTENSION);
    }
    let config_content:  &'a str;
    match std::fs::read_to_string(&file_path) {
        Ok(cfgcontent) => config_content = Box::leak(cfgcontent.into_boxed_str()),
        Err(e) => 
            return Err(Error::new(
                ErrorKind::InvalidInput,
                format!("Error read {}: {}",&file_path,e)
            )),
    };
    match toml::from_str::<HashMap<String,T>>(&config_content) {
        Ok(cfg) => {
            item_cfg = cfg
        }, 
        Err(e) => {
            return Err(Error::new(
               ErrorKind::InvalidInput,
               format!("Error loading {} {}: {}",name,&file_path,e)
            ))
        },
    };
    info!("Loaded {} config from: {}", name, &file_path);
    Ok(item_cfg)
} 