// // Reaktoro is a unified framework for modeling chemically reactive systems.
// //
// // Copyright © 2014-2022 Allan Leal
// //
// // This library is free software; you can redistribute it and/or
// // modify it under the terms of the GNU Lesser General Public
// // License as published by the Free Software Foundation; either
// // version 2.1 of the License, or (at your option) any later version.
// //
// // This library is distributed in the hope that it will be useful,
// // but WITHOUT ANY WARRANTY; without even the implied warranty of
// // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// // Lesser General Public License for more details.
// //
// // You should have received a copy of the GNU Lesser General Public License
// // along with this library. If not, see <http://www.gnu.org/licenses/>.

// #pragma once

// // C++ includes
// #include <memory>
// #include <string>

// // Reaktoro includes
// #include <Reaktoro/Common/Index.hpp>
// #include <Reaktoro/Common/Matrix.hpp>
// #include <Reaktoro/Common/Real.hpp>

// namespace Reaktoro {

// // Forward declarations
// class ChemicalProps;
// class ChemicalState;
// class ChemicalSystem;
// class ReactionSystem;

// /// A class that provides a convenient way to retrieve chemical quantities.
// /// Here the term chemical quantity is used in a broad sense. It means any
// /// quantity for an element, species, or phase in a chemical system that
// /// can be calculated at a chemical state whose temperature, pressure, and
// /// mole amounts of all species are known.
// ///
// /// In the example below, the volume of a phase named Gaseous and the pH
// /// of the aqueous phase (assuming both phases were defined in the chemical
// /// system) are retrieved:
// ///
// /// ~~~
// /// ChemicalQuantity q(state);
// ///
// /// const double vol = q["phaseVolume(Gaseous)"];
// /// const double pH = q["pH"];
// /// ~~~
// ///
// /// The table below shows all possible quantities that can be retrieved from
// /// a ChemicalQuantity instance. The first column, **Quantity**, lists the
// /// names of the quantities; the second column, **Units**, lists the default
// /// units of the quantity; and the third column, **Example**, lists the
// /// formatted strings needed to retrieve a quantity.
// ///
// /// | Quantity                 | Units  | Example                                    |
// /// | --------                 | -----  | -------                                    |
// /// | temperature              | kelvin | `"temperature(units=celsius)"`             |
// /// | pressure                 | pascal | `"pressure(units=bar)"`                    |
// /// | volume                   | m3     | `"volume(units=cm3)"`                      |
// /// | activity                 | ---    | `"activity(CO2(aq))"`                      |
// /// | activityCoefficient      | ---    | `"activityCoefficient(Na+)"`               |
// /// | fugacity                 | bar    | `"fugacity(CO2(g))"`                       |
// /// | chemicalPotential        | J/mol  | `"chemicalPotential(Cl-)"`                 |
// /// | elementAmount            | mol    | `"elementAmount(Ca)"`                      |
// /// | elementAmountInPhase     | mol    | `"elementAmountInPhase(Mg Aqueous)"`       |
// /// | elementMass              | kg     | `"elementMass(Fe units=g)"`                |
// /// | elementMassInPhase       | kg     | `"elementMassInPhase(C Gaseous)"`          |
// /// | elementMolality          | molal  | `"elementMolality(Cl units=mmolal)"`       |
// /// | elementMolarity          | molar  | `"elementMolarity(K units=mmolar)"`        |
// /// | speciesAmount            | mol    | `"speciesAmount(H2O(l))"`                  |
// /// | speciesMass              | kg     | `"speciesMass(Calcite units=g)"`           |
// /// | speciesMoleFraction      | ---    | `"speciesMoleFraction(HCO3-)"`             |
// /// | speciesMolality          | molal  | `"speciesMolality(Ca++)"`                  |
// /// | speciesMolarity          | molar  | `"speciesMolarity(Mg++)"`                  |
// /// | phaseAmount              | mol    | `"phaseAmount(Aqueous)"`                   |
// /// | phaseMass                | kg     | `"phaseMass(Dolomite)"`                    |
// /// | phaseVolume              | m3     | `"phaseVolume(Gaseous)"`                   |
// /// | pH                       | ---    | `"pH"`                                     |
// /// | pE                       | ---    | `"pE"`                                     |
// /// | Eh                       | volt   | `"Eh"`                                     |
// /// | ionicStrength            | molal  | `"ionicStrength"`                          |
// /// | fluidVolume              | m3     | `"fluidVolume(units=liter)"`               |
// /// | fluidVolumeFraction      | ---    | `"fluidVolumeFraction"`                    |
// /// | solidVolume              | m3     | `"solidVolume(units=mm3)"`                 |
// /// | solidVolumeFraction      | ---    | `"solidVolumeFraction"`                    |
// /// | reactionRate             | mol/s  | `"reactionRate(Dolomite units=mmol/hour)"` |
// /// | reactionEquilibriumIndex | ---    | `"reactionEquilibriumIndex(Quartz)"`       |
// /// | tag                      | ---    | `"tag"`                                    |
// /// | t                        | s      | `"t(units=minute)"`                        |
// /// | time                     | s      | `"time(units=year)"`                       |
// /// | progress                 | ---    | `"progress"`                               |
// ///
// class ChemicalQuantity
// {
// public:
//     /// A type to describe a chemical quantity function.
//     using Function = std::function<double()>;

//     /// Disable the default ChemicalQuantity constructor.
//     /// This is to enforce the initialization of ChemicalQuantity
//     /// instance with a ChemicalSystem instance.
//     ChemicalQuantity() = delete;

//     /// Construct a ChemicalQuantity instance from a ChemicalSystem object.
//     explicit ChemicalQuantity(const ChemicalSystem& system);

//     /// Construct a ChemicalQuantity instance from a ReactionSystem object.
//     explicit ChemicalQuantity(const ReactionSystem& reactions);

//     /// Construct a ChemicalQuantity instance from a ChemicalState object.
//     explicit ChemicalQuantity(const ChemicalState& state);

//     /// Destroy this ChemicalQuantity instance.
//     virtual ~ChemicalQuantity() = default;

//     /// Return the chemical system of the ChemicalQuantity instance.
//     auto system() const -> const ChemicalSystem&;

//     /// Return the chemical reactions of the ChemicalQuantity instance.
//     auto reactions() const -> const ReactionSystem&;

//     /// Return the chemical state of the ChemicalQuantity instance.
//     auto state() const -> const ChemicalState&;

//     /// Return the chemical properties of the ChemicalQuantity instance.
//     auto props() const -> const ChemicalProps&;

//     /// Return the reaction rates of the ChemicalQuantity instance.
//     auto rates() const -> const VectorXr&;

//     /// Return the tag variable of the ChemicalQuantity instance.
//     auto tag() const -> double;

//     /// Update the state of this ChemicalQuantity instance.
//     auto update(const ChemicalState& state) -> ChemicalQuantity&;

//     /// Update the state of this ChemicalQuantity instance.
//     auto update(const ChemicalState& state, double t) -> ChemicalQuantity&;

//     /// Return the value of the quantity given as a formatted string.
//     auto value(std::string str) const -> double;

//     /// Return a created function that calculates the chemical quantity from a formatted string.
//     auto function(std::string str) const -> Function;

//     /// Return the value of the quantity given as a formatted string.
//     auto operator()(std::string str) const -> double;

// private:
//     struct Impl;

//     std::shared_ptr<Impl> pimpl;
// };

// } // namespace Reaktoro
