/* 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 */
/*ParseCompile compile werner or kurucz model atmospheres into cloudy format, originallly by K Volk,
 * also compile opacity and grains  */
#include "cddefines.h"
#include "continuum.h"
#include "atmdat.h"
#include "dense.h"
#include "iso.h"
#include "helike.h"
#include "helike_recom.h"
#include "grains.h"
#include "rfield.h"
#include "stars.h"
#include "parse.h"

void ParseCompile(char *chCard )
{
	int lgEOL ;
	long int i , ncell;
	char chRead[FILENAME_PATH_LENGTH_2],
	  chRFI[FILENAME_PATH_LENGTH_2],
	  chSZD[FILENAME_PATH_LENGTH_2],
	  *ptr;


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

	/* >>chng 01 aug 24, remove compile opacity command */
#	if 0
	/* this option to compile opacities into file for later use */
	if( lgMatch("OPAC",chCard) )
	{
		/* calls fill to set up continuum energy mesh if first call, 
		 * otherwise reset to original mesh */
		ContCreateMesh();

		/* read in some external data files, but only if this is first call */
		atmdat_readin();

		/* first generate the frequency array */
		ContCreatePointers();

		/* say that we want to compile the opacities */
		opac.lgCompileOpac = TRUE;

		/* generate inital set of opacities ut only if this is the first call 
		 * in this coreload */
		OpacityCreateAll();

		fprintf(ioQQQ, 
			"Success!!  Created file opacity.opc\nMake sure this is on the path.\n" );
		puts( "[Stop in ParseCompile]" );
		cdEXIT(EXIT_SUCCESS);
	}
#	endif

	/* >>chng 00 apr 27, modified for arbitrary file names by PvH
	 *
	 * this option to compile grains into file for later use
	 *
	 * the command supports the following syntax:
	 *
	 * COMPILE GRAINS
	 *     compile a standard set of opacity files
	 *
	 * COMPILE GRAINS <refr-ind-file> <size-distr-file> [ <no-bins> ]
	 *     compile a single opacity file
	 *
	 * Remarks:
	 * - the parameters of this command can be supplied in arbitrary order.
	 * - the file names can either be supplied as names between quotes or
	 *   as keywords; it is allowed to use a filename between quotes for
	 *   one file and a keyword for the other file; both names have to be
	 *   present in either form, there are no defaults.
	 * - filenames are recognized by their extension: .rfi for refractive
	 *   index files, and .szd for size distribution files, this allows
	 *   their sequence to be arbitrary.
	 * - the number-of-bins parameter is optional, it is defaulted to 10.
	 *
	 * NB NB NB NB NB NB NB NB NB NB NB NB NB
	 *
	 * - in order not to upset FFmtRead for reading the number-of-bins
	 *   parameter, all file names and keywords should be read first and
	 *   erased after being read ! to assure that all digits are erased,
	 *   the keywords 0M010, 0M100 and 1M000 are matched on all 5 characters.
	 *   if keywords are known not to contain digits or minus signs, erasing
	 *   is not necessary of course....
	 */
	if( lgMatch("GRAI",chCard) )
	{

		/* calls fill to set up continuum energy mesh if first call, 
		 * otherwise reset to original mesh */
		ContCreateMesh();

		/* read in some external data files, but only if this is first call */
		atmdat_readin();

		/* first generate the frequency array */
		ContCreatePointers();

		chRFI[0] = '\0';
		chSZD[0] = '\0';

		/* get first filename (either .rfi or .szd file) */
		if( strchr( chCard,'\"' ) != NULL )
		{
			GetQuote(chRead,chCard, TRUE );
			if( strstr(chRead,".rfi") != NULL || strstr(chRead,".mix") != NULL ) 
			{
				strcpy(chRFI,chRead);
			}
			else if( strstr(chRead,".szd") != NULL ) 
			{
				strcpy(chSZD,chRead);
			}
			else 
			{
				fprintf( ioQQQ, " filename %s has unknown extension, sorry\n" , chRead );
				puts( "[Stop in ParseCompile]" );
				cdEXIT(EXIT_FAILURE);
			}
		}

		/* get second filename (either .rfi or .szd file) */
		if( strchr( chCard,'\"' ) != NULL )
		{
			GetQuote(chRead,chCard, TRUE );
			if( strstr(chRead,".rfi") != NULL || strstr(chRead,".mix") != NULL ) 
			{
				strcpy(chRFI,chRead);
			}
			else if( strstr(chRead,".szd") != NULL ) 
			{
				strcpy(chSZD,chRead);
			}
			else 
			{
				fprintf( ioQQQ, " filename %s has unknown extension, sorry\n" , chRead );
				puts( "[Stop in ParseCompile]" );
				cdEXIT(EXIT_FAILURE);
			}
		}

		/* if no .rfi file was supplied between quotes, check for keywords */
		if( chRFI[0] == '\0' ) 
		{
			/* check on index of refraction names */
			if( (ptr = strstr(chCard,"AC1-")) != NULL )
			{
				/* amorphous carbon from Rouleau & Martin 1991 */
				strcpy(chRFI , "ac1-amcarb.rfi" );
				/* erase this keyword, it upsets FFmtRead */
				strncpy(ptr,"    ",4);
			}
			else if( (ptr = strstr(chCard,"BE1-")) != NULL )
			{
				/* amorphous carbon from Rouleau & Martin 1991 */
				strcpy(chRFI , "be1-amcarb.rfi" );
				/* erase this keyword, it upsets FFmtRead */
				strncpy(ptr,"    ",4);
			}
			else if( lgMatch( "GRAP" , chCard ) )
			{
				/* graphite */
				strcpy(chRFI , "graphite.rfi" );
			}
			else if( lgMatch( "SILI" , chCard ) )
			{
				/* astronomical silicate */
				strcpy(chRFI , "silicate.rfi" );
			}
			else if( lgMatch( " PAH" , chCard ) )
			{
				/* astronomical silicate */
				strcpy(chRFI , "pah1.rfi" );
			}
			else if( lgMatch( "GREY" , chCard ) || lgMatch( "GRAY" , chCard ))
			{
				strcpy(chRFI , "grey.rfi" );
			}
		}

		/* if no .szd file was supplied between quotes, check for keywords */
		if( chSZD[0] == '\0' ) 
		{
			/* check on size distribution */
			if( (ptr = strstr(chCard,"0M010")) != NULL )
			{
				strcpy(chSZD , "0m010.szd" );
				/* erase this keyword, it upsets FFmtRead */
				strncpy(ptr,"     ",5);
			}
			else if( (ptr = strstr(chCard,"0M100")) != NULL )
			{
				strcpy(chSZD , "0m100.szd" );
				/* erase this keyword, it upsets FFmtRead */
				strncpy(ptr,"     ",5);
			}
			else if( (ptr = strstr(chCard,"1M000")) != NULL )
			{
				strcpy(chSZD , "1m000.szd" );
				/* erase this keyword, it upsets FFmtRead */
				strncpy(ptr,"     ",5);
			}
			else if( lgMatch( "ORIO" , chCard ) )
			{
				strcpy(chSZD , "orion.szd" );
			}
			else if( lgMatch( " ISM" , chCard ) )
			{
				strcpy(chSZD , "ism.szd" );
			}
			else if( (ptr = strstr(chCard,"BT94")) != NULL )
			{
				/* Bakes & Tielens 1994 size distribution */
				strcpy(chSZD , "bt94.szd" );
				strncpy(ptr,"    ",4);
			}
			else if( (ptr = strstr(chCard,"0N341")) != NULL )
			{
				/* small pah, 15 C atoms */
				strcpy(chSZD , "0n341.szd" );
				strncpy(ptr,"     ",5);
			}
			else if( (ptr = strstr(chCard,"0N682")) != NULL )
			{
				/* large pah, 120 c atoms */
				strcpy(chSZD , "0n682.szd" );
				strncpy(ptr,"     ",5);
			}
		}

		/* the user has to supply either both the .rfi and .szd files, or neither
		 * (to compile the complete standard set of files); anything else is illegal */
		if( chRFI[0] == '\0' && chSZD[0] != '\0' )
		{
			fprintf(ioQQQ,"Sorry, but I did not recognize a refractive index file.\n");
			fprintf(ioQQQ,"Supply a file name between quotes or one of the following ");
			fprintf(ioQQQ,"keywords: ac1-amcarb, be1-amcarb, graphite, silicate, grey, pah\n");
			cdEXIT(EXIT_FAILURE);
		}

		if( chSZD[0] == '\0' && chRFI[0] != '\0' )
		{
			fprintf(ioQQQ,"Sorry, but I did not recognize a size distribution file.\n");
			fprintf(ioQQQ,"Supply a file name between quotes or one of the following ");
			fprintf(ioQQQ,"keywords: 0m010, 0m100, 1m000, ism, orion, on341, 0n682, bt94\n");
			cdEXIT(EXIT_FAILURE);
		}

		/* compile the complete standard set of files */
		if( chRFI[0] == '\0' && chSZD[0] == '\0' )
		{
			/* ism graphite, single bin */
			mie_write_opc( "graphite.rfi" , "ism.szd" , 1 );

			/* ism silicate, single bin */
			mie_write_opc( "silicate.rfi" , "ism.szd" , 1 );

			/* ism graphite, 10 bins */
			mie_write_opc( "graphite.rfi" , "ism.szd" , 10 );

			/* ism silicate, 10 bins */
			mie_write_opc( "silicate.rfi" , "ism.szd" , 10 );

			/* orion graphite, single bin */
			mie_write_opc( "graphite.rfi" , "orion.szd" , 1 );

			/* orion silicate, single bin */
			mie_write_opc( "silicate.rfi" , "orion.szd" , 1 );

			/* orion graphite, 10 bins */
			mie_write_opc( "graphite.rfi" , "orion.szd" , 10 );

			/* orion silicate, 10 bins */
			mie_write_opc( "silicate.rfi" , "orion.szd" , 10 );

			/* 0.01 micron silicate */
			mie_write_opc( "silicate.rfi" , "0m010.szd" , 1 );

			/* 0.1 micron silicate */
			mie_write_opc( "silicate.rfi" , "0m100.szd" , 1 );

			/* 1 micron silicate */
			mie_write_opc( "silicate.rfi" , "1m000.szd" , 1 );

			/* 0.01 micron graphite */
			mie_write_opc( "graphite.rfi" , "0m010.szd" , 1 );

			/* 0.1 micron graphite */
			mie_write_opc( "graphite.rfi" , "0m100.szd" , 1 );

			/* 1 micron graphite */
			mie_write_opc( "graphite.rfi" , "1m000.szd" , 1 );

			/* grey single bin */
			mie_write_opc( "grey.rfi" , "ism.szd" , 1 );

			/* grey resolved distribution */
			mie_write_opc( "grey.rfi" , "ism.szd" , 10 );

			/* small pah */
			mie_write_opc( "pah1.rfi" , "0n341.szd" , 1 );

			/* large pah */
			mie_write_opc( "pah1.rfi" , "0n682.szd" , 1 );

			/* distibuted pah */
			mie_write_opc( "pah1.rfi" , "bt94.szd" , 10 );

			/* single pah */
			mie_write_opc( "pah1.rfi" , "bt94.szd" , 1 );
		}
		/* this option is to compile a single type of grain */
		else
		{
			i = 5;
			ncell = (long)FFmtRead(chCard,&i,INPUT_LINE_LENGTH,&lgEOL);
			if( lgEOL )
			{
				/* the default, 10 cells */
				ncell = 10;
			}
			if( ncell <= 0 )
			{
				fprintf(ioQQQ,"Number of bins must be positive.  Sorry.\n");
				cdEXIT(EXIT_FAILURE);
			}
			/* this actually does the work */
			mie_write_opc( chRFI , chSZD , ncell );
		}

		fprintf(ioQQQ, 
			"Success!!  Created grain opacity file(s).\nMake sure this directory is on the path.\n" );
		puts( "[Stop in ParseCompile]" );
		cdEXIT(EXIT_SUCCESS);
	}

	else if( lgMatch("HE-L",chCard) )
	{
		int nelem;
		/* compile he-like command - compiles table of recombination coeficients */
		helike.lgCompileRecomb = TRUE;

		/* we will want to create the rec coef for a large number of levels, then stop.
		 * this sets the number of levels to a large number.  macro is in helike.h */
		for( nelem = ipHELIUM; nelem < LIMELM; nelem++)
		{
			dense.lgElmtOn[nelem] = TRUE;
			iso.nTopOff[ipHE_LIKE][nelem] = 0;
			iso.nCollapsed_max[ipHE_LIKE][nelem] = 0;

			if( nelem == ipHELIUM )
			{
				iso.numLevels_max[ipHE_LIKE][nelem] = ( ( 1 + HE_RREC_MAXN ) * HE_RREC_MAXN + 1 );
				iso.n_HighestResolved_max[ipHE_LIKE][nelem] = HE_RREC_MAXN;
			}
			else
			{
				iso.numLevels_max[ipHE_LIKE][nelem] = ( ( 1 + HE_LIKE_RREC_MAXN ) * HE_LIKE_RREC_MAXN + 1 );
				iso.n_HighestResolved_max[ipHE_LIKE][nelem] = HE_LIKE_RREC_MAXN;
			}
		}
	}

	else if( lgMatch("GAUN",chCard) )
	{
		/* compile guant command - compiles table of free free gaunt factors */
		rfield.lgCompileGauntFF = TRUE;
	}

	else if( lgMatch("STAR",chCard) )
	{
		/* this subroutine is intended to convert a sequential version of the klaus 
		 * werner or kurucz model values (assumed to come with the program) into a 
		 * direct access version for faster access.  the original file is assumed to 
		 * be named in *.ASC, and the new direct access file is assumed to be named
		 * in *.MOD.  if either cannot be openned the subroutine exits. */

		/* possible we only want to copy over the Rauch atmospheres */
		if( lgMatch("RAUC",chCard) && lgMatch("INIT",chCard) )
		{
			if( lgMatch(" OLD",chCard)  )
			{
				/* this is the original set */
				RauchInitialize();
			}
			else
			{
				/* this is the new set */
				RauchInitialize02();
			}
			/* both of above will exit so can't get down to here, but some compilers don't know that 
			puts( "[Stop in ParseCompile]" );
			cdEXIT(EXIT_SUCCESS);*/
		}

		/* calls fill to set up continuum energy mesh if first call, 
		 * otherwise reset to original mesh */
		ContCreateMesh();

		/* read in some external data files, but only if this is first call */
		atmdat_readin();

		/* first generate the frequency array */
		ContCreatePointers();

		/* check for "only" keyword, which means only do one of the group */
		if( lgMatch("ONLY",chCard) )
		{

			/* only do one of the stars, which one?*/
			if( lgMatch("WERN",chCard) )
			{
				/* do Werner hot stars */
				WernerCompile();

				fprintf( ioQQQ, "\n The compilation was successful!\n" );
				fprintf( ioQQQ, " The portable file  werner.ascii is no longer needed and may be deleted to save space.\n" );
				fprintf( ioQQQ, "\n Good Luck!!\n\n\n" );
			}
			else if( lgMatch("RAUC",chCard) )
			{
				int lgFlag;
				/* do the Rauch hot stars */
				if( lgMatch(" OLD",chCard) )
				{
					lgFlag = RauchCompile();
				}
				else
				{
					lgFlag = RauchCompile02();
				}
				if( lgFlag )
				{
					fprintf( ioQQQ, "\n Something bad happened during the Rauch compile.\n" );
				}
				else
				{
					fprintf( ioQQQ, "\n The compilation was successful!\n" );
					fprintf( ioQQQ, " The portable ascii files are no longer needed and may be deleted to save space.\n" );
					fprintf( ioQQQ, "\n Good Luck!!\n\n\n" );
				}
			}
			else if( lgMatch("COST",chCard) )
			{
				/* do the costar OB stars */
				CoStarCompile();

				fprintf( ioQQQ, "\n The compilation was successful!\n" );
				fprintf( ioQQQ, " The portable ascii files are no longer needed and may be deleted to save space.\n" );
				fprintf( ioQQQ, "\n Good Luck!!\n\n\n" );
			}
			else if( lgMatch("ATLA",chCard) )
			{
				/* do all work with Atlas */
				AtlasCompile();

				fprintf( ioQQQ, "\n The compilation was successful!\n" );
				fprintf( ioQQQ, " The portable files kurucz.ascii and kurucz.list are no longer needed and may be deleted to save space.\n" );
				fprintf( ioQQQ, "\n Good Luck!!\n\n\n" );
			}
		}

		else
		{
			int lgProblems = 0;

			/* no only, so do all three at one time*/

			/* do the costar OB stars - do first since fast */
			CoStarCompile();

			/* do werner hot stars  */
			WernerCompile();

			/* do the rauch hot stars - use new by default */
			lgProblems = RauchCompile02();

			/* do all work with atlas */
			AtlasCompile();

			if( lgProblems )
			{
				fprintf( ioQQQ, " \n Problems occurred during the compilation - check output.\n" );
			}
			else
			{
				fprintf( ioQQQ, " \n The compilation was successful!\n" );
				fprintf( ioQQQ, 
					" The portable files kurucz.ascii, kurucz.list, rauch_solar.ascii, rauch_halo.ascii, costar.ascii ,and werner.ascii\n" );
				fprintf( ioQQQ, 
					" are no longer needed and may be deleted to save space.\n" );
				fprintf( ioQQQ, "\n Good Luck!!\n\n\n" );
			}

		}

		puts( "[Stop in ParseCompile]" );
		cdEXIT(EXIT_SUCCESS);
	}
	else
	{
		fprintf( ioQQQ, " One of the keywords, Opacity or Stars,must appear.\n" );
		fprintf( ioQQQ, " Sorry.\n" );
		puts( "[Stop in ParseCompile]" );
		cdEXIT(EXIT_FAILURE);
	}
	/* all of the above exited - can't fall to here */
}

