/**
 * Program that reads an ACM scenery file and generates on standard output
 * ILS records for each runway found. The generated ILS are all assumed to be
 * ILS/DME, then with localized antenna, glide path antenna and DME antenna.
 * The name and the frequency of each ILS are left as place holders to be
 * filled by hand in with data from other sources.
 * 
 * Usage:
 * 
 * ./create-ils.exe SCENERY
 * 
 * This program has been used to complete the sceneries based on the
 * ourairports.com data base, where all the ILS are missing.
 * 
 * @file
 * @author Umberto Salsi <salsi@icosaedro.it>
 * @version $Date: 2017/11/09 05:16:33 $
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "../src/util/error.h"
#include "../src/util/memory.h"
#include "../src/util/reader.h"
#include "../src/util/units.h"
#include "../src/dis/dis/earth.h"


static int parseDouble(reader_Type *in, char *s, double *x)
{
	char *tail;
	*x = strtod(s, &tail);
	if( tail == s || *tail != 0 || ! isfinite(*x) ){
		fprintf(stderr, "%s:%d: invalid decimal number syntax: %s\n",
			reader_getPath(in), reader_getLineNumber(in), s);
		return 0;
	}
	return 1;
}


static void generateILS(char *rwy, earth_LatLonAlt *end1, earth_LatLonAlt *end2)
{
	VPoint end1_xyz;
	earth_LatLonAltToXYZ(end1, &end1_xyz);
	VPoint end2_xyz;
	earth_LatLonAltToXYZ(end2, &end2_xyz);
	
	// Locator antenna 300 m away end2:
	VPoint fwd = end2_xyz;
	VSub(&fwd, &end1_xyz, &fwd);
	double mag = VMagnitude(&fwd);
	fwd.x *= 300/mag;
	fwd.y *= 300/mag;
	fwd.z *= 300/mag;
	VPoint loc_xyz = end2_xyz;
	VAdd(&loc_xyz, &fwd, &loc_xyz);
	earth_LatLonAlt loc;
	earth_XYZToLatLonAlt(&loc_xyz, &loc);
	
	VMatrix XYZToLocNED;
	earth_generateWorldToLocalMatrix(&loc, &XYZToLocNED);
	VPoint a_ned;
	VTransform(&end1_xyz, &XYZToLocNED, &a_ned);
	double bearing = atan2(-a_ned.y, -a_ned.x);
	if( bearing < 0 )
		bearing += 2*M_PI;
	
	// GS antenna 100 m right end1:
	fwd = end2_xyz;
	VSub(&fwd, &end1_xyz, &fwd);
	mag = VMagnitude(&fwd);
	fwd.x *= 100/mag;
	fwd.y *= 100/mag;
	fwd.z *= 100/mag;
	VMatrix r;
	VIdentMatrix(&r);
	VRotate(&r, ZRotation, M_PI/2);
	VPoint gs_ned;
	VTransform_(&fwd, &r, &gs_ned);
	VAdd(&gs_ned, &a_ned, &gs_ned);
	VPoint gs_xyz;
	VReverseTransform(&gs_ned, &XYZToLocNED, &gs_xyz);
	earth_LatLonAlt gs;
	earth_XYZToLatLonAlt(&gs_xyz, &gs);
	
	char loc_lat_s[99];
	earth_latitudeToString(loc_lat_s, sizeof(loc_lat_s), loc.latitude, earth_LLM_DMS);
	char loc_lon_s[99];
	earth_longitudeToString(loc_lon_s, sizeof(loc_lon_s), loc.longitude, earth_LLM_DMS);
	char gs_lat_s[99];
	earth_latitudeToString(gs_lat_s, sizeof(gs_lat_s), gs.latitude, earth_LLM_DMS);
	char gs_lon_s[99];
	earth_longitudeToString(gs_lon_s, sizeof(gs_lon_s), gs.longitude, earth_LLM_DMS);
	
	printf("ILS %s ILS/DME name vhf %s %s %s %s %4.0f 5 %5.1f 3\n",
		rwy, loc_lat_s, loc_lon_s, gs_lat_s, gs_lon_s, gs.z, units_RADtoDEG(bearing));
}


static void parseRunway(reader_Type *in, int argc, char *argv[])
{
	if( argc != 10 ){
		fprintf(stderr, "%s:%d: invalid number of fields in RWY record: %d\n",
			reader_getPath(in), reader_getLineNumber(in), argc);
		return;
	}
	
	double lat1, lon1, lat2, lon2;
	if( ! earth_parseLatitude(argv[6], &lat1) ){
		fprintf(stderr, "%s:%d: invalid latitude: %s\n",
			reader_getPath(in), reader_getLineNumber(in), argv[6]);
		return;
	}
	if( ! earth_parseLongitude(argv[7], &lon1) ){
		fprintf(stderr, "%s:%d: invalid longitude: %s\n",
			reader_getPath(in), reader_getLineNumber(in), argv[7]);
		return;
	}
	if( ! earth_parseLatitude(argv[8], &lat2) ){
		fprintf(stderr, "%s:%d: invalid latitude: %s\n",
			reader_getPath(in), reader_getLineNumber(in), argv[8]);
		return;
	}
	if( ! earth_parseLongitude(argv[9], &lon2) ){
		fprintf(stderr, "%s:%d: invalid longitude: %s\n",
			reader_getPath(in), reader_getLineNumber(in), argv[9]);
		return;
	}
	
	
	char id1[9], id2[9];
	char *id = argv[2];
	char *slash = strchr(id, '/');
	if( slash == NULL ){
		fprintf(stderr, "%s:%d: missing slash character in runway name: %s\n",
			reader_getPath(in), reader_getLineNumber(in), id);
		strcpy(id1, "?");
		strcpy(id2, "?");
	} else {
		*slash = 0;
		memory_strcpy(id1, sizeof(id1), id);
		memory_strcpy(id2, sizeof(id2), slash+1);
	}
	
	double elevation;
	if( ! parseDouble(in, argv[3], &elevation) )
		elevation = 0.0;
	
	earth_LatLonAlt end1;
	end1.latitude = lat1;  end1.longitude = lon1;  end1.z = elevation;
	
	earth_LatLonAlt end2;
	end2.latitude = lat2;  end2.longitude = lon2;  end2.z = elevation;
	
	printf("# %s:\n", argv[1]);
	generateILS(id1, &end1, &end2);
	generateILS(id2, &end2, &end1);
}


static int parseScenery(char *path)
{
	reader_Type *in = reader_new(path);
	char line[999];
	while( reader_getLine(in, line, sizeof(line)) ){

		// Ignore empty and comment lines.
		if( line[0] == '\0' || line[0] == '#' )
			continue;

		int argc;
		char *argv[99];
		if( ! reader_split(line, &argc, argv, 32) ){
			fprintf(stderr, "%s:%d: too many fields -- ignoring line\n",
				reader_getPath(in), reader_getLineNumber(in));
			continue;
		}
		
		if( argc > 0 && strcmp(argv[0], "RWY") == 0 )
			parseRunway(in, argc, argv);
	}
	if( reader_getError(in) != NULL )
		fprintf(stderr, "%s: %s", reader_getPath(in), reader_getError(in));
    memory_dispose(in);
	return 1;
}


int main(int argc, char** argv)
{
	error_init(argv[0]);
	if( argc != 2 ){
		fprintf(stderr, "ERROR: required just one argument.\n");
		return 1;
	}
	return parseScenery(argv[1])? 0 : 1;
}

