/**********************************************************
      binned R and T receiver functions by given baz interval.
	    V1 (cpp version) By Meijian An & Mei Feng, 2024/07/03
	    V0 (bash version) By Mei Feng

***********************************************************/

#ifdef _OPENMP
#include <omp.h>
#endif

#include <cstdio>
#include <string>
#include <cmath>
#include "mystds.h"     //General functions
#include "Sac_head.h"

using namespace std;

struct Arguement
{
	string output_filename;
	double dBaz;
	double dT;
};

struct sacRF
{
	int npts;
	double b, dt;
	float *amp;
};


int get_argument(struct Arguement &argu, int argc, char**argv);

int main(int argc, char **argv)
{
	struct Arguement argu;
	get_argument(argu, argc, argv);

	// back azimuth bins
	int nbaz = 1;
	if(argu.dBaz > 0.0 && argu.dBaz <= 180)
		nbaz = (int)(360/argu.dBaz)+1;
	int *nbaz_bin = new int[nbaz];
	memset(nbaz_bin, 0, sizeof(int)*nbaz);

	// read RFs into memory
	int maxpt = 1000000;
	float  *RFTmp = new float [maxpt];
	struct SacHead sacHdr;

	struct sacRF * sacs = new struct sacRF[nbaz];
	memset(sacs, 0, sizeof(struct sacRF)*nbaz);
	for(int i=1; i<argc; i++)
	{
		if(argv[i][0] == '-') continue;

		FILE *fRF = openfile(argv[i], "rb");
		if(fRF == NULL) continue;

		//read sac head
		int npt = 0;
		int ibaz = 0;
		if(fread((char*)&sacHdr, 1, sizeof(sacHdr), fRF) == sizeof(sacHdr) && sacHdr.npts > 10)
		{
			if(sacHdr.baz < 0.0) sacHdr.baz += 360;
			ibaz  = (nbaz == 1 || sacHdr.baz < -360.0)?0:((int)(sacHdr.baz/argu.dBaz)) ;

			//read sac data
			npt= fread(RFTmp, sizeof(float), sacHdr.npts, fRF);
		}
		fclose(fRF);
		
		if (npt < 10)
			continue;

		if (nbaz_bin[ ibaz ] == 0)
		{
			sacs[ibaz].npts = (sacHdr.npts > maxpt) ? maxpt:sacHdr.npts;
			sacs[ibaz].dt   = sacHdr.delta;
			sacs[ibaz].b    = sacHdr.b;
			sacs[ibaz].amp = new float[sacs[ibaz].npts];
			memcpy(sacs[ibaz].amp, RFTmp, sizeof(float)*sacHdr.npts);
		}
		else
		{
			if (sacs[ibaz].npts != sacHdr.npts || sacs[ibaz].b != sacHdr.b || sacs[ibaz].dt != sacHdr.delta )
			{
				fprintf(stderr, "Warning: inconsistent npts, b or dt\n");
				if(sacs[ibaz].npts > sacHdr.npts || sacs[ibaz].dt != sacHdr.delta)
				{
					fprintf(stderr, "Warning: shorter RF than the previous one!\n");
					continue;
				}
			}
			for(int i=0;i<sacs[ibaz].npts; i++)
				sacs[ibaz].amp[i] += RFTmp[i];
		}
		nbaz_bin[ ibaz ]++;
	}
	int deci=int(argu.dT/sacHdr.delta+0.001);
	int npts=int(sacHdr.npts/deci);
	// fprintf(stderr, "%d\t%d\n", deci, npts);
	
	FILE* fRFbin = openfile(argu.output_filename.c_str(), "w");
	for(int ibaz=0; ibaz<nbaz; ibaz++)
	{
		if(sacs[ibaz].npts<10) continue;
		fprintf(fRFbin, "> %d %g %d %g %g %g %d\n", ibaz, argu.dBaz, npts, sacs[ibaz].b, argu.dT, ibaz*argu.dBaz, nbaz_bin[ibaz]);
		for(int i=0;i<sacs[ibaz].npts; i+=deci)
		{
			sacs[ibaz].amp[i] /= nbaz_bin[ ibaz ];
			fprintf(fRFbin, "%g\t%g\n", sacs[ibaz].b+i*sacs[ibaz].dt, sacs[ibaz].amp[i]);
		}
	}
	fclose(fRFbin);


	// free memory
	delete RFTmp; 

	for (int ibaz = 0; ibaz < nbaz; ibaz++)
	{
		if(sacs[ibaz].npts>0)
			delete sacs[ibaz].amp;
	}
	delete sacs;

	return 0;
}

int show_help(char* argv0 /*=argv[0]*/)
{
	printf("%s (Version 1.0) by Mei Feng, 2024/07/03\n\n", argv0);
	printf("Info:\n"
		"   binned R and T receiver functions by given baz interval.\n\n");
	printf("arguments:\n"
		"     -h:        Show this help information.\n"
		"     Receiver function files in sac format\n"
		"                Sac headers of Baz are necessary.\n"
		"     -o=[RFbin.out]:      Output file name for binned RF. Default is RFbin.out.\n"
		"  -dBaz=[5]     Width of Back-azimuth bins for RF normlization. Baz <=0 or >180, all RFs are equally stacked. Default bin is 5 degree.\n"
		"  -dT=[0.05]    sampling rate for the output binned RFs. Default is 0.05 s.\n"
		);

	return 1;
}

int get_argument(struct Arguement &argu, int argc, char**argv)
{
	if(get_switch("-h", false, argc, argv) == true || argc < 3)
	{
		show_help(argv[0]);
		exit(0);
	}

 	//Get All arguement values.
	argu.output_filename   = get_Parameter("-o=",        string("RFbin.out"), argc, argv);

	argu.dBaz = get_Parameter("-dBaz=", double(5.0), argc, argv);
	argu.dT = get_Parameter("-dT=", double(0.05), argc, argv);

	SHOWerr1("%s options are:\n", argv[0]);
	SHOWerr1("\t       dBaz = %g\n", argu.dBaz);
	SHOWerr1("\t       dT = %g\n", argu.dT);
	SHOWerr1("\t       output = %s\n", argu.output_filename.c_str());
	return 1;
}

