use df_st_image_maps::WorldMapImages;
use df_st_image_site_maps::SiteMapImages;
use failure::Fail;
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use regex::Regex;
use std::path::{Path, PathBuf};
#[allow(dead_code)]
#[derive(Debug, Default)]
pub struct FoundFiles {
pub legends: Option<PathBuf>,
pub legends_plus: Option<PathBuf>,
pub world_history: Option<PathBuf>,
pub world_site_and_pops: Option<PathBuf>,
pub storyteller_js: Option<PathBuf>,
pub storyteller_xml: Option<PathBuf>,
}
impl FoundFiles {
pub fn some_found(&self) -> bool {
self.legends.is_some()
|| self.legends_plus.is_some()
|| self.world_history.is_some()
|| self.world_site_and_pops.is_some()
|| self.storyteller_js.is_some()
|| self.storyteller_xml.is_some()
}
}
#[derive(Debug, Fail)]
enum FileNameError {
#[fail(display = "Path is not a file")]
PathNotExist,
#[fail(display = "Path has no filename that can be found.")]
NoFileNameFound,
#[fail(display = "Path filename might contain non-UTF8 characters.")]
NonUTF8CharFound,
}
fn get_prefix(file: &PathBuf) -> Result<Option<String>, FileNameError> {
if !file.is_file() {
error!("Path is not a file");
return Err(FileNameError::PathNotExist);
}
let filename = match file.file_name() {
Some(x) => x,
None => {
error!("Path has no filename that can be found.");
return Err(FileNameError::NoFileNameFound);
}
};
let filename = match filename.to_str() {
Some(x) => x,
None => {
error!("Path filename might contain non-UTF8 characters.");
return Err(FileNameError::NonUTF8CharFound);
}
};
let file_name_prefix =
get_filename_from_region_prefix(filename).or_else(|| get_filename_from_postfix(filename));
Ok(file_name_prefix)
}
pub fn get_file_prefix(file: &PathBuf) -> Option<String> {
let (_, file_name_prefix) = match get_file_prefix_and_path(&file) {
Ok(result) => result,
Err(err) => {
error!("{}", err.to_string());
return None;
}
};
file_name_prefix
}
fn get_file_prefix_and_path(file: &PathBuf) -> Result<(PathBuf, Option<String>), FileNameError> {
let mut file = file.clone();
let file_name_prefix = if file.is_file() {
get_prefix(&file)?
} else if file.is_dir() {
let (file_new, prefix) = find_file_prefix_in_folder(&file);
file = file_new;
prefix
} else {
error!(
"The path does not point to a file or folder: {}",
file.to_string_lossy()
);
return Err(FileNameError::PathNotExist);
};
Ok((file, file_name_prefix))
}
fn find_file_prefix_in_folder(folder: &PathBuf) -> (PathBuf, Option<String>) {
if !folder.is_dir() {
return (folder.clone(), None);
}
for entry in folder.read_dir().expect("Could not look in the folder.") {
if let Ok(entry) = entry {
let file = entry.path();
if file.is_file() {
let file_name_prefix = match get_prefix(&file) {
Ok(result) => result,
Err(err) => {
warn!("{}", err.to_string());
None
}
};
if file_name_prefix.is_some() {
return (entry.path(), file_name_prefix);
}
}
}
}
warn!(
"Could not find any files in this folder that look like legend files.\n\
Folder: {}",
folder.to_string_lossy()
);
(folder.clone(), None)
}
pub fn find_missing_files(file: &PathBuf) -> FoundFiles {
let mut filenames = FoundFiles::default();
let (file, file_name_prefix) = match get_file_prefix_and_path(&file) {
Ok(result) => result,
Err(err) => {
error!("{}", err.to_string());
return filenames;
}
};
if let Some(fnp) = file_name_prefix {
info!("Finding files for prefix: {}", fnp);
filenames.legends = path_if_file_exist(format!("{}-legends.xml", fnp), &file);
filenames.legends_plus = path_if_file_exist(format!("{}-legends_plus.xml", fnp), &file);
filenames.world_history = path_if_file_exist(format!("{}-world_history.txt", fnp), &file);
filenames.world_site_and_pops =
path_if_file_exist(format!("{}-world_sites_and_pops.txt", fnp), &file);
filenames.storyteller_js = path_if_file_exist(format!("{}-storyteller.js", fnp), &file);
filenames.storyteller_xml = path_if_file_exist(format!("{}-storyteller.xml", fnp), &file);
}
debug!("Found files: {:#?}", filenames);
filenames
}
pub fn find_missing_images(file: &PathBuf) -> WorldMapImages {
let mut filenames = WorldMapImages::default();
let (file, file_name_prefix) = match get_file_prefix_and_path(&file) {
Ok(result) => result,
Err(err) => {
error!("{}", err.to_string());
return filenames;
}
};
if let Some(fnp) = file_name_prefix {
info!("Finding image files for prefix: {}", fnp);
filenames.detailed = path_if_file_exist(format!("{}-detailed.bmp", fnp), &file);
filenames.world_map = path_if_file_exist(format!("{}-world_map.bmp", fnp), &file);
filenames.biome = path_if_file_exist(format!("{}-bm.bmp", fnp), &file);
filenames.diplomacy = path_if_file_exist(format!("{}-dip.bmp", fnp), &file);
filenames.drainage = path_if_file_exist(format!("{}-drn.bmp", fnp), &file);
filenames.elevation = path_if_file_exist(format!("{}-el.bmp", fnp), &file);
filenames.elevation_water = path_if_file_exist(format!("{}-elw.bmp", fnp), &file);
filenames.evil = path_if_file_exist(format!("{}-evil.bmp", fnp), &file);
filenames.hydrologic = path_if_file_exist(format!("{}-hyd.bmp", fnp), &file);
filenames.nobility = path_if_file_exist(format!("{}-nob.bmp", fnp), &file);
filenames.rainfall = path_if_file_exist(format!("{}-rain.bmp", fnp), &file);
filenames.salinity = path_if_file_exist(format!("{}-sal.bmp", fnp), &file);
filenames.savagery = path_if_file_exist(format!("{}-sav.bmp", fnp), &file);
filenames.cadaster = path_if_file_exist(format!("{}-str.bmp", fnp), &file);
filenames.temperature = path_if_file_exist(format!("{}-tmp.bmp", fnp), &file);
filenames.trade = path_if_file_exist(format!("{}-trd.bmp", fnp), &file);
filenames.vegetation = path_if_file_exist(format!("{}-veg.bmp", fnp), &file);
filenames.volcanism = path_if_file_exist(format!("{}-vol.bmp", fnp), &file);
}
debug!("Found image files: {:#?}", filenames);
filenames
}
pub fn find_site_map_images(file: &PathBuf) -> SiteMapImages {
let mut filenames = SiteMapImages::default();
let (file, file_name_prefix) = match get_file_prefix_and_path(&file) {
Ok(result) => result,
Err(err) => {
error!("{}", err.to_string());
return filenames;
}
};
if let Some(fnp) = file_name_prefix {
info!("Finding image files for prefix: {}", fnp);
let folder = file.parent().expect("File is not in folder?");
for file in list_site_maps_in_folder(folder) {
filenames.site_maps.push(file);
}
}
debug!("Found image files: {:#?}", filenames);
filenames
}
fn list_site_maps_in_folder(folder: &Path) -> Vec<PathBuf> {
let paths = match folder.read_dir() {
Ok(result) => result,
Err(err) => {
error!("Error while searching for site maps: {}", err);
return vec![];
}
};
let mut folder_list = Vec::new();
for file in paths {
if let Ok(file) = file {
let file_name = file
.file_name()
.into_string()
.expect("File found with non UTF-8 characters");
let re = Regex::new(r"([\w-]*\w)(-(?:site_map-[0-9]+)\.\w+)").unwrap();
if re.is_match(&file_name) {
folder_list.push(file.path());
}
}
}
folder_list
}
fn path_if_file_exist(filename: String, filepath_org: &PathBuf) -> Option<PathBuf> {
let filepath = filepath_org.with_file_name(filename);
if filepath.exists() && filepath.is_file() {
return Some(filepath);
}
None
}
fn get_filename_from_region_prefix(filename: &str) -> Option<String> {
let re = Regex::new(r"(region[0-9-]+[0-9])(-[\w-]+\.\w+)").unwrap();
let caps = match re.captures(filename) {
Some(x) => x,
None => return None,
};
match caps.get(1) {
Some(x) => Some(x.as_str().to_string()),
None => None,
}
}
pub fn get_world_info_from_filename(filename: &str, world_id: i32) -> df_st_core::DFWorldInfo {
let re = Regex::new(r"region([0-9]+)-([0-9]+)-([0-9]+)-([0-9]+)").unwrap();
let caps = match re.captures(filename) {
Some(x) => x,
None => {
return df_st_core::DFWorldInfo {
id: world_id,
save_name: Some(filename.to_string()),
..Default::default()
}
}
};
let region_number = match caps.get(1) {
Some(x) => Some(x.as_str().parse::<i32>().unwrap()),
None => None,
};
let year = match caps.get(2) {
Some(x) => Some(x.as_str().parse::<i32>().unwrap()),
None => None,
};
let month = match caps.get(3) {
Some(x) => Some(x.as_str().parse::<i32>().unwrap()),
None => None,
};
let day = match caps.get(4) {
Some(x) => Some(x.as_str().parse::<i32>().unwrap()),
None => None,
};
df_st_core::DFWorldInfo {
id: world_id,
save_name: Some(filename.to_string()),
region_number,
year,
month,
day,
..Default::default()
}
}
fn get_filename_from_postfix(filename: &str) -> Option<String> {
let re = Regex::new(
r"([\w-]*\w)(-(?:
bm|detailed|dip|drn|el|elw|evil|hyd|
legends_plus|legends|nob|rain|sal|sav|
site_map-[0-9]+|
str|tmp|trd|veg|vol|world_history
|world_map|world_sites_and_pops
)\.\w+)",
)
.unwrap();
let caps = match re.captures(filename) {
Some(x) => x,
None => return None,
};
match caps.get(1) {
Some(x) => Some(x.as_str().to_string()),
None => None,
}
}