/* This file is part of Cloudy and is copyright (C)1978-2006 by Gary J. Ferland
 * For conditions of distribution and use see copyright notice in license.txt */
/*ParseGrain parse parameters on grains command */
#include "cddefines.h"
#include "grainvar.h"
#include "phycon.h"
#include "input.h"
#include "optimize.h"
#include "parse.h"
#include "grains.h"

void ParseGrain(char *chCard, 
		int *lgDSet)
{
	int lgC15 = FALSE,
	  lgC120 = FALSE,
	  lgEOL,
	  lgLinSet, 
	  lgLogLinSet, 
	  lgQuoteFound,
	  lgSizeDistribution;
	char *ptr;
	GrainPar gp;

	/*possible name of input file with opacities */
	char chFile[FILENAME_PATH_LENGTH_2];
	const char *chOption;
	long int i;

#	ifdef DEBUG_FUN
	fputs( "<+>ParseGrain()\n", debug_fp );
#	endif

	*lgDSet = TRUE;

	/* >>chng 00 dec 20, initialize chFile to empty string..., PvH */
	chFile[0] = '\0';
	chOption = "";
	/* >>chng 01 jan 17, read filename first, it may contain digits that would upset FFmtRead,
	 * as well as other tests that will follow. GetQuote will erase the filename from chCard, PvH */
	lgQuoteFound = strchr( input.chOrgCard,'\"' ) != NULL;
	if( lgQuoteFound )
	{
		/* this will both scan in whatever label is inside the quotes in OrgCard, 
		 * but also remove the contents there and in chCard,
		 * so that following keywords will not trigger off it */
		GetQuote( chFile , chCard , TRUE );
	}

	gp.lgGreyGrain = lgMatch("GREY",chCard) || lgMatch("GRAY",chCard) || lgMatch("grey_",chFile);
		
	/* now check for the keyword "function" - this is a special case,
	 * where grain abundance varies with depth 
	 * if set true then will call routine GrnVryDpth */
	gp.lgAbunVsDepth = lgMatch("FUNC",chCard);

	/* check for the keyword "single bin" - 
	 * use resolved grain size distributions if not present */
	lgSizeDistribution = ! lgMatch("SING",chCard);

	/* check for the keyword "qheating" - 
	 * quantum heating should be turned on */
	gp.lgForbidQHeating = FALSE;
	gp.lgRequestQHeating = lgMatch("QHEA",chCard);

	/* the keyword "no qheat" always takes precedence */
	if( lgMatch("O QH",chCard) ) 
	{
		gp.lgForbidQHeating = TRUE;
		gp.lgRequestQHeating = FALSE;
		phycon.lgPhysOK = FALSE;
	}
	
	/* option to force constant reevaluation of grain physics - 
	 * usually reevaluate grains at all times, but NO REEVALUATE will
	 * save some time but may affect stability */
	gv.lgReevaluate = !lgMatch(" NO REEV",chCard);

	/* option to turn off photoelectric heating by grain, NO HEATING */
	if( lgMatch("O HE",chCard) )
	{
		phycon.lgPhysOK = FALSE;
		gv.lgDHetOn = FALSE;
	}

	/* option to turn off gas cooling by grain, NO COOLING */
	if( lgMatch("O CO",chCard) )
	{
		phycon.lgPhysOK = FALSE;
		gv.lgDColOn = FALSE;
	}

	/* these are keywords for PAH's, they need to be read before the depletion factor */
	if( (ptr = strstr(chCard,"C120 ")) != NULL )
	{
		lgC120 = TRUE;
		/* erase this keyword, it upsets FFmtRead */
		strncpy(ptr,"     ",5);
	}
	else if( (ptr = strstr(chCard,"C15 ")) != NULL )
	{
		lgC15 = TRUE;
		/* erase this keyword, it upsets FFmtRead */
		strncpy(ptr,"    ",4);
	}

	/* log - linear option for grain abundance */
	lgLogLinSet = FALSE;
	lgLinSet = FALSE;
	if( lgMatch(" LOG",chCard) )
	{
		lgLogLinSet = TRUE;
		lgLinSet = FALSE;
	}
	else if( lgMatch("LINE",chCard) )
	{
		lgLogLinSet = TRUE;
		lgLinSet = TRUE;
	}

	/* get the grain abundance as the first parameter,
	 * returns 0 if no number, ok since interpreted as log, or unity*/
	i = 5;
	gp.dep = FFmtRead(chCard,&i,INPUT_LINE_LENGTH,&lgEOL);

	/* was keyword log or linear on the line? */
	if( lgLogLinSet )
	{
		/* log or linear was specified, which was it */
		if( lgLinSet )
		{
			/* linear quantity entered, check it */
			if( gp.dep <= 0. )
			{
				fprintf( ioQQQ, " Impossible value for linear abundance.\n" );
				fprintf( ioQQQ, " Abundance entered was%10.2e\n", gp.dep );
				fprintf( ioQQQ, " Sorry.\n" );
				puts( "[Stop in ParseGrain]" );
				cdEXIT(EXIT_FAILURE);
			}
		}
		else
		{
			gp.dep = pow(10.,gp.dep);
		}
	}
	else
	{
		/* neither log nor linear specified, check sign
		 * force it to be a log - linear if greater than 0 */
		if( gp.dep <= 0. )
		{
			gp.dep = pow(10.,gp.dep);
		}
	}

	if( gp.dep < FLT_MIN )
	{
		fprintf( ioQQQ, " Grain abundance entered here (%f) is impossible.\n", gp.dep );
		puts( "[Stop in ParseGrain]" );
		cdEXIT(EXIT_FAILURE);
	}

	/* it is possible that there is a file name on the command line - 
	 * if so then we want to call correct reoutine, and not look for keywords 
	 * the signature of a keyword is a pair of quotes - is one present? */
	if( lgQuoteFound )
	{
		/* read the file name that was specified */
		mie_read_opc(chFile,gp);
	}
	else
	{
		if( lgMatch("ORIO",chCard) )
		{
			/* This scales the Orion grain abundance so that the observed 
			 * dust to gas ratio that Cloudy predicts is in agreement with
			 * that observed in the Veil,
			 *>>refer	grain	Abel, N., Brogan, C., Ferland, G., O'Dell, C.R., 
			 *>>refercon	Shaw, G., Troland, T., 2004, ApJ, submitted */
			gp.dep *= 0.85;

			/* optional keyword ORION to use orion curves for large R grains */
			/* only turn on one if graphite or silicate is on line, both if not */
			if( lgMatch("GRAP",chCard) )
			{
				/* only turn on orion graphite */
				chOption = "ORION GRAPHITE ";
				if( lgSizeDistribution )
				{
					mie_read_opc("graphite_orion_10.opc",gp);
				}
				else
				{
					mie_read_opc("graphite_orion_01.opc",gp);
				}
			}
			else if( lgMatch("SILI",chCard) )
			{
				/* only turn on orion silicate */
				chOption = "ORION SILICATE ";
				if( lgSizeDistribution )
				{
					mie_read_opc("silicate_orion_10.opc",gp);
				}
				else
				{
					mie_read_opc("silicate_orion_01.opc",gp);
				}
			}
			else
			{
				/* turn both on */
				chOption = "ORION ";
				if( lgSizeDistribution )
				{
					mie_read_opc("graphite_orion_10.opc",gp);
					mie_read_opc("silicate_orion_10.opc",gp);
				}
				else
				{
					mie_read_opc("graphite_orion_01.opc",gp);
					mie_read_opc("silicate_orion_01.opc",gp);
				}
			}
		}

		else if( lgMatch(" PAH",chCard) )
		{
			/* only turn on the large PAH */
			if( lgC120 )
			{
				chOption = "PAH C120 ";
				mie_read_opc("pah1_0n682.opc",gp);
			}
			/* only turn on the small PAH */
			else if( lgC15 )
			{
				chOption = "PAH C15 ";
				mie_read_opc("pah1_0n341.opc",gp);
			}
			/* turn on size-distributed PAHs */
			else
			{
				chOption = "PAH ";
				if( lgSizeDistribution )
				{
					mie_read_opc("pah1_bt94_10.opc",gp);
				}
				else
				{
					mie_read_opc("pah1_bt94_01.opc",gp);
				}
			}
		}

		else if( lgMatch("GREY",chCard) || lgMatch("GRAY",chCard) )
		{
			/* grey grains */
			chOption = "GREY ";
			if( lgSizeDistribution )
			{
				mie_read_opc("grey_ism_10.opc",gp);
			}
			else
			{
				mie_read_opc("grey_ism_01.opc",gp);
			}
		}

		else if( lgMatch(" ISM",chCard) )
		{
			if( lgMatch("GRAP",chCard) )
			{
				/* only turn on ism graphite */
				chOption = "ISM GRAPHITE ";
				if( lgSizeDistribution )
				{
					mie_read_opc("graphite_ism_10.opc",gp);
				}
				else
				{
					mie_read_opc("graphite_ism_01.opc",gp);
				}
			}
			else if( lgMatch("SILI",chCard) )
			{
				/* only turn on orion silicate */
				chOption = "ISM SILICATE ";
				if( lgSizeDistribution )
				{
					mie_read_opc("silicate_ism_10.opc",gp);
				}
				else
				{
					mie_read_opc("silicate_ism_01.opc",gp);
				}
			}
			else
			{
				/* turn both ISM graphite and silicate on */
				chOption = "ISM ";
				if( lgSizeDistribution )
				{
					mie_read_opc("graphite_ism_10.opc",gp);
					mie_read_opc("silicate_ism_10.opc",gp);
				}
				else
				{
					mie_read_opc("graphite_ism_01.opc",gp);
					mie_read_opc("silicate_ism_01.opc",gp);
				}
			}
		}

		/* default case */
		else
		{
			/* turn both ISM graphite and silicate on */
			if( lgSizeDistribution )
			{
				mie_read_opc("graphite_ism_10.opc",gp);
				mie_read_opc("silicate_ism_10.opc",gp);
			}
			else
			{
				mie_read_opc("graphite_ism_01.opc",gp);
				mie_read_opc("silicate_ism_01.opc",gp);
			}
		}
	}

	/* vary option */
	if( optimize.lgVarOn )
	{
		char chHold[INPUT_LINE_LENGTH];
		size_t length;
		/*  pointer to where to write */
		optimize.nvfpnt[optimize.nparm] = input.nRead;
		optimize.vparm[0][optimize.nparm] = (float)log10(gp.dep);
		optimize.vincr[optimize.nparm] = 1.;

		/* these are varios options for density laws, 
		 * first is constant density or pressre*/
		strcpy( optimize.chVarFmt[optimize.nparm] , "GRAIN ABUND=%f LOG ");
		/* >>chng 00 dec 20, chFile may not be defined..., PvH */
		if( chFile[0] != '\0' )
		{
			sprintf(chHold , "\"%s\" ", chFile  );
			strcat( optimize.chVarFmt[optimize.nparm] , chHold );
		}
		/* find out how long chOption is - it was declared as a pointer, then
		 * set equal to a local string */
		length = strlen( chOption );
		if( length == 0 )
			TotalInsanity();

		/* make sure we have enough room to store the string */
		if( length > FILENAME_PATH_LENGTH_2 )
		{
			fprintf(ioQQQ," type of grain string length is too long.  This is parse_grain\n");
			TotalInsanity();
		}
		/* copy the streng into the format */
		strcat( optimize.chVarFmt[optimize.nparm] , chOption );

		if( gp.lgAbunVsDepth )
			strcat( optimize.chVarFmt[optimize.nparm] , "FUNCTION " );
		if( !lgSizeDistribution )
			strcat( optimize.chVarFmt[optimize.nparm] , "SINGLE " );
		if( gp.lgForbidQHeating )
			strcat( optimize.chVarFmt[optimize.nparm] , "NO QHEAT " );
		else if( gp.lgRequestQHeating )
			strcat( optimize.chVarFmt[optimize.nparm] , "QHEAT " );
		if( !gv.lgReevaluate )
			strcat( optimize.chVarFmt[optimize.nparm] , "NO REEVALUATE " );
		if( !gv.lgDHetOn )
			strcat( optimize.chVarFmt[optimize.nparm] , "NO HEATING " );
		if( !gv.lgDColOn )
			strcat( optimize.chVarFmt[optimize.nparm] , "NO COOLING " );

		optimize.nvarxt[optimize.nparm] = 1;
		++optimize.nparm;
	}

#	ifdef DEBUG_FUN
	fputs( " <->ParseGrain()\n", debug_fp );
#	endif
	return;
}

