/**
 * This program calculates the chemical equilibrium composition for methane steam reforming
 * reactions at user-specified conditions. It uses Cantera's Gibbs free energy minimization
 * to determine the thermodynamically favorable product distribution.
 *
 * Key reactions modeled:
 * - Steam reforming: CH4 + H2O ⇌ CO + 3H2
 * - Methanol reforming: CH3OH + H2O ⇌ CO2 + 3H2
 * - Water-gas shift: CO + H2O ⇌ CO2 + H2
 * - Boudouard: 2CO ⇌ C(s) + CO2
 * The reactions are considered based on the reactions provided in the gri30.yaml mechanism file not selected by the user.
 *
 * @author Yashwanth Kutti Pochareddy & Claude AI
 * @date 26 November 2025
 * @version 0.5
 *
 * @dependencies
 * - Cantera 3.1.0 or higher
 * - GRI-Mech 3.0 mechanism file (gri30.yaml)
 * - C++17 compiler
 *
 * @usage
 * Compile: g++ Reforming_delG_Min.cpp -o Reforming_delG_Min -std=c++17 $(pkg-config --cflags --libs cantera)
 * Run: ./Reforming_delG_Min [options]
 *
 * @example
 * ./Reforming_delG_Min --CH4 1.0 --H2O 3.0 --temp 1073 --command par_all
 *
 * @license GNU General Public License version 3
 */

#include <string>
#include "cantera/zerodim.h"
#include <iostream>
#include <map>
#include <stdio.h>

using namespace Cantera;
using namespace std;

const string VERSION = "2.0.0";

// Command types for different output formats
enum mycmd {def, all, par_all, ch4_frac, ch3oh_frac, h2o_frac, h2_frac, co_frac, co2_frac, c_frac, o2_frac, temp_only, pressure_only};

// Maps for argument storage
map<string, string> arguments;
map<string, bool> arguments_single;
typedef map<string, string>::const_iterator argkey;
typedef map<string, bool>::const_iterator argkey_single;

// Default values for all parameters
double CH4_moles = 1.0;
double CH3OH_moles = 0.0;  // Methanol
double H2O_moles = 3.0;  // Steam-to-carbon ratio of 3
double CO2_moles = 0.0;
double CO_moles = 0.0;
double H2_moles = 0.0;
double O2_moles = 0.0;
double temperature = 1073.0;  // 800°C
double pressure_atm = 1.0;

// Output variables - will store equilibrium results
double eq_CH4_frac = 0.0;
double eq_CH3OH_frac = 0.0;
double eq_H2O_frac = 0.0;
double eq_H2_frac = 0.0;
double eq_CO_frac = 0.0;
double eq_CO2_frac = 0.0;
double eq_O2_frac = 0.0;
double eq_C_frac = 0.0;
double eq_temp = 0.0;
double eq_pressure = 0.0;

// Command mode
mycmd command = def;

// Function declarations
int load_arguments(int, char**);
void out_par_all();
void print_help();
void output();
int methane_reforming(int np, void* p);

int main(int argc, char** argv) {
    if (load_arguments(argc, argv) == 0)
        return 0;

    try {
        return methane_reforming(0, 0);
    } catch (CanteraError& err) {
        cerr << "Cantera Error: " << err.what() << endl;
        return -1;
    } catch (std::exception& e) {
        cerr << "Error: " << e.what() << endl;
        return -1;
    } catch (...) {
        cerr << "Unknown error occurred!" << endl;
        return -1;
    }
}

int methane_reforming(int np, void* p)
{
    // Validate inputs
    if (CH4_moles < 0 || CH3OH_moles < 0 || H2O_moles < 0 ||
        CO2_moles < 0 || CO_moles < 0 || H2_moles < 0 || O2_moles < 0)
    {
        cerr << "Error: Negative mole values are not allowed!" << endl;
        return -1;
    }

    double total_moles = CH4_moles + CH3OH_moles + H2O_moles + CO2_moles + CO_moles + H2_moles + O2_moles;
    if (total_moles <= 0)
    {
        cerr << "Error: Total moles must be greater than zero!" << endl;
        return -1;
    }

    if (temperature <= 0)
    {
        cerr << "Error: Temperature must be greater than zero!" << endl;
        return -1;
    }

    if (pressure_atm <= 0)
    {
        cerr << "Error: Pressure must be greater than zero!" << endl;
        return -1;
    }

    // Loading the thermodynamic species, reactions and phase data
    auto sol = newSolution("gri30.yaml");
    auto gas = sol->thermo();

    double pressure = pressure_atm * OneAtm;

    std::string composition = "CH4:" + std::to_string(CH4_moles) +
                             ", CH3OH:" + std::to_string(CH3OH_moles) +
                             ", H2O:" + std::to_string(H2O_moles) +
                             ", CO2:" + std::to_string(CO2_moles) +
                             ", CO:" + std::to_string(CO_moles) +
                             ", H2:" + std::to_string(H2_moles) +
                             ", O2:" + std::to_string(O2_moles);

    // Equilibrium calculation
    gas->setState_TPX(temperature, pressure, composition);
    gas->equilibrate("TP");

    // Store equilibrium results in global variables
    eq_temp = gas->temperature();
    eq_pressure = gas->pressure() / OneAtm;
    eq_CH4_frac = gas->moleFraction(gas->speciesIndex("CH4"));
    eq_CH3OH_frac = gas->moleFraction(gas->speciesIndex("CH3OH"));
    eq_H2O_frac = gas->moleFraction(gas->speciesIndex("H2O"));
    eq_H2_frac = gas->moleFraction(gas->speciesIndex("H2"));
    eq_CO_frac = gas->moleFraction(gas->speciesIndex("CO"));
    eq_CO2_frac = gas->moleFraction(gas->speciesIndex("CO2"));
    eq_O2_frac = gas->moleFraction(gas->speciesIndex("O2"));
    eq_C_frac = gas->moleFraction(gas->speciesIndex("C"));

    // Call output function based on command mode
    output();

    return 0;
}

void output()
{
    // Output of calculation results based on command type
    switch(command)
    {
        case par_all:
            out_par_all();
            break;
        case ch4_frac:
            cout << eq_CH4_frac << endl;
            break;
        case ch3oh_frac:
            cout << eq_CH3OH_frac << endl;
            break;
        case h2o_frac:
            cout << eq_H2O_frac << endl;
            break;
        case h2_frac:
            cout << eq_H2_frac << endl;
            break;
        case co_frac:
            cout << eq_CO_frac << endl;
            break;
        case co2_frac:
            cout << eq_CO2_frac << endl;
            break;
        case o2_frac:
            cout << eq_O2_frac << endl;
            break;
        case c_frac:
            cout << eq_C_frac << endl;
            break;
        case temp_only:
            cout << eq_temp << endl;
            break;
        case pressure_only:
            cout << eq_pressure << endl;
            break;
        case def:
        case all:
            {
                cout << "========== EQUILIBRIUM CALCULATION FOR STEAM METHANE REFORMING ==========" << endl;
                cout << endl;
                cout << "========== INPUT CONDITIONS ==========" << endl;
                cout << "Initial composition (moles):" << endl;
                cout << "  CH4: " << CH4_moles << endl;
                cout << "  CH3OH: " << CH3OH_moles << endl;
                cout << "  H2O: " << H2O_moles << endl;
                cout << "  CO2: " << CO2_moles << endl;
                cout << "  CO: " << CO_moles << endl;
                cout << "  H2: " << H2_moles << endl;
                cout << "  O2: " << O2_moles << endl;
                cout << "Temperature: " << temperature << " K" << endl;
                cout << "Pressure: " << pressure_atm << " atm" << endl;
                cout << "========== INPUT CONDITIONS ==========" << endl;
                cout << endl;

                cout << "========== EQUILIBRIUM RESULTS ==========" << endl;
                cout << "Temperature: " << eq_temp << " K" << endl;
                cout << "Pressure: " << eq_pressure << " atm" << endl << endl;

                cout << "Equilibrium species mole fractions:" << endl;
                cout << "  CH4: " << eq_CH4_frac << endl;
                cout << "  CH3OH: " << eq_CH3OH_frac << endl;
                cout << "  H2O: " << eq_H2O_frac << endl;
                cout << "  H2: " << eq_H2_frac << endl;
                cout << "  CO: " << eq_CO_frac << endl;
                cout << "  CO2: " << eq_CO2_frac << endl;
                cout << "  O2: " << eq_O2_frac << endl;
                cout << "  C: " << eq_C_frac << endl;
                cout << "========== EQUILIBRIUM RESULTS ==========" << endl;
                cout << endl;
                break;
            }
        default:
            print_help();
    }
}

void out_par_all()
{
    // Machine-readable output format for automated parsing
    printf("Temperature       %.2f\n", eq_temp);
    printf("Pressure          %.4f\n", eq_pressure);
    printf("CH4_fraction      %.6f\n", eq_CH4_frac);
    printf("CH3OH_fraction    %.6f\n", eq_CH3OH_frac);
    printf("H2O_fraction      %.6f\n", eq_H2O_frac);
    printf("H2_fraction       %.6f\n", eq_H2_frac);
    printf("CO_fraction       %.6f\n", eq_CO_frac);
    printf("CO2_fraction      %.6f\n", eq_CO2_frac);
    printf("O2_fraction       %.6f\n", eq_O2_frac);
    printf("C_fraction        %.6f\n", eq_C_frac);
    printf("All_values_in_mole_fractions\n");
}

int load_arguments(int argc, char** argv)
{
    // Parse all command-line arguments
    int i = 1;
    // Run through all arguments
    while (i != argc)
    {
        string str = argv[i];
        if (str.find("--", 0) != string::npos)
        {
            ++i;
            if (i == argc)
            {
                // we reached the end of the arguments with a single option so stop here
                arguments_single[str] = true;
                break;
            }
            string str2 = argv[i];
            if (str2.find("--", 0) == string::npos)
            {
                // The argument was a pair of the form '--option value', load that into hash
                arguments[str] = str2;
                ++i;
            }
            else
            {
                // The argument was a single one with a new option after
                arguments_single[str] = true;
            }
        }
        else
        {
            // The argument was not in the form '--option'!, load in single option hash
            arguments_single[str] = true;
            ++i;
        }
    }

    // Check for --version flag
    argkey_single key_single = arguments_single.find("--version");
    if (key_single != arguments_single.end())
    {
        cout << VERSION << endl;
        return 0;
    }

    // Check for --help flag
    key_single = arguments_single.find("--help");
    if (key_single != arguments_single.end())
    {
        print_help();
        return 0;
    }

    // Parse input species moles
    argkey key = arguments.find("--CH4");
    if (key != arguments.end())
        CH4_moles = atof(key->second.c_str());

    key = arguments.find("--CH3OH");
    if (key != arguments.end())
        CH3OH_moles = atof(key->second.c_str());

    key = arguments.find("--H2O");
    if (key != arguments.end())
        H2O_moles = atof(key->second.c_str());

    key = arguments.find("--CO2");
    if (key != arguments.end())
        CO2_moles = atof(key->second.c_str());

    key = arguments.find("--CO");
    if (key != arguments.end())
        CO_moles = atof(key->second.c_str());

    key = arguments.find("--H2");
    if (key != arguments.end())
        H2_moles = atof(key->second.c_str());
    
    key = arguments.find("--O2");
    if (key != arguments.end())
        O2_moles = atof(key->second.c_str());

    // Parse temperature
    key = arguments.find("--temp");
    if (key != arguments.end())
        temperature = atof(key->second.c_str());

    key = arguments.find("--temperature");
    if (key != arguments.end())
        temperature = atof(key->second.c_str());

    // Parse pressure
    key = arguments.find("--pressure");
    if (key != arguments.end())
        pressure_atm = atof(key->second.c_str());

    key = arguments.find("--P");
    if (key != arguments.end())
        pressure_atm = atof(key->second.c_str());

    // Parse command option
    key = arguments.find("--command");
    if (key != arguments.end())
    {
        string mystr = key->second;
        // Convert to lowercase for case-insensitive comparison
        std::transform(mystr.begin(), mystr.end(), mystr.begin(), ::tolower);

        if (mystr == "par_all")
            command = par_all;
        else if (mystr == "all")
            command = all;
        else if (mystr == "ch4_frac" || mystr == "ch4")
            command = ch4_frac;
        else if (mystr == "ch3oh_frac" || mystr == "ch3oh")
            command = ch3oh_frac;
        else if (mystr == "h2o_frac" || mystr == "h2o")
            command = h2o_frac;
        else if (mystr == "h2_frac" || mystr == "h2")
            command = h2_frac;
        else if (mystr == "co_frac" || mystr == "co")
            command = co_frac;
        else if (mystr == "co2_frac" || mystr == "co2")
            command = co2_frac;
        else if (mystr == "o2_frac" || mystr == "o2")
            command = o2_frac;
        else if (mystr == "c_frac" || mystr == "c")
            command = c_frac;
        else if (mystr == "temp" || mystr == "temperature")
            command = temp_only;
        else if (mystr == "pressure" || mystr == "p")
            command = pressure_only;
    }

    return 1;
}

void print_help()
{
    printf("\n\n    Methane/Methanol Steam Reforming Equilibrium Calculator\n\n");
    printf("This program calculates the chemical equilibrium composition for\n");
    printf("methane and methanol steam reforming reactions using Gibbs free\n");
    printf("energy minimization via Cantera.\n\n");
    printf("Key reactions modeled:\n");
    printf("  - Steam reforming: CH4 + H2O ⇌ CO + 3H2\n");
    printf("  - Methanol reforming: CH3OH + H2O ⇌ CO2 + 3H2\n");
    printf("  - Water-gas shift: CO + H2O ⇌ CO2 + H2\n");
    printf("  - Boudouard: 2CO ⇌ C(s) + CO2\n\n");
    printf("Usage: \n\n");
    printf("  Reforming_delG_Min [opt: --help --version] --INPUT1 VALUE1 --INPUT2 VALUE2 ... \n\n");
    printf("  INPUT is the command for which the VALUE is the corresponding input value.\n\n");
    printf("     --command   : Forces output into the following formats:\n");
    printf("                   If no command is given, the output is verbose (same as 'all').\n");
    printf("          all    : All values are displayed (verbose output).\n");
    printf("          par_all: Outputs all parameters in machine-readable format,\n");
    printf("                   one parameter per line (for automated parsing).\n");
    printf("          ch4    : Outputs only the CH4 mole fraction.\n");
    printf("          ch3oh  : Outputs only the CH3OH mole fraction.\n");
    printf("          h2o    : Outputs only the H2O mole fraction.\n");
    printf("          h2     : Outputs only the H2 mole fraction.\n");
    printf("          co     : Outputs only the CO mole fraction.\n");
    printf("          co2    : Outputs only the CO2 mole fraction.\n");
    printf("          o2     : Outputs only the O2 mole fraction.\n");
    printf("          c      : Outputs only the C (solid carbon) mole fraction.\n");
    printf("          temp   : Outputs only the equilibrium temperature.\n");
    printf("          pressure: Outputs only the equilibrium pressure.\n");
    printf("\n");
    printf("     --CH4       : Inputs the CH4 moles, default is 1.0.\n");
    printf("\n");
    printf("     --CH3OH     : Inputs the CH3OH (methanol) moles, default is 0.0.\n");
    printf("\n");
    printf("     --H2O       : Inputs the H2O moles, default is 3.0.\n");
    printf("\n");
    printf("     --CO2       : Inputs the CO2 moles, default is 0.0.\n");
    printf("\n");
    printf("     --CO        : Inputs the CO moles, default is 0.0.\n");
    printf("\n");
    printf("     --H2        : Inputs the H2 moles, default is 0.0.\n");
    printf("\n");
    printf("     --O2        : Inputs the O2 moles, default is 0.0.\n");
    printf("\n");
    printf("     --temp      : Inputs the temperature in Kelvin, default is 1073 K.\n");
    printf("     --temperature: (Same as --temp)\n");
    printf("\n");
    printf("     --pressure  : Inputs the pressure in atm, default is 1.0 atm.\n");
    printf("     --P         : (Same as --pressure)\n");
    printf("\n");
    printf("Examples:\n\n");
    printf("  # Run with defaults (CH4=1.0, H2O=3.0, T=1073K, P=1atm)\n");
    printf("  ./Reforming_delG_Min\n\n");
    printf("  # Specify all flow values and conditions\n");
    printf("  ./Reforming_delG_Min --CH4 1.5 --H2O 4.5 --CO2 0.1 --temp 1123 --pressure 1.5\n\n");
    printf("  # Include methanol in feed\n");
    printf("  ./Reforming_delG_Min --CH4 0.5 --CH3OH 0.5 --H2O 3.0 --temp 1073\n\n");
    printf("  # Include oxygen in feed\n");
    printf("  ./Reforming_delG_Min --CH4 1.0 --O2 0.5 --H2O 3.0 --temp 1073\n\n");
    printf("  # Get machine-readable output for automated processing\n");
    printf("  ./Reforming_delG_Min --CH4 1.0 --H2O 3.0 --command par_all\n\n");
    printf("  # Get only H2 mole fraction (useful for piping to other programs)\n");
    printf("  ./Reforming_delG_Min --CH4 1.0 --H2O 3.0 --temp 1123 --command h2\n\n");
    printf("  # Use in a script to capture output\n");
    printf("  h2_frac=$(./Reforming_delG_Min --CH4 1.0 --H2O 3.0 --command h2)\n");
    printf("  echo \"H2 fraction is: $h2_frac\"\n\n");
    printf("If the --version option is given, the version number\n");
    printf("is displayed and the program exits.\n");
    printf("The --help option displays this information.\n\n");
    printf("Version: %s\n\n", VERSION.c_str());
}
