#ifdef _DEBUG
#pragma warning(disable : 4786)	// disable truncation warning (Only used by debugger)
#endif
#include <iostream>
#include <fstream>
#include <sstream>

#include "Utils.h"
#include "Phreeqc.h"
#include "Parser.h"
#include "Solution.h"
#include "Exchange.h"
#include "Surface.h"
#include "PPassemblage.h"
#include "cxxKinetics.h"
#include "SSassemblage.h"
#include "GasPhase.h"
#include "Reaction.h"
#include "cxxMix.h"
#include "Temperature.h"
#include "dumper.h"
#include "runner.h"
#include "cxxMix.h"
#include "Surface.h"
#include "phqalloc.h"

#if defined(PHREEQCI_GUI)
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#endif

/* ---------------------------------------------------------------------- */
int Phreeqc::
read_dump(void)
/* ---------------------------------------------------------------------- */
{
/*
 *      Reads DUMP data block
 *
 *      Arguments:
 *         none
 *
 *      Returns:
 *         KEYWORD if keyword encountered, input_error may be incremented if
 *                    a keyword is encountered in an unexpected position
 *         EOF     if eof encountered while reading mass balance concentrations
 *         ERROR   if error occurred reading data
 *
 */
	int return_value;
	/*
	 *  Make parser
	 */
	std::istringstream iss_in;
	return_value = streamify_to_next_keyword(iss_in);
	CParser parser(iss_in, phrq_io);
	assert(!reading_database());

	//For testing, need to read line to get started
	parser.set_echo_file(CParser::EO_NONE);
	std::vector < std::string > vopts;
	std::istream::pos_type next_char;
	parser.get_option(vopts, next_char);

	if (pr.echo_input == FALSE)
	{
		parser.set_echo_file(CParser::EO_NONE);
	}
	else
	{
		parser.set_echo_file(CParser::EO_NOKEYWORDS);
	}

	dump_info.Read(parser);

	// Need to output the next keyword
	if (return_value == OPTION_KEYWORD) echo_msg(sformatf( "\t%s\n", line));
	return (return_value);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_delete(void)
/* ---------------------------------------------------------------------- */
{
/*
 *      Reads DELETE data block
 *
 *      Arguments:
 *         none
 *
 *      Returns:
 *         KEYWORD if keyword encountered, input_error may be incremented if
 *                    a keyword is encountered in an unexpected position
 *         EOF     if eof encountered while reading mass balance concentrations
 *         ERROR   if error occurred reading data
 *
 */
	int return_value;
	/*
	 *  Make parser
	 */
	std::istringstream iss_in;
	return_value = streamify_to_next_keyword(iss_in);
	CParser parser(iss_in, phrq_io);
	//assert(!reading_database());

	//For testing, need to read line to get started
	parser.set_echo_file(CParser::EO_NONE);
	std::vector < std::string > vopts;
	std::istream::pos_type next_char;
	parser.get_option(vopts, next_char);

	if (pr.echo_input == FALSE)
	{
		parser.set_echo_file(CParser::EO_NONE);
	}
	else
	{
		parser.set_echo_file(CParser::EO_NOKEYWORDS);
	}

	delete_info.Read(parser);


	// Need to output the next keyword
	if (return_value == OPTION_KEYWORD) echo_msg(sformatf( "\t%s\n", line));
	return (return_value);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_run_cells(void)
/* ---------------------------------------------------------------------- */
{
/*
 *      Reads DELETE data block
 *
 *      Arguments:
 *         none
 *
 *      Returns:
 *         KEYWORD if keyword encountered, input_error may be incremented if
 *                    a keyword is encountered in an unexpected position
 *         EOF     if eof encountered while reading mass balance concentrations
 *         ERROR   if error occurred reading data
 *
 */
	int return_value;
	/*
	 *  Make parser
	 */
	std::istringstream iss_in;
	return_value = streamify_to_next_keyword(iss_in);
	CParser parser(iss_in, phrq_io);
	assert(!reading_database());

	//For testing, need to read line to get started
	parser.set_echo_file(CParser::EO_NONE);
	std::vector < std::string > vopts;
	std::istream::pos_type next_char;
	parser.get_option(vopts, next_char);

	if (pr.echo_input == FALSE)
	{
		parser.set_echo_file(CParser::EO_NONE);
	}
	else
	{
		parser.set_echo_file(CParser::EO_NOKEYWORDS);
	}

	runner r(parser, phrq_io);
	run_info = r;


	// Need to output the next keyword
	if (return_value == OPTION_KEYWORD) echo_msg(sformatf( "\t%s\n", line));
	return (return_value);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
streamify_to_next_keyword(std::istringstream & lines)
/* ---------------------------------------------------------------------- */
{
/*
 *   Reads to next keyword or eof
 *
 *   Returns:
 *       OPTION_KEYWORD
 *       OPTION_EOF
 *       
 */
	// Handle echo
	int save_echo_input = pr.echo_input;
	pr.echo_input = FALSE;

	std::string accumulate(line);
	accumulate.append("\n");
	int j;
	for (;;)
	{
		j = check_line("Streamify", FALSE, TRUE, TRUE, FALSE);
		if (j == EOF)
		{						/* end of file */
			break;
		}
		else if (j == KEYWORD)
		{						/* keyword */
			break;
		}
		else
		{
			accumulate.append(line);
			accumulate.append("\n");
		}
	}

	lines.str(accumulate);
	pr.echo_input = save_echo_input;
	if (j == EOF) return (OPTION_EOF);
	if (j == KEYWORD) return (OPTION_KEYWORD);


	return (OPTION_ERROR);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
dump_entities(void)
/* ---------------------------------------------------------------------- */
{
	if (!dump_info.Get_on() || pr.dump == FALSE)
	{
		return(OK);
	}
	dump_info.Set_on(false);
	if (!dump_info.Get_bool_any())
	{
		return(OK);
	}

	if (this->phrq_io)
	{
		std::ios_base::openmode mode = std::ios_base::out;
		if (dump_info.Get_append())
		{
			mode = std::ios_base::app;
		}
		if (this->phrq_io->dump_open(dump_info.Get_file_name().c_str(), mode))
		{
			dump_ostream(*this->phrq_io->Get_dump_ostream());
			this->phrq_io->dump_close();
		}
		else
		{
			error_string = sformatf( "Unable to open dump file \"%s\"", dump_info.Get_file_name().c_str());
			error_msg(error_string, STOP);
		}
	}
	return (OK);
}
/* ---------------------------------------------------------------------- */
int Phreeqc::
delete_entities(void)
/* ---------------------------------------------------------------------- */
{
	if (!delete_info.Get_solution().Get_defined() &&
		!delete_info.Get_pp_assemblage().Get_defined() &&
		!delete_info.Get_exchange().Get_defined() &&
		!delete_info.Get_surface().Get_defined() &&
		!delete_info.Get_ss_assemblage().Get_defined() &&
		!delete_info.Get_gas_phase().Get_defined() &&
		!delete_info.Get_kinetics().Get_defined() &&
		!delete_info.Get_mix().Get_defined() &&
		!delete_info.Get_reaction().Get_defined() &&
		!delete_info.Get_temperature().Get_defined() &&
		!delete_info.Get_pressure().Get_defined())
	{
		return(OK);
	}

	// solutions
	if (delete_info.Get_solution().Get_defined())
	{
		if (delete_info.Get_solution().Get_numbers().size() == 0)
		{
			Rxn_solution_map.clear();
		}
		else
		{
			std::set < int >::iterator it;
			for (it = delete_info.Get_solution().Get_numbers().begin(); it != delete_info.Get_solution().Get_numbers().end(); it++)
			{
				Rxn_solution_map.erase(*it);
			}
		}
	}

	// pp_assemblages
	if (delete_info.Get_pp_assemblage().Get_defined())
	{
		if (delete_info.Get_pp_assemblage().Get_numbers().size() == 0)
		{
			Rxn_pp_assemblage_map.clear();
		}
		else
		{
			std::set < int >::iterator it;
			for (it = delete_info.Get_pp_assemblage().Get_numbers().begin(); it != delete_info.Get_pp_assemblage().Get_numbers().end(); it++)
			{
				Rxn_pp_assemblage_map.erase(*it);
			}
		}
	}
	// exchangers
	if (delete_info.Get_exchange().Get_defined())
	{
		if (delete_info.Get_exchange().Get_numbers().size() == 0)
		{
			Rxn_exchange_map.clear();
		}
		else
		{
			std::set < int >::iterator it;
			for (it = delete_info.Get_exchange().Get_numbers().begin(); it != delete_info.Get_exchange().Get_numbers().end(); it++)
			{
				Rxn_exchange_map.erase(*it);
			}
		}
	}
	// surfaces
	if (delete_info.Get_surface().Get_defined())
	{
		if (delete_info.Get_surface().Get_numbers().size() == 0)
		{
			Rxn_surface_map.clear();
		}
		else
		{
			std::set < int >::iterator it;
			for (it = delete_info.Get_surface().Get_numbers().begin(); it != delete_info.Get_surface().Get_numbers().end(); it++)
			{
				Rxn_surface_map.erase(*it);
			}
		}
	}
	// ss_assemblages
	if (delete_info.Get_ss_assemblage().Get_defined())
	{
		if (delete_info.Get_ss_assemblage().Get_numbers().size() == 0)
		{
			Rxn_ss_assemblage_map.clear();
		}
		else
		{
			std::set < int >::iterator it;
			for (it = delete_info.Get_ss_assemblage().Get_numbers().begin(); it != delete_info.Get_ss_assemblage().Get_numbers().end(); it++)
			{
				Rxn_ss_assemblage_map.erase(*it);
			}
		}
	}
	// gas_phases
	if (delete_info.Get_gas_phase().Get_defined())
	{
		if (delete_info.Get_gas_phase().Get_numbers().size() == 0)
		{
			Rxn_gas_phase_map.clear();
		}
		else
		{
			std::set < int >::iterator it;
			for (it = delete_info.Get_gas_phase().Get_numbers().begin(); it != delete_info.Get_gas_phase().Get_numbers().end(); it++)
			{
				Rxn_gas_phase_map.erase(*it);
			}
		}
	}
	// kinetics
	if (delete_info.Get_kinetics().Get_defined())
	{
		if (delete_info.Get_kinetics().Get_numbers().size() == 0)
		{
			Rxn_kinetics_map.clear();
		}
		else
		{
			std::set < int >::iterator it;
			for (it = delete_info.Get_kinetics().Get_numbers().begin(); it != delete_info.Get_kinetics().Get_numbers().end(); it++)
			{
				Rxn_kinetics_map.erase(*it);
			}
		}
	}
	// mixes
	if (delete_info.Get_mix().Get_defined())
	{
		if (delete_info.Get_mix().Get_numbers().size() == 0)
		{
			Rxn_mix_map.clear();
		}
		else
		{
			std::set < int >::iterator it;
			for (it = delete_info.Get_mix().Get_numbers().begin(); it != delete_info.Get_mix().Get_numbers().end(); it++)
			{
				Rxn_mix_map.erase(*it);
			}
		}
	}
	// reactions
	if (delete_info.Get_reaction().Get_defined())
	{
		if (delete_info.Get_reaction().Get_numbers().size() == 0)
		{
			Rxn_reaction_map.clear();
		}
		else
		{
			std::set < int >::iterator it;
			for (it = delete_info.Get_reaction().Get_numbers().begin(); it != delete_info.Get_reaction().Get_numbers().end(); it++)
			{
				Rxn_reaction_map.erase(*it);
			}
		}
	}
	// temperatures
	if (delete_info.Get_temperature().Get_defined())
	{
		if (delete_info.Get_temperature().Get_numbers().size() == 0)
		{
			Rxn_temperature_map.clear();
		}
		else
		{
			std::set < int >::iterator it;
			for (it = delete_info.Get_temperature().Get_numbers().begin(); it != delete_info.Get_temperature().Get_numbers().end(); it++)
			{
				Rxn_temperature_map.erase(*it);
			}
		}
	}
	// pressures
	if (delete_info.Get_pressure().Get_defined())
	{
		if (delete_info.Get_pressure().Get_numbers().size() == 0)
		{
			Rxn_pressure_map.clear();
		}
		else
		{
			std::set < int >::iterator it;
			for (it = delete_info.Get_pressure().Get_numbers().begin(); it != delete_info.Get_pressure().Get_numbers().end(); it++)
			{
				Rxn_pressure_map.erase(*it);
			}
		}
	}
	// Turn off delete until next read
	delete_info.SetAll(false);
	return (OK);
}
#ifdef USE_OPTIMIZED_BUT_NOT_MUCH
/* ---------------------------------------------------------------------- */
int Phreeqc::
run_as_cells(void)
/* ---------------------------------------------------------------------- */
{
	class save save_data;
	LDBLE kin_time;
	int count_steps, use_mix;
	char token[2 * MAX_LENGTH];

	state = REACTION;
	if (run_info.Get_cells().Get_numbers().size() == 0 ||
		!(run_info.Get_cells().Get_defined())) return(OK);

	// running cells
	run_info.Set_run_cells(true);

	dup_print("Beginning of run as cells.", TRUE);
	LDBLE initial_total_time_save;
	if (run_info.Get_start_time() != NA)
	{
		initial_total_time_save = run_info.Get_start_time();
	}
	else
	{
		initial_total_time_save = initial_total_time;
	}

	std::set < int >::iterator it = run_info.Get_cells().Get_numbers().begin();

	for ( ; it != run_info.Get_cells().Get_numbers().end(); it++)
	{
		int i = *it;
		if (i < 0) continue;
		initial_total_time = initial_total_time_save;
		cxxKinetics *kinetics_ptr = NULL;
/*
 *   Run reaction step
 */
		/*
		*   Find maximum number of steps
		*/
		dup_print("Beginning of batch-reaction calculations.", TRUE);
		count_steps = 1;
		if (cxxReaction *rxn_ptr = Utilities::Rxn_find(Rxn_reaction_map, i))
		{
			int count = rxn_ptr->Get_reaction_steps();
			if (count > count_steps)
				count_steps = count;
		}
		if (cxxKinetics *rxn_ptr = Utilities::Rxn_find(Rxn_kinetics_map, i))
		{
			kinetics_ptr = rxn_ptr;
			if (rxn_ptr->Get_reaction_steps() > count_steps)
				count_steps = rxn_ptr->Get_reaction_steps();
		}
		if (cxxTemperature *rxn_ptr = Utilities::Rxn_find(Rxn_temperature_map, i))
		{
			int count = rxn_ptr->Get_countTemps();
			if (count > count_steps)
			{
				count_steps = count;
			}
		}
		if (cxxPressure *rxn_ptr = Utilities::Rxn_find(Rxn_pressure_map, i))
		{
			int count = rxn_ptr->Get_count();
			if (count > count_steps)
			{
				count_steps = count;
			}
		}
		count_total_steps = count_steps;
		if (count_steps > 1)
		{
			state = ADVECTION;
			set_advection(i, TRUE, TRUE, i);
			/*
			*  save data for saving solutions
			*/
			memcpy(&save_data, &save, sizeof(class save));
			/* 
			*Copy everything to -2
			*/
			copy_use(-2);
			rate_sim_time_start = 0;
			rate_sim_time = 0;
			for (reaction_step = 1; reaction_step <= count_steps; reaction_step++)
			{
				sprintf(token, "Reaction step %d.", reaction_step);
				if (reaction_step > 1 && incremental_reactions == FALSE)
				{
					copy_use(-2);
				}
				set_initial_moles(-2);
				dup_print(token, FALSE);
				/*
				*  Determine time step for kinetics
				*/
				kin_time = 0.0;
				if (use.Get_kinetics_in() == TRUE)
				{
					// runner kin_time
					// equivalent to kin_time in count_steps
					if (run_info.Get_time_step() != NA)
					{
						if (incremental_reactions == FALSE)
						{
							/* not incremental reactions */
							kin_time = reaction_step * run_info.Get_time_step() / ((LDBLE) count_steps);
						}
						else
						{
							/* incremental reactions */
							kin_time = run_info.Get_time_step() / ((LDBLE) count_steps);
						}
					}
					// runner kin_time not defined
					else
					{
						cxxKinetics *kinetics_ptr = Utilities::Rxn_find(Rxn_kinetics_map, -2);
						kin_time = kinetics_ptr->Current_step((incremental_reactions==TRUE), reaction_step);
					}
				}
				if (incremental_reactions == FALSE ||
					(incremental_reactions == TRUE && reaction_step == 1))
				{
					use_mix = TRUE;
				}
				else
				{
					use_mix = FALSE;
				}
				/*
				*   Run reaction step
				*/
				run_reactions(-2, kin_time, use_mix, 1.0);
				if (incremental_reactions == TRUE)
				{
					rate_sim_time_start += kin_time;
					rate_sim_time = rate_sim_time_start;
				}
				else
				{
					rate_sim_time = kin_time;
				}
				punch_all();
				print_all();
				/* saves back into -2 */
				if (reaction_step < count_steps)
				{
					saver();
				}
			}
			/*
			*   save end of reaction
			*/
			memcpy(&save, &save_data, sizeof(class save));
			if (use.Get_kinetics_in() == TRUE)
			{
				Utilities::Rxn_copy(Rxn_kinetics_map, -2, use.Get_n_kinetics_user());
			}
			saver();
		}
		else
			// only 1 step, no worries about incremental reactions
		{
			state = TRANSPORT;

			rate_sim_time_start = 0;
			rate_sim_time = 0;
			reaction_step = 1;

			sprintf(token, "Reaction step %d.", reaction_step);

			dup_print(token, FALSE);
			/*
			*  Determine time step for kinetics
			*/
			kin_time = 0.0;
			if (kinetics_ptr)
			{
				// runner kin_time
				// equivalent to kin_time in count_steps
				if (run_info.Get_time_step() != NA)
				{
					kin_time = run_info.Get_time_step();
				}
				// runner kin_time not defined
				else
				{
					kin_time = kinetics_ptr->Get_steps()[0];
				}
			}
			/*
			*   Run reaction step
			*/
			use_mix = TRUE;
			run_reactions(i, kin_time, use_mix, 1.0);
			rate_sim_time = kin_time;
			saver();
		}
	}
	initial_total_time += rate_sim_time;
	run_info.Get_cells().Set_defined(false);
	// not running cells
	run_info.Set_run_cells(false);
	return (OK);
}
#else
/* ---------------------------------------------------------------------- */
int Phreeqc::
run_as_cells(void)
/* ---------------------------------------------------------------------- */
{
	class save save_data;
	LDBLE kin_time;
	int count_steps, use_mix;
	char token[2 * MAX_LENGTH];

	state = REACTION;
	if (run_info.Get_cells().Get_numbers().size() == 0 ||
		!(run_info.Get_cells().Get_defined())) return(OK);

	// running cells
	run_info.Set_run_cells(true);

	dup_print("Beginning of run as cells.", TRUE);
	LDBLE initial_total_time_save;
	if (run_info.Get_start_time() != NA)
	{
		initial_total_time_save = run_info.Get_start_time();
	}
	else
	{
		initial_total_time_save = initial_total_time;
	}

	std::set < int >::iterator it = run_info.Get_cells().Get_numbers().begin();

	for ( ; it != run_info.Get_cells().Get_numbers().end(); it++)
	{
		int i = *it;
		if (i < 0) continue;
		if (Utilities::Rxn_find(Rxn_solution_map, i) == NULL
			&& Utilities::Rxn_find(Rxn_mix_map, i) == NULL)
			continue;
		initial_total_time = initial_total_time_save;
		set_advection(i, TRUE, TRUE, i);
/*
 *   Run reaction step
 */
		/*
		*   Find maximum number of steps
		*/
		dup_print("Beginning of batch-reaction calculations.", TRUE);
		count_steps = 1;
		if (!this->run_cells_one_step)
		{
			if (use.Get_reaction_in() == TRUE && use.Get_reaction_ptr() != NULL)
			{
				int count = use.Get_reaction_ptr()->Get_reaction_steps();
				if (count > count_steps)
					count_steps = count;
			}
			if (use.Get_kinetics_in() == TRUE && use.Get_kinetics_ptr() != NULL)
			{
				if (use.Get_kinetics_ptr()->Get_reaction_steps() > count_steps)
					count_steps = use.Get_kinetics_ptr()->Get_reaction_steps();
			}
			if (use.Get_temperature_in() == TRUE && use.Get_temperature_ptr() != NULL)
			{
				int count = use.Get_temperature_ptr()->Get_countTemps();
				if (count > count_steps)
				{
					count_steps = count;
				}
			}
			if (use.Get_pressure_in() == TRUE && use.Get_pressure_ptr() != NULL)
			{
				int count = use.Get_pressure_ptr()->Get_count();
				if (count > count_steps)
				{
					count_steps = count;
				}
			}
		}
		count_total_steps = count_steps;
		/*
		*  save data for saving solutions
		*/
		// memcpy(&save_data, &save, sizeof(class save));
		save_data = save;
		/* 
		*Copy everything to -2
		*/
		copy_use(-2);
		rate_sim_time_start = 0;
		rate_sim_time = 0;
		for (reaction_step = 1; reaction_step <= count_steps; reaction_step++)
		{
			sprintf(token, "Reaction step %d.", reaction_step);
			if (reaction_step > 1 && incremental_reactions == FALSE)
			{
				copy_use(-2);
			}
			set_initial_moles(-2);
			dup_print(token, FALSE);
			/*
			*  Determine time step for kinetics
			*/
			kin_time = 0.0;
			if (use.Get_kinetics_in() == TRUE)
			{
				// runner kin_time
				// equivalent to kin_time in count_steps
				if (run_info.Get_time_step() != NA)
				{
					if (incremental_reactions == FALSE)
					{
						/* not incremental reactions */
						kin_time = reaction_step * run_info.Get_time_step() / ((LDBLE) count_steps);
					}
					else
					{
						/* incremental reactions */
						kin_time = run_info.Get_time_step() / ((LDBLE) count_steps);
					}
				}
				// runner kin_time not defined
				else
				{
					cxxKinetics *kinetics_ptr = Utilities::Rxn_find(Rxn_kinetics_map, -2);
					kin_time = kinetics_ptr->Current_step((incremental_reactions==TRUE), reaction_step);
				}
			}
			if (incremental_reactions == FALSE ||
				(incremental_reactions == TRUE && reaction_step == 1))
			{
				use_mix = TRUE;
			}
			else
			{
				use_mix = FALSE;
			}
			/*
			*   Run reaction step
			*/
			run_reactions(-2, kin_time, use_mix, 1.0);
			if (incremental_reactions == TRUE)
			{
				rate_sim_time_start += kin_time;
				rate_sim_time = rate_sim_time_start;
			}
			else
			{
				rate_sim_time = kin_time;
			}
			if (state != ADVECTION)
			{
				punch_all();
				print_all();
			}
			/* saves back into -2 */
			if (reaction_step < count_steps)
			{
				saver();
			}
		}
		/*
		*   save end of reaction
		*/
		// memcpy(&save, &save_data, sizeof(class save));
		save = save_data;
		if (use.Get_kinetics_in() == TRUE)
		{
			Utilities::Rxn_copy(Rxn_kinetics_map, -2, use.Get_n_kinetics_user());
		}
		saver();
	}
	initial_total_time += rate_sim_time;
	run_info.Get_cells().Set_defined(false);
	// not running cells
	run_info.Set_run_cells(false);
	return (OK);
}
#endif
/* ---------------------------------------------------------------------- */
void Phreeqc::
dump_ostream(std::ostream& os)
/* ---------------------------------------------------------------------- */
{
	// solutions
	if (dump_info.Get_bool_solution())
	{
		if (dump_info.Get_solution().size() == 0)
		{
			Utilities::Rxn_dump_raw(Rxn_solution_map, os, 0);
		}
		else
		{
			std::set < int >::iterator it;
			for (it = dump_info.Get_solution().begin(); it != dump_info.Get_solution().end(); it++)
			{
				cxxSolution *p = Utilities::Rxn_find(Rxn_solution_map, *it);
				if (p != NULL && p->Get_n_user() >= 0)
				{
					p->dump_raw(os, 0);
				}
			}
		}
	}

	// pp_assemblages
	if (dump_info.Get_bool_pp_assemblage())
	{
		if (dump_info.Get_pp_assemblage().size() == 0)
		{
			Utilities::Rxn_dump_raw(Rxn_pp_assemblage_map, os, 0);
		}
		else
		{
			std::set < int >::iterator it;
			for (it = dump_info.Get_pp_assemblage().begin(); it != dump_info.Get_pp_assemblage().end(); it++)
			{
				cxxPPassemblage *p = Utilities::Rxn_find(Rxn_pp_assemblage_map, *it);

				if (p != NULL && p->Get_n_user() >= 0)
				{
					p->dump_raw(os, 0);
				}
			}
		}
	}
	// exchanges
	if (dump_info.Get_bool_exchange())
	{
		if (dump_info.Get_exchange().size() == 0)
		{
			Utilities::Rxn_dump_raw(Rxn_exchange_map, os, 0);
		}
		else
		{
			std::set < int >::iterator it;
			for (it = dump_info.Get_exchange().begin(); it != dump_info.Get_exchange().end(); it++)
			{
				cxxExchange *p = Utilities::Rxn_find(Rxn_exchange_map, *it);

				if (p != NULL && p->Get_n_user() >= 0)
				{
					p->dump_raw(os, 0);
				}
			}
		}
	}

	// surfaces
	if (dump_info.Get_bool_surface())
	{
		if (dump_info.Get_surface().size() == 0)
		{
			Utilities::Rxn_dump_raw(Rxn_surface_map, os, 0);
		}
		else
		{
			std::set < int >::iterator it;
			for (it = dump_info.Get_surface().begin(); it != dump_info.Get_surface().end(); it++)
			{
				cxxSurface *p = Utilities::Rxn_find(Rxn_surface_map, *it);

				if (p != NULL && p->Get_n_user() >= 0)
				{
					p->dump_raw(os, 0);
				}
			}
		}
	}
	// ss_assemblages
	if (dump_info.Get_bool_ss_assemblage())
	{
		if (dump_info.Get_ss_assemblage().size() == 0)
		{
			Utilities::Rxn_dump_raw(Rxn_ss_assemblage_map, os, 0);
		}
		else
		{
			std::set < int >::iterator it;
			for (it = dump_info.Get_ss_assemblage().begin(); it != dump_info.Get_ss_assemblage().end(); it++)
			{
				cxxSSassemblage *p = Utilities::Rxn_find(Rxn_ss_assemblage_map, *it);

				if (p != NULL && p->Get_n_user() >= 0)
				{
					p->dump_raw(os, 0);
				}
			}
		}
	}
	// gas_phases
	if (dump_info.Get_bool_gas_phase())
	{
		if (dump_info.Get_gas_phase().size() == 0)
		{
			Utilities::Rxn_dump_raw(Rxn_gas_phase_map, os, 0);
		}
		else
		{
			std::set < int >::iterator it;
			for (it = dump_info.Get_gas_phase().begin(); it != dump_info.Get_gas_phase().end(); it++)
			{
				cxxGasPhase *p = Utilities::Rxn_find(Rxn_gas_phase_map, *it);

				if (p != NULL && p->Get_n_user() >= 0)
				{
					p->dump_raw(os, 0);
				}
			}
		}
	}

	// kinetics
	if (dump_info.Get_bool_kinetics())
	{
		if (dump_info.Get_kinetics().size() == 0)
		{
			Utilities::Rxn_dump_raw(Rxn_kinetics_map, os, 0);
		}
		else
		{
			std::set < int >::iterator it;
			for (it = dump_info.Get_kinetics().begin(); it != dump_info.Get_kinetics().end(); it++)
			{
				cxxKinetics *p = Utilities::Rxn_find(Rxn_kinetics_map, *it);

				if (p != NULL && p->Get_n_user() >= 0)
				{
					p->dump_raw(os, 0);
				}
			}
		}
	}
	// mix
	if (dump_info.Get_bool_mix())
	{
		if (dump_info.Get_mix().size() == 0)
		{
			Utilities::Rxn_dump_raw(Rxn_mix_map, os, 0);
		}
		else
		{
			std::set < int >::iterator it;
			for (it = dump_info.Get_mix().begin(); it != dump_info.Get_mix().end(); it++)
			{
				cxxMix *p = Utilities::Rxn_find(Rxn_mix_map, *it);

				if (p != NULL && p->Get_n_user() >= 0)
				{
					p->dump_raw(os, 0);
				}
			}
		}
	}

	// reaction
	if (dump_info.Get_bool_reaction())
	{
		if (dump_info.Get_reaction().size() == 0)
		{
			Utilities::Rxn_dump_raw(Rxn_reaction_map, os, 0);
		}
		else
		{
			std::set < int >::iterator it;
			for (it = dump_info.Get_reaction().begin(); it != dump_info.Get_reaction().end(); it++)
			{
				cxxReaction *p = Utilities::Rxn_find(Rxn_reaction_map, *it);

				if (p != NULL && p->Get_n_user() >= 0)
				{
					p->dump_raw(os, 0);
				}
			}
		}
	}

	// temperature
	if (dump_info.Get_bool_temperature())
	{
		if (dump_info.Get_temperature().size() == 0)
		{
			Utilities::Rxn_dump_raw(Rxn_temperature_map, os, 0);
		}
		else
		{
			std::set < int >::iterator it;
			for (it = dump_info.Get_temperature().begin(); it != dump_info.Get_temperature().end(); it++)
			{
				cxxTemperature *p = Utilities::Rxn_find(Rxn_temperature_map, *it);

				if (p != NULL && p->Get_n_user() >= 0)
				{
					p->dump_raw(os, 0);
				}
			}
		}
	}
	// pressure
	if (dump_info.Get_bool_pressure())
	{
		if (dump_info.Get_pressure().size() == 0)
		{
			Utilities::Rxn_dump_raw(Rxn_pressure_map, os, 0);
		}
		else
		{
			std::set < int >::iterator it;
			for (it = dump_info.Get_pressure().begin(); it != dump_info.Get_pressure().end(); it++)
			{
				cxxPressure *p = Utilities::Rxn_find(Rxn_pressure_map, *it);

				if (p != NULL && p->Get_n_user() >= 0)
				{
					p->dump_raw(os, 0);
				}
			}
		}
	}
	// Turn off any reaction calculation
	os << "USE mix none" << "\n";
	os << "USE reaction none" << "\n";
	os << "USE reaction_temperature none" << "\n";
	os << "USE reaction_pressure none" << "\n";

	// Turn off dump until next read
	dump_info.SetAll(false);
}
#if defined MULTICHART
/* ---------------------------------------------------------------------- */
int Phreeqc::
read_user_graph_handler(void)
/* ---------------------------------------------------------------------- */
{
/*
 *      Reads USER_GRAPH_DATA_BLOCK data block
 *
 *      Arguments:
 *         none
 *
 *      Returns:
 *         KEYWORD if keyword encountered, input_error may be incremented if
 *                    a keyword is encountered in an unexpected position
 *         EOF     if eof encountered while reading mass balance concentrations
 *         ERROR   if error occurred reading data
 *
 */
	int return_value;

	/*
	 *  Make parser
	 */
	std::istringstream iss_in;
	return_value = streamify_to_next_keyword(iss_in);
	CParser parser(iss_in, phrq_io);

	//For testing, need to read line to get started
	std::vector < std::string > vopts;
	std::istream::pos_type next_char;

	if (pr.echo_input == FALSE)
	{
		parser.set_echo_file(CParser::EO_NONE);
	}
	else
	{
		parser.set_echo_file(CParser::EO_NOKEYWORDS);
	}

	assert(!reading_database());

	bool success = chart_handler.Read(this, parser);

	// Need to output the next keyword
	if (return_value == OPTION_KEYWORD) echo_msg(sformatf( "\t%s\n", line));
	return (return_value);
}
#endif
