use std::ffi::CStr;
use std::os::raw::{c_char, c_int};
use crate::error::InputError;
use crate::ffi::enums::{FlowUnits as ENFlowUnits, HeadLossType as ENHeadLossType};
use crate::ffi::error_codes::ErrorCode;
use crate::simulation::Simulation;
use crate::model::options::HeadlossFormula;
use crate::model::units::FlowUnits;
pub struct Project {
pub(crate) simulation: Option<Simulation>,
}
macro_rules! get_simulation {
($ph:expr) => {{
if $ph.is_null() {
return ErrorCode::InvalidHandle;
}
let project = unsafe { &*$ph };
match project.simulation.as_ref() {
Some(s) => s,
None => return ErrorCode::NoNetworkData,
}
}};
}
macro_rules! get_simulation_mut {
($ph:expr) => {{
if $ph.is_null() {
return ErrorCode::InvalidHandle;
}
let project = unsafe { &mut *$ph };
match project.simulation.as_mut() {
Some(s) => s,
None => return ErrorCode::NoNetworkData,
}
}};
}
pub(crate) use get_simulation;
#[allow(unused_imports)]
pub(crate) use get_simulation_mut;
#[unsafe(no_mangle)]
pub unsafe extern "C" fn EN_createproject(ph: *mut *mut Project) -> ErrorCode {
if ph.is_null() {
return ErrorCode::InvalidHandle;
}
unsafe { *ph = Box::into_raw(Box::new(Project { simulation: None })) };
ErrorCode::Ok
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn EN_deleteproject(ph: *mut Project) -> ErrorCode {
if ph.is_null() {
return ErrorCode::InvalidHandle;
}
unsafe { drop(Box::from_raw(ph)) };
ErrorCode::Ok
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn EN_init(
ph: *mut Project,
_rpt_file: *const c_char,
_out_file: *const c_char,
flow_units: c_int,
headloss_type: c_int,
) -> ErrorCode {
if ph.is_null() {
return ErrorCode::InvalidHandle;
}
let flow_units = match ENFlowUnits::from_repr(flow_units) {
Some(flow_units) => flow_units,
None => return ErrorCode::InvalidParameterCode,
};
let headloss_type = match ENHeadLossType::from_repr(headloss_type) {
Some(headloss_formula) => headloss_formula,
None => return ErrorCode::InvalidParameterCode,
};
let flow_units = match flow_units {
ENFlowUnits::Cfs => FlowUnits::CFS,
ENFlowUnits::Gpm => FlowUnits::GPM,
ENFlowUnits::Mgd => FlowUnits::MGD,
ENFlowUnits::Imgd => FlowUnits::IMGD,
ENFlowUnits::Afd => FlowUnits::AFD,
ENFlowUnits::Lps => FlowUnits::LPS,
ENFlowUnits::Lpm => FlowUnits::LPM,
ENFlowUnits::Mld => FlowUnits::MLD,
ENFlowUnits::Cmh => FlowUnits::CMH,
ENFlowUnits::Cmd => FlowUnits::CMD,
ENFlowUnits::Cms => FlowUnits::CMS,
};
let headloss_formula = match headloss_type {
ENHeadLossType::HW => HeadlossFormula::HazenWilliams,
ENHeadLossType::DW => HeadlossFormula::DarcyWeisbach,
ENHeadLossType::CM => HeadlossFormula::ChezyManning,
};
let simulation = Simulation::init(flow_units, headloss_formula);
let project = unsafe { &mut *ph };
project.simulation = Some(simulation);
ErrorCode::Ok
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn EN_open(
ph: *mut Project,
inp_file: *const c_char,
_rpt_file: *const c_char,
_out_file: *const c_char,
) -> ErrorCode {
if ph.is_null() {
return ErrorCode::InvalidHandle;
}
if inp_file.is_null() {
return ErrorCode::CannotOpenInputFile;
}
let c_str = unsafe { CStr::from_ptr(inp_file) };
let path = match c_str.to_str() {
Ok(s) => s,
Err(_) => return ErrorCode::CannotOpenInputFile,
};
let simulation = match Simulation::from_file(path) {
Ok(s) => s,
Err(e) => {
return match e {
InputError::FileOpen { .. } | InputError::FileRead(_) => {
ErrorCode::CannotOpenInputFile
}
InputError::Parse { .. } => ErrorCode::InputError,
InputError::NodeExists { .. } => ErrorCode::DuplicateId,
InputError::LinkExists { .. } => ErrorCode::DuplicateId,
InputError::PatternNotFound { .. } => ErrorCode::UndefinedPattern,
_ => ErrorCode::InputError,
};
}
};
let project = unsafe { &mut *ph };
project.simulation = Some(simulation);
ErrorCode::Ok
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn EN_saveinpfile(ph: *mut Project, inp_file: *const c_char) -> ErrorCode {
let simulation = get_simulation_mut!(ph);
if inp_file.is_null() {
return ErrorCode::CannotOpenInputFile;
}
let c_str = unsafe { CStr::from_ptr(inp_file) };
let path = match c_str.to_str() {
Ok(s) => s,
Err(_) => return ErrorCode::CannotOpenInputFile,
};
let result = simulation.network.save_network(path);
if result.is_err() {
return ErrorCode::CannotOpenInputFile;
}
ErrorCode::Ok
}