#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
/*
A few changes have been made, including:
1) Memory is freed, rather than lying on the OS
2) Memory is no longer repeatdly allocated, which meant excessive use 
of system memory.
*/
#include <stdio.h>
#ifdef HAVE_STDLIB_H

#endif
#include <malloc.h>
#include <math.h>
#include <string.h>
#include <sys/types.h>
#include "yagi.h"

double Zo=Z0; /* Z0 is defined in yagi.h */

extern int optind, opterr;
extern char *optarg;
double min_offset_from_peak, angular_stepsize_2; /* not needed */

double pin, design_f, normalised_f, f;
double gain_E_plane, gain_H_plane, peak_gain;
struct element_data *coordinates;
struct FCOMPLEX *current;
int elements;
double rrange_min=RRANGE_MIN;
double rrange_max=RRANGE_MAX;


int main(int argc, char **argv)
{
	FILE *ifp, *ofp, *gain_fp;
	FILE *gnuplot_filename_fp; 
	FILE *gnuplot_log_command_filename_fp;
	FILE *gnuplot_lin_command_filename_fp;
	char *input_filename, *output_filename, *temp; 
	char *gnuplot_log_command_filename;
	char *gnuplot_lin_command_filename;
	char *gain_filename; 
	char *gnuplot_filename; 
	char *original_filename;
	double min_f, max_f, step_f, vswr, angular_step,theta;
	double magnitude, phase,max_SL,E_max=E_MAX, H_max=H_MAX;
	struct FCOMPLEX *voltage, input_impedance;
	double fb_ratio,gain_E_plane_back;
	double gain_H_plane_back;
	struct flags flag;
	struct pattern pattern_shape;
	int  c, step=0;
	input_filename=string(0L, 100L);
	gnuplot_filename=string(0L, 400L);
	gnuplot_log_command_filename=string(0L, 400L);
	gnuplot_lin_command_filename=string(0L, 400L);
	output_filename=string(0L, 100L);
	original_filename=string(0L, 100L);
	gain_filename=string(0L, 100L);
	memset((char *) &flag, 0, sizeof(flag));
   while ((c =  getoptions(argc,argv,"cehpsr:E:H:R:Z:")) != -1)
   switch       (c) 
   {   	case 'c':
	      flag.cflg=1;
	      break;
	case 'p':  /* Print data for gnuplot_log */
		flag.pflg=1;
	      break;
	case 'e':  /* suppress E- plane 3dB BW */
		flag.eflg=1;
	      break;
	case 'h':  /* suppress H- plane 3dB BW */
	flag.hflg=1;
	      break;
	 case 'r':  /* suppress H- plane 3dB BW */
		rrange_min=atof(optarg);
	      break;
	 case 'R':  /* suppress H- plane 3dB BW */
	rrange_max=atof(optarg);
	      break;
	 case 's':   /* suppress diagnostics */
		flag.sflg=1;
	      break;
          case 'E':             /* Max angle in E plane to look for -3dB */
			      E_max=atof(optarg);
               break;
          case 'H':
               H_max=atof(optarg); /* max angle in H plane to look for -3dB */
               break;
          case 'Z':        /* Zo */
               Zo=atof(optarg);
               break;
			 case '?':   /* default */
					flag.errflg=1;
					break;
	}
	if((argc-optind != 1) || flag.errflg)
	{
		usage_output(argv[0]);
		exit(0);
	}
	/* The file read by 'output' is expected to have a .out extension.
	'output' creates files with extensions:
	.dat     Containing the basic broperties of impedance, gain etc as a function
		 of frequency.
	.gai     Contains field patterns (gain) in the both H and E plane.
	
	We here get all the file names, then open files. */
	strcpy(input_filename, argv[optind]);
	strcpy(original_filename, argv[optind]);
	strcpy(output_filename, *(argv+optind));
	strcpy(gain_filename, *(argv+optind));
       
	strcat(input_filename,".out");
	strcat(output_filename,".dat");
	strcat(gain_filename,".gai");
	ifp=fopen(input_filename,"rb");
	ofp=fopen(output_filename,"wb");
	gain_fp=fopen(gain_filename,"wt");
	if(ifp == NULL)
	{
		fprintf(stderr,"Cant open %s\n", input_filename);
		exit(10);
	}

	temp=string(0L,100L);
	/* No longer need to refer to files by names, we just use the 
	file pointers, so free memory associated with names. */
	free_string(output_filename,0L,100L);
	free_string(gain_filename,0L,100L);
	/* Read the header on the .out file, which is usually 100 Bytes,
	but can be defined in yagi.h as HEADER_SIZE */
	elements=read_header(ifp, ofp, &min_f, &max_f, &step_f, &design_f, &angular_step);
	/* Creatre an array of structures, so contain the x and y locations of 
	each element, and the lengths of the elements. All dimensions are in m */
	coordinates=element_data_vector(1,elements); /* x,y &l of centre of ele's */
	/* read into memory the x,y, and lengths of all elements */
	fread((char *) &coordinates[1], sizeof(struct element_data),elements,ifp);
	/* Create arrays to hold real and imaginary components of voltage */
	voltage=FCOMPLEXvector(1,elements);
	current=FCOMPLEXvector(1,elements);
	/* read voltages applied to elements into memory */
	fread((char *) &voltage[1], sizeof(struct FCOMPLEX),elements, ifp);
	/* Now print a one line header to put into .dat file */
	fprintf(ofp,"  f(MHz) E(deg) H(deg)  R     jX    VSWR   Gain(dBi)     FB(dB)    SideLobes(dB)\n\n");
	if(flag.pflg==1)
	{
		if(angular_step > 10)
		{
			fprintf(stderr,"The angular step site is set at less that 10 degress. Edit the file %s, change the ANGULAR_STEP to 10 degrees or less, then rerun 'yagi %s' and 'output -p %s'\n", original_filename, original_filename, original_filename);
			exit(12);

		}
		sprintf(gnuplot_log_command_filename,"%s.glog",original_filename);
		sprintf(gnuplot_lin_command_filename,"%s.glin",original_filename);
		gnuplot_log_command_filename_fp=fopen(gnuplot_log_command_filename,"w");
		gnuplot_lin_command_filename_fp=fopen(gnuplot_lin_command_filename,"w");
		write_gnuplot_header(gnuplot_log_command_filename_fp,f,original_filename,step,LOG);
		write_gnuplot_header(gnuplot_lin_command_filename_fp,f,original_filename,step,LIN);
	}
	/* compute data at every frequency of interest */
	for(f=min_f; f<=max_f; f+=step_f)
	{
		normalised_f=f/design_f;
		fread((char *) &current[1], sizeof(struct FCOMPLEX),elements, ifp);
		z_input(voltage[1], current[1], &input_impedance);
		/* Compute magnitude and phase of reflection coefficient */
		reflection_coefficient(input_impedance, &magnitude, &phase);
		/* Compute VSWR from magnitude of reflection coefficient */
		vswr=calculate_vswr(magnitude);
		/* Calculate power input to antenna */
		pin=calculate_power_input(input_impedance.r,current[1]); /* in Watts */
		if(pin < 0.0)
		{
			fprintf(stderr,"input power less than 0! Probably due to self or mutual impedance being inaccurate when current not sinusidal\n");
			fprintf(stderr,"f=%f MHz Zin=%f +i%f\n",f/1e6, input_impedance.r, input_impedance.i);
		}
		/* compute gain at theta=90, phi=0 (forward direction) */
		gain(90, 0, pin, normalised_f, coordinates, current, elements, &gain_E_plane, &gain_H_plane, f, design_f );
		/* compute gain at theta -90 degrees (ie back - direction) */
		gain(270, 0, pin, normalised_f, coordinates, current, elements, &gain_E_plane_back, &gain_H_plane_back, f, design_f); 
		fb_ratio=gain_E_plane-gain_E_plane_back;  /* in dB, so subtract */
		/* If the values of impedance are too large, the cant be printed in
		the .dat file. Hence we truncate them. At this point, the numbers
		are so large, that we are not likely to be able to use them anyway. */
		if(input_impedance.r > 9999999)
			input_impedance.r = 9999999;
		if(input_impedance.i > 9999999)
			input_impedance.i = 9999999;
		if(input_impedance.r < -9999999)
			input_impedance.r = -9999999;
		if(input_impedance.i < -9999999)
			input_impedance.i = -9999999;
	
	   /* Find the most importent bits of the pattern info */

		/* Estimiate 3dB bandwidth using .See '-E' and '-H' options */
		peak_gain=gain_E_plane;
		if(flag.hflg || elements==1)
			pattern_shape.three_dB_H=0.0;  
		else
	      pattern_shape.three_dB_H=(double) zbrent(error_3dB_H, 0.0,H_max,0.1);  
		if(flag.eflg)
			pattern_shape.three_dB_E=0.0;  
		else
		 	pattern_shape.three_dB_E=(double) zbrent(error_3dB_E, 90.0,E_max,0.1); 
		if(flag.cflg==1)
		{
			max_SL=find_max_sidelobe_slow(peak_gain, pin,coordinates,current,elements,f,design_f); 
		}
		else
			max_SL=0.0;
		fprintf(ofp,"%9.3f %3.1f  %3.1f %6.2f %6.2f %6.3f %10.3f %10.3f %10.3f\n",f/1e6,2*(pattern_shape.three_dB_E-90), 2*pattern_shape.three_dB_H,input_impedance.r, input_impedance.i, vswr, peak_gain, fb_ratio,max_SL);
		write_gain_at_various_angles(gain_fp, angular_step, pin, normalised_f, f, coordinates, current, elements, design_f); 
		if((min_f < max_f) && !flag.sflg)
			printf("%s completed  %5.1f%%\n",argv[0],100*(f-min_f)/(max_f-min_f));
		if(flag.pflg == 1) /* Plot results in files suitable for gnuplot */
		{
			step++;
			sprintf(gnuplot_filename,"%s.%.4f.g",original_filename,f/1e6);
			gnuplot_filename_fp=fopen(gnuplot_filename,"w");

			for(theta=0;theta<360;theta+=angular_step)
			{
		        	gain(theta+90.0, 0, pin, normalised_f, coordinates, current, elements, &gain_E_plane, &gain_H_plane, f, design_f );
				if(gain_E_plane < rrange_min)
				    gain_E_plane= rrange_min;
				if(gain_H_plane < rrange_min)
				    gain_H_plane= rrange_min;
				fprintf(gnuplot_filename_fp,"%11.3f %11.3f %11.3f %8.3f %11.3f %11.3f %11.3f %11.3f %11.3f\n",theta,gain_E_plane,gain_H_plane,vswr,pow(10.0,gain_E_plane/10.0),pow(10.0,gain_H_plane/10.0),0.0,0.0,0.0);
				/*
				if(theta<=90)
					zz=-40.0;
				else if (theta > 90 && theta <= 180)
					zz=-20.0;
				else if (theta > 180 && theta <= 270)
					zz=0.0;
				else
					zz=10.0;
				fprintf(gnuplot_log_filename_fp,"%11.3f %11.3f %11.3f %8.3f %11.3f %11.3f\n",theta,zz,gain_H_plane,vswr,0.0,0.0,0.0);
				*/
			}
			fprintf(gnuplot_log_command_filename_fp,"plot '%s' using 1:2\n",gnuplot_filename);
			fprintf(gnuplot_lin_command_filename_fp,"plot '%s' using 1:5\n",gnuplot_filename);
			fprintf(gnuplot_lin_command_filename_fp,"pause -1 \"Hit RETURN to see pattern at %.4f MHz on a linear scale\"\n",f);
			fprintf(gnuplot_log_command_filename_fp,"pause -1 \"Hit RETURN to see pattern at %.4f MHz on a log scale\"\n",f);
		}
	}
	if(flag.pflg==1)
	{
		fclose(gnuplot_filename_fp);
		fclose(gnuplot_log_command_filename_fp);
		fclose(gnuplot_lin_command_filename_fp);
	}
	output_filename=string(0L, 100L);
	original_filename=string(0L, 100L);
	gain_filename=string(0L, 100L);
	/* free strings not already freed */
	free_string(input_filename,0L,100L);
	free_string(temp,0L,100L);
	free_string(gnuplot_filename,0L, 400L);
	free_string(gnuplot_log_command_filename,0L, 400L);
	free_string(gnuplot_lin_command_filename,0L, 400L);
        free_string(output_filename, 0L, 100L);
	free_string(original_filename, 0L,100L); 
	free_string(gain_filename, 0L, 100L);
	/* free vectors */
	free_FCOMPLEXvector(voltage,1L,(long) elements);
	free_FCOMPLEXvector(current,1L,(long) elements);

	fclose(ifp); 
	fclose(gain_fp);
	exit(0);
}



double error_3dB_E(double x)
{
		double ans;

		gain(x, 0, pin, normalised_f, coordinates, current, elements, &gain_E_plane, &gain_H_plane, f, design_f );
		ans=peak_gain-gain_E_plane-3.01;
		return(ans);
}

double error_3dB_H(double x)
{
		double ans;

		gain(0, x, pin, normalised_f, coordinates, current, elements, &gain_E_plane, &gain_H_plane, f, design_f );
		ans=peak_gain-gain_H_plane-3.01;
		return(ans);
}
