//! Thermophysical properties of _**real**_ humid air.
//!
//! This module provides a comprehensive interface for calculating thermophysical properties of
//! _**real**_ humid air through the [`HumidAir`] struct.
//!
//! Properties are calculated in accordance with **ASHRAE RP-1485**.

mod common;
mod defined;
mod invariant;
mod request;
mod undefined;

use std::{collections::HashMap, marker::PhantomData};

use request::HumidAirUpdateRequest;

use crate::{
    io::HumidAirParam,
    native::CoolPropError,
    state_variant::{Defined, StateVariant},
};

/// Result type for operations that could fail while updating humid air state.
pub type StateResult<T> = Result<T, HumidAirStateError>;

/// Result type for operations that could fail while retrieving humid air properties.
pub type OutputResult<T> = Result<T, HumidAirOutputError>;

/// Provider of thermophysical properties of _**real**_ humid air.
///
/// It implements the [Typestate Pattern](https://en.wikipedia.org/wiki/Typestate_analysis)
/// and has one generic type parameter: `S` -- state variant
/// _([`Defined`] or [`Undefined`](crate::state_variant::Undefined))_.
///
/// Depending on `S`, the `HumidAir` instance has different functionality.
///
/// Properties are calculated in accordance with **ASHRAE RP-1485**.
///
/// # See Also
///
/// - [Humid Air Properties](https://coolprop.org/fluid_properties/HumidAir.html)
#[derive(Debug)]
pub struct HumidAir<S: StateVariant = Defined> {
    update_request: Option<HumidAirUpdateRequest>,
    outputs: HashMap<HumidAirParam, OutputResult<f64>>,
    state: PhantomData<S>,
}

/// Error during [`HumidAir::update`] or [`HumidAir::in_state`].
#[derive(Clone, Debug, Eq, PartialEq, thiserror::Error)]
pub enum HumidAirStateError {
    /// Specified inputs are invalid.
    #[error("specified inputs (`{0:?}`, `{1:?}`, `{2:?}`) are invalid")]
    InvalidInputs(HumidAirParam, HumidAirParam, HumidAirParam),

    /// Some of the specified input value is infinite or NaN.
    #[error("input values must be finite")]
    InvalidInputValue,
}

/// Error during calculation of the [`HumidAir`] output parameter value.
#[derive(Clone, Debug, Eq, PartialEq, thiserror::Error)]
pub enum HumidAirOutputError {
    /// Specified output parameter is not available.
    #[error("specified output parameter `{0:?}` is not available")]
    UnavailableOutput(HumidAirParam),

    /// Failed to calculate the output parameter value.
    #[error("failed to calculate the output value of `{0:?}`: {1}")]
    CalculationFailed(HumidAirParam, CoolPropError),
}
