/*
 * DspRisTgt.cpp
 *
 */

#include "dsp_ris_internals_.h"

#include "idd_avionic_types.h"

#include "gc_math.h"

#include <math.h>
#include <float.h>
#include <string.h>

static dsp_ris_tgt_db_t autoMonitorable_ristgt;

dsp_ris_tgt_db_t& dsp_ris_tgt_db=autoMonitorable_ristgt;

static void polar2XY(float& x, float &y, float az, float rng)
{
	x=rng*cosf(az);
	y=rng*sinf(az);
}

static void XY2polar(float& az, float& rng, float x, float y)
{
	az=atan2(y, x);
	rng=sqrtf(x*x+y*y);
}


const iddtypes::inu_data_t& DspRisTgtInuData()
{
	return dsp_ris_tgt_db.inu;
}

void DspRisTgtUpdate(const iddtypes::inu_data_t& inu, float delta_time)
{
	//s.tracksUpdateExt(delta_time, cmd.nav.inertial_altitude.data);
	float ac_altitude=inu.inertial_altitude.data;

	if (delta_time<0.005)
		delta_time=0.005;

	DspRigTgtMutexAcquire(true);

	float rv=sqrtf(inu.own_ship_velocity.vector.x*inu.own_ship_velocity.vector.x+inu.own_ship_velocity.vector.y*inu.own_ship_velocity.vector.y);
	dsp_ris_tgt_db.vxy=rv;

	dsp_ris_tgt_db.rbm_range-=(rv*delta_time);

	for(int i=0; i<DSP_RIS_MAX_TGT; ++i)
	{
		dsp_ris_tgt_t& t=dsp_ris_tgt_db.t[i];
		if (t.enabled==0)
			continue;
		if (t.enabled<0)
		{
			++t.enabled;
		}

		//t.range_delta=t.rng_meters;

		float az=t.az;
		float rng=t.ground_range; //t.rng_meters;

		float vx=0;
		float vy=0;
		float speed=t.speed; //*delta_time;

		if (t.turn_duration>0)
		{
			t.heading+=t.turn*delta_time;
			t.turn_duration-=delta_time;
		}

		t.heading=gc_math::angle_bound_pi(t.heading);

		polar2XY(vx, vy, t.heading, speed);

		float x=0;
		float y=0;
		polar2XY(x, y, az, rng);

		t.vx=vx; // /delta_time;
		t.vy=vy; // /delta_time;

		x+=(t.vx-inu.own_ship_velocity.vector.x)*delta_time; //x+=(vx-(cmd.nav.own_ship_velocity.vector.x*delta_time));
		y+=(t.vy-inu.own_ship_velocity.vector.y)*delta_time; //y+=(vy-(cmd.nav.own_ship_velocity.vector.y*delta_time));

		XY2polar(az, rng, x, y);

		t.rad_vel=0;

		if (rng>0)
		{
			float xn=x/rng;
			float yn=y/rng;

			float rv=(t.vx*xn)+(t.vy*yn);

			t.rad_vel=rv;
		}



		t.ground_range=rng;
		float delta_altitude=t.altitude-ac_altitude;
		rng=sqrtf(delta_altitude*delta_altitude+rng*rng);  //slant

		if (fabsf(rng)>FLT_EPSILON)
			t.el=asinf(delta_altitude/rng);
		else
			t.el=0;

		t.az=az;
		t.range_delta=(rng-t.slant_range);
		t.range_rate=t.range_delta/delta_time; //t.range_delta;
		t.slant_range=rng;
		//t.range=t.rng_meters;
		t.x=x;
		t.y=y;

		//if (t.range>risTrackOverrides.max_rng)
		//	t.enabled=0;
	}

	dsp_ris_tgt_db.inu=inu;
	DspRigTgtMutexRelease();
}

#include "DspLrpHeader.h"
#include "idd_dsp_results_types.h"


static float rs2m(iddtypes::range_scale_t rs)
{
	float rmax=10*1852;
	int ri=int(rs);
	if (ri<0)
		return rmax;
	if (ri>(int(iddtypes::_80NM)))
		return 80*1852;

	static const float cvt[]={1852*10, 1852*10, 1852*20, 1852*40, 1852*80};
	return cvt[ri];
}

float DspRisRanceScale2Meters(iddtypes::range_scale_t rs)
{
	return rs2m(rs);
}

#define SPEED_OF_LIGHT_MS (2.997925e+08F*10e-6f)
static const float STT_MR_DX=0.1639f;;
static const float STT_MR_DY=-0.1212f;

static void pos2mp(float& monopulse_ratio_az, float& monopulse_ratio_el, double tgt_body_az, double tgt_body_el, float au, float av, float processed_tx_chan_mhz)
{
    const float lambda=SPEED_OF_LIGHT_MS/processed_tx_chan_mhz;

    float t_v=sinf(-tgt_body_el); //float tgt_ant_el = -asinf(tgt_v);
    float t_u=sinf(-(tgt_body_az)*cosf(tgt_body_el)); //float tgt_ant_az = -asinf(tgt_u)/cosf(tgt_ant_el);

    float delta_v=t_v-av;
    float delta_u=t_u-au;

    float mp_angle=gc_math::angle_bound_pi((delta_u/lambda)*(GC_K_PI*STT_MR_DX));
    float mp_daz=tanf(mp_angle); //(delta_u/lambda)*(PI*STT_MR_DX));

    mp_angle=gc_math::angle_bound_pi((delta_v/lambda)*(GC_K_PI*STT_MR_DY));
    float mp_del=tanf(mp_angle);

    monopulse_ratio_az=mp_daz;
    monopulse_ratio_el=mp_del;
}

void DspRisTargetsLookup(const DspLrpHeaderOutput::Header* hdr, idddsp::dsp_detections_t& dspdet, idddsp::dsp_stt_data_t* stt, bool scan_mode)
{
	if (dsp_ris_tgt_db.no_override==0)
	{
		dspdet.detections.num_of_detected_tgts=0;
	}

	if (!hdr->ge.mode.radiate)
		return;

	bool as_mode=false;

	bool close_plot=
			(!hdr->ge.general_settings.antenna.event.bar_in_progress) |
			(!hdr->ge.general_settings.antenna.event.frame_in_progress) |
			(hdr->ge.function_settings.pe_settings.close_plot_flag);

	bool stt_mode=false;

	switch(hdr->ge.mode.operation_mode)
	{
	case iddtypes::rws_master_mode:
	case iddtypes::tws_master_mode:
	case iddtypes::sam_master_mode:
		break;

	case iddtypes::acm_master_mode:
		//WARNING: submode required
		break;

	case iddtypes::gmti_master_mode:
	case iddtypes::sea_high_master_mode:
		as_mode=true;
		break;

	case iddtypes::gm_master_mode:
	case iddtypes::dbs_master_mode:
		as_mode=true;
		break;

	case iddtypes::stt_master_mode:
	case iddtypes::sstt_master_mode:
		close_plot=true;
		stt_mode=true;
		break;

	case iddtypes::vs_master_mode:
		break;

	default:
		return;
	}

	if (stt_mode)
	{
		if (!stt)
			return;

		stt->eccm_data_list.num_meas=0;
		stt->measures_list.num_meas=0;
	}

	float max_range=rs2m(hdr->ge.mode.range_scale);

	float nav_az=hdr->ge.general_settings.antenna.position.navaz_rad;
	float nav_el=hdr->ge.general_settings.antenna.position.navel_rad;

	float az_bw=GC_DEG_TO_RAD(2.5);
	float el_bw=GC_DEG_TO_RAD(2.5);

	unsigned int nfft_total=dspdet.detections.processed_nfft_total;
	unsigned int tt=dspdet.detections.processed_pck_timetag;
	float chmhz=hdr->ge.function_settings.pe_settings.tx_chan_mhz;

	unsigned int n_det=dspdet.detections.num_of_detected_tgts;

	float ac_altitude=hdr->ge.general_settings.navigation.geo_pos.altitude_m;

	auto bar_n=hdr->ge.general_settings.antenna.event.current_bar_number;

	if (dsp_ris_tgt_db.space_invaders)
	{
		static unsigned int sp_decimator;
		static unsigned int sp_id;
		if (sp_decimator==0)
		{
			float range=max_range/(MAX_NO_OF_TGT_DETECTIONS+2);

			for(int i=0; i<MAX_NO_OF_TGT_DETECTIONS; ++i)
			{
		        auto& d=dspdet.detections.target_detections[i];

				d.associated_altitude=ac_altitude;
				d.associated_azimuth=nav_az;
				d.associated_elevation=nav_el;
				d.detection_valid=i+1;
				d.id=++sp_id;
				d.associated_bar_number=bar_n;
				d.detected_tgt.detected_tgt_range=range*(i+1);

                d.detected_tgt.monop_u=0;
                d.detected_tgt.monop_v=0;
                d.detected_tgt.monop_valid=3;
                d.detected_tgt.detection_timetag=tt;
                d.detected_tgt.amplitude_det=50;
                d.detected_tgt.detected_tgt_range_validity=iddtypes::valid;
                d.detected_tgt.detected_tgt_rrate=0;
                d.detected_tgt.detected_tgt_rrate_validity=iddtypes::valid;
                d.detected_tgt.sdr_det=5;
                d.detected_tgt.nfft_total=nfft_total;
                d.detected_tgt.tx_chan_mhz=chmhz;
			}
			dspdet.detections.num_of_detected_tgts=MAX_NO_OF_TGT_DETECTIONS;
		}
		++sp_decimator;
		if (sp_decimator>=6)
			sp_decimator=0;
		return;
	}

	if (!DspRigTgtMutexAcquire(false))
	{
		++dsp_ris_tgt_db.contentions;
		return;
	}

	for(int i=0; i<DSP_RIS_MAX_TGT; ++i)
	{
		if (n_det>=MAX_NO_OF_TGT_DETECTIONS)
			break;

		dsp_ris_tgt_t& t=dsp_ris_tgt_db.t[i];

		if (!t.enabled)
		{
			t.tot=0;
			t.already_seen=0;
			continue;
		}

		if ((!scan_mode) || close_plot)
			t.already_seen=0;

		if (t.already_seen)
		{
			t.tot=0;
			continue;
		}

		if (t.slant_range<0)
			continue;
		if (t.slant_range>max_range)
			continue;
		if (t.altitude<0)
			continue;


		bool visible=false;

		float daz=fabsf(t.az-nav_az);
		if (daz<az_bw)
		{

			float del=fabsf(t.el-nav_el);

			if ((del<el_bw) || ((as_mode && (t.altitude<ac_altitude))))
			{
				visible=true;
			}
		}

		if (visible)
		{
	        if (stt_mode)
	        {
	        	const float rng_win=400;
	        	float r_start=hdr->ge.function_settings.pe_settings.unamb_tgt_range-rng_win;
	        	float r_stop=r_start+rng_win*2;

	        	if ((t.slant_range<r_start) || (t.slant_range>r_stop))
	        		continue;

                //float ac_vel=hdr->ge.general_settings.navigation.speed.vx;//*dspEmu.ac_vel_factor;
                //ac_vel=ac_vel*cosf(t.az+hdr->ge.general_settings.navigation.attitude.platfrom_azimuth_rad);
                //float vel_tgt=t.speed+ac_vel;

	        	idddsp::dsp_stt_data_t& tgt=*stt;
	            tgt.measures_list.num_meas=1;
	            tgt.measures_list.main_measure[0].rng_tgt=t.slant_range;
	            tgt.measures_list.main_measure[0].mr_daz=0;
	            tgt.measures_list.main_measure[0].mr_del=0;
	            tgt.measures_list.main_measure[0].vel_tgt=t.rad_vel; //vel_tgt; //t.speed; //range_rate;
	            if (t.sdr)
	            	tgt.measures_list.main_measure[0].snr_tgt=t.sdr;
	            else
	            	tgt.measures_list.main_measure[0].snr_tgt=100;

	            tgt.eccm_data_list.num_meas=1;
	            if (t.amplitude)
	            	tgt.eccm_data_list.eccm_data[0].amp_tgt=t.amplitude;
	            else
	            	tgt.eccm_data_list.eccm_data[0].amp_tgt=6;

#if 0
	            {//Monopulse simulation
	                //const float SPEED_OF_LIGHT=(2.997925e+08F*10e-6f);
	                const float PI=GC_K_PI;

	                const float lambda=SPEED_OF_LIGHT_MS/chmhz;
	                const float tgt_az=t.az;
	                const float tgt_el=t.el;
	                const float cmd_az=nav_az;
	                const float cmd_el=nav_el;

	                float ref_u=sinf(tgt_az)*cosf(tgt_el);
	                float tgt_u=sinf(cmd_az)*cosf(cmd_el);
	                float delta_u=ref_u-tgt_u;
	                float mr_az=tanf(delta_u)*2*PI*STT_MR_DX/lambda;
	                float ref_v=sinf(tgt_el);
	                float tgt_v=sinf(cmd_el);
	                float delta_v=ref_v-tgt_v;
	                float mr_el=tanf(delta_v)*2*PI*STT_MR_DY/lambda;
	                tgt.measures_list.main_measure[0].mr_daz=mr_az;
	                tgt.measures_list.main_measure[0].mr_del=mr_el;
	            }
#else
	            {
					float mr_az=0;
					float mr_el=0;
					float au=hdr->ge.general_settings.antenna.position.urx_rad;
					float av=hdr->ge.general_settings.antenna.position.vrx_rad;
					float t_az=-(t.az+hdr->ge.general_settings.navigation.attitude.platfrom_azimuth_rad);
					float t_el=-t.el;
					pos2mp(mr_az, mr_el, t_az, t_el, au, av, chmhz);
					tgt.measures_list.main_measure[0].mr_daz=mr_az;
					tgt.measures_list.main_measure[0].mr_del=mr_el;
	            }
#endif

	        	break;
	        }

			++t.tot;
			if ((t.tot<8) & (!as_mode))
				continue;
		}

		if (t.tot<1)
		{
			continue;
		}


        float sinel=sinf(t.el);

        auto& d=dspdet.detections.target_detections[n_det];

		d.associated_azimuth=t.az;
		d.associated_elevation=t.el;

		d.associated_altitude=//t.altitude;
                hdr->ge.general_settings.navigation.geo_pos.altitude_m+sinel*t.slant_range;

		d.associated_bar_number=bar_n; //hdr->ge.general_settings.antenna.event.current_bar_number;

		d.detected_tgt.amplitude_det=t.amplitude>0 ? t.amplitude : 10;
		d.detected_tgt.sdr_det=t.sdr>0 ? t.sdr : 5;

		d.detected_tgt.detected_tgt_range=t.slant_range;
		d.detected_tgt.detected_tgt_range_validity=iddtypes::valid;

		d.detected_tgt.detected_tgt_rrate=t.range_rate;
		d.detected_tgt.detected_tgt_rrate_validity=iddtypes::valid;

		d.detected_tgt.detected_tgt_radial_vel=t.rad_vel;
		d.detected_tgt.detected_tgt_radial_vel_validity=iddtypes::not_valid;

		d.detected_tgt.monop_valid=3;
		d.detected_tgt.monop_u=0;
		d.detected_tgt.monop_v=0;

        d.detected_tgt.nfft_total=nfft_total;
        d.detected_tgt.tx_chan_mhz=chmhz;

        d.detected_tgt.detection_timetag=tt;

        d.id=i;
        d.track_association=i;
        d.track_association_value=0;

		d.detection_valid=3;

		++t.hits;

		if (t.max_tot<t.tot)
		{
			t.max_tot=t.tot;
		}
		t.tot=0;
		t.already_seen=1;

		++n_det;
	}
	DspRigTgtMutexRelease();

	dspdet.detections.num_of_detected_tgts=n_det;
}


#define SAR_IMAGE_DX	2048
struct ris_sar_image_t
{
	enum { DIM=SAR_IMAGE_DX}; //was 484
	uint16_t data[DIM][DIM];
};

bool DspRisPostprocessSignal(const DspLrpHeaderOutput::Header* hdrptr, DspRawSweepData* sc)
{
	int map_type=0;

	if (!hdrptr->ge.mode.radiate)
		return false;

	switch(hdrptr->ge.mode.operation_mode)
	{
	default:
		break;
	case iddtypes::gm_master_mode:
	case iddtypes::dbs_master_mode:
	case iddtypes::sea_low_master_mode:
		map_type=1;
		break;
	case iddtypes::wa_master_mode:
		map_type=2;
		break;
	case iddtypes::sar_master_mode:
		map_type=3;
		break;
	}

	if (map_type==0)
		return false;

	if (map_type==3)
	{
        ris_sar_image_t& img=*(ris_sar_image_t*)&(sc->radials);

    	int sq_min=(SAR_IMAGE_DX/2)-512;
    	int sq_max=(SAR_IMAGE_DX/2)+512;

        for(int r=0; r<SAR_IMAGE_DX; ++r)
        {
        	uint16_t* p=img.data[r];

        	if ((r<sq_min) || (r>sq_max))
        	{
            	for(int c=0; c<SAR_IMAGE_DX; ++c)
            	{
            		p[c]=256;
            	}
        	}
        	else
        	{
        		int c=0;
            	for(c=0; c<sq_min; ++c)
            	{
            		p[c]=512;
            	}
            	for(; c<sq_max; ++c)
            	{
            		p[c]=16000;
            	}
            	for(; c<SAR_IMAGE_DX; ++c)
            	{
            		p[c]=512;
            	}
        	}
        }
		return true;
	}
	unsigned int n_radials=sc->radials.valid_radials;

	if (n_radials==0)
		return false;

	int samples=sc->radials.sweep[0].samples;

	float range_scale_meters=DspRisRanceScale2Meters(hdrptr->ge.mode.range_scale);
	float scale_m=samples/range_scale_meters;

	float ac_altitude=hdrptr->ge.general_settings.navigation.geo_pos.altitude_m;

	float x_range=dsp_ris_tgt_db.rbm_range;

	if (x_range<ac_altitude)
	{
		x_range=range_scale_meters-1000;
		dsp_ris_tgt_db.rbm_range=x_range;
	}
	if (x_range>range_scale_meters)
	{
		x_range=range_scale_meters-1000;
		dsp_ris_tgt_db.rbm_range=x_range;
	}

	int alt_line=ac_altitude*scale_m;
	if (alt_line>samples)
		alt_line=samples;

	int gain=hdrptr->ge.function_settings.pe_settings.mgc;
	if (gain>127)
		gain=127;

	float ptaz=hdrptr->ge.general_settings.navigation.attitude.platfrom_azimuth_rad;


	if (map_type==2)
	{
		float nav_az=hdrptr->ge.general_settings.antenna.position.navaz_rad;
		int x_rbin=fabsf((x_range*scale_m)/cosf(nav_az+ptaz));
		for(unsigned int n=0; n<n_radials; ++n)
		{
			uint8_t* d=sc->radials.sweep[n].data;
			memset(d, 0, samples);
			for(int i=-16; i<16; ++i)
			{
				int pos=x_rbin+i;
				if ((pos<samples) && (pos>10))
				{
					int lvl=i<0 ? -i : i;
					lvl=16-lvl;
					lvl/=5;
					lvl*=2;
					d[x_rbin-i]=lvl;
				}
			}
			sc->radials.sweep[n].azimuth=nav_az;
		}
	}
	else
	{
		static idddsp::dsp_detections_t dspdet;
		dspdet.detections.num_of_detected_tgts=0;

		DspRisTargetsLookup(hdrptr, dspdet, 0, false);
		float nav_az=sc->radials.sweep[0].azimuth;
		int x_rbin=fabsf((x_range*scale_m)/cosf(nav_az+ptaz));
		for(unsigned int n=0; n<n_radials; ++n)
		{
			int i=0;
			uint8_t* d=sc->radials.sweep[n].data;
			for(;i<alt_line; ++i)
			{
				d[i]=0;
			}
			unsigned char v=64+gain;
			for(;i<samples; ++i)
			{
				d[i]=v;
			}

			if (dsp_ris_tgt_db.rbm_sim)
			{
				unsigned char x_intesity=v+40;

				for(int i=-5; i<5; ++i)
				{
					int pos=x_rbin+i;
					if ((pos<samples) && (pos>10))
						d[x_rbin-i]=x_intesity; //+i;
				}
			}
		}


		int tgt_size=2;

		switch(hdrptr->ge.mode.range_scale)
		{
		default:
		case iddtypes::_10NM:
			//samples=123*2;
			break;
		case iddtypes::_20NM:
			//samples=247*2; //samples*=2;
			tgt_size*=2;
			break;
		case iddtypes::_40NM:
			//samples=494*2; //samples*=4;
			tgt_size*=4;
			break;
		case iddtypes::_80NM:
			//samples=988*2; //samples*=8;
			tgt_size*=8;
			break;
		}

		for(unsigned int n=0; n<dspdet.detections.num_of_detected_tgts; ++n)
		{
			if (!dspdet.detections.target_detections[n].detection_valid)
				continue;

			float rng=dspdet.detections.target_detections[n].detected_tgt.detected_tgt_range;
			int rbin=rng*cosf(dspdet.detections.target_detections[n].associated_elevation)*scale_m;

			int b_min=rbin-tgt_size;
			int b_max=rbin+tgt_size;
			if (b_min<0)
				b_min=0;
			if (b_max>samples)
				b_max=samples;

			float az_offset=fabsf(dspdet.detections.target_detections[n].associated_azimuth-nav_az);
			float w=1;
			if (az_offset>FLT_EPSILON)
					w=1-(az_offset/0.04);
			float intensity=200;
			if (w<=0)
				intensity=0;
			else
				intensity*=w;

			//intensity=200;

			if ((b_min<alt_line) || (intensity<64))
			{
				dspdet.detections.target_detections[n].detection_valid=false;
				continue;
			}
			//unsigned char intensity_color=intensity;
			uint8_t* d=sc->radials.sweep[n].data;

			for(int k=b_min; k<b_max; ++k)
			{
				unsigned char intensity_color=intensity-fabsf(10*((k-rbin)/(tgt_size*2)));
				d[k]=intensity_color;
			}
		}
	}

	return true;
}

