import Foundation // TODO: Needs updated for when forms are using `minmal` values. public struct FlaggedEquipmentMeasurement: Equatable { public var airflow: Flagged public var coilPressureDrop: Flagged public var externalStaticPressure: Flagged public var filterPressureDrop: Flagged public var returnPlenumPressure: Flagged public var supplyPlenumPressure: Flagged public init( airflow: Flagged, coilPressureDrop: Flagged, externalStaticPressure: Flagged, filterPressureDrop: Flagged, returnPlenumPressure: Flagged, supplyPlenumPressure: Flagged ) { self.airflow = airflow self.coilPressureDrop = coilPressureDrop self.externalStaticPressure = externalStaticPressure self.filterPressureDrop = filterPressureDrop self.returnPlenumPressure = returnPlenumPressure self.supplyPlenumPressure = supplyPlenumPressure } public init( budgets: BudgetedPercentEnvelope, measurement: EquipmentMeasurement, ratedPressures: RatedStaticPressures, tons: CoolingCapacity? ) { switch measurement { case let .airHandler(airHandler): self = .airHandler( budgets: budgets, measurement: airHandler, ratedPressures: ratedPressures, tons: tons ) case let .furnaceAndCoil(furnaceAndCoil): self = .furnaceAndCoil( budgets: budgets, measurement: furnaceAndCoil, ratedPressures: ratedPressures, tons: tons ) } } public static func airHandler( budgets: BudgetedPercentEnvelope, measurement: EquipmentMeasurement.AirHandler, ratedPressures: RatedStaticPressures, tons: CoolingCapacity? ) -> Self { .init( airflow: checkAirflow(value: measurement.airflow, tons: tons), coilPressureDrop: .init( wrappedValue: (measurement.$postCoilPressure.positiveValue - measurement.$postFilterPressure.positiveValue) ?? 0, .result(.good()) ), externalStaticPressure: checkExternalStaticPressure( value: measurement.externalStaticPressure, ratedPressures: ratedPressures ), filterPressureDrop: .init( value: measurement.$postFilterPressure.positiveValue - measurement.$returnPlenumPressure.positiveValue, budget: budgets.filterBudget, ratedPressures: ratedPressures ), returnPlenumPressure: .init( value: measurement.$returnPlenumPressure.positiveValue, budget: budgets.returnPlenumBudget, ratedPressures: ratedPressures ), supplyPlenumPressure: .init( value: measurement.$supplyPlenumPressure.positiveValue ?? 0, budget: budgets.supplyPlenumBudget, ratedPressures: ratedPressures ) ) } public static func furnaceAndCoil( budgets: BudgetedPercentEnvelope, measurement: EquipmentMeasurement.FurnaceAndCoil, ratedPressures: RatedStaticPressures, tons: CoolingCapacity? ) -> Self { .init( airflow: checkAirflow(value: measurement.airflow, tons: tons), coilPressureDrop: .init( value: measurement.$preCoilPressure.positiveValue - measurement.$supplyPlenumPressure.positiveValue, budget: budgets.coilBudget, ratedPressures: ratedPressures ), externalStaticPressure: checkExternalStaticPressure( value: measurement.externalStaticPressure, ratedPressures: ratedPressures ), filterPressureDrop: .init( value: measurement.$postFilterPressure.positiveValue - measurement.$returnPlenumPressure.positiveValue, budget: budgets.filterBudget, ratedPressures: ratedPressures, ignoreMinimum: true ), returnPlenumPressure: .init( value: measurement.$returnPlenumPressure.positiveValue, budget: budgets.returnPlenumBudget, ratedPressures: ratedPressures ), supplyPlenumPressure: .init( value: measurement.$supplyPlenumPressure.positiveValue, budget: budgets.supplyPlenumBudget, ratedPressures: ratedPressures ) ) } } // MARK: - Helpers #if DEBUG extension FlaggedEquipmentMeasurement { public static func mock(type equipmentType: EquipmentType) -> Self { .init( budgets: .init(equipmentType: equipmentType, fanType: .variableSpeed), measurement: .mock(type: equipmentType), ratedPressures: .init(), tons: .default ) } } #endif fileprivate extension Flagged { init( value: Double, budget: Percentage, ratedPressures: RatedStaticPressures, ignoreMinimum: Bool = false ) { let minimum = ignoreMinimum ? 0 : ratedPressures.minimum * budget.fraction let maximum = ratedPressures.maximum * budget.fraction let rated = ratedPressures.rated * budget.fraction self.init( wrappedValue: value, .using(maximum: maximum, minimum: minimum, rated: rated) ) } init( value: Double?, budget: Percentage, ratedPressures: RatedStaticPressures, ignoreMinimum: Bool = false ) { guard let value else { self = .error(message: "Value is not set.") return } self.init( value: value, budget: budget, ratedPressures: ratedPressures, ignoreMinimum: ignoreMinimum ) } } fileprivate func checkExternalStaticPressure( value: Double, ratedPressures: RatedStaticPressures ) -> Flagged { .init( wrappedValue: value, .rated(ratedPressures) ) } fileprivate func checkAirflow( value: Double?, tons: CoolingCapacity? ) -> Flagged { guard let value, let tons else { return .init(wrappedValue: value ?? 0, .result(.good())) } return .init(wrappedValue: value, .airflow(tons: tons)) }