/***************************************************************************
 * Creator:  Xiaohua XU                                                    *
 *           (University of Science and Technology of China)               *
 * Date   :  06/03/2024                                                    *
 ***************************************************************************/

/***************************************************************************
 * Modification history:                                                   *
 *                                                                         *
 * DATE   :                                                                *
 *                                                                         *
 ***************************************************************************/

#include "PRM.h"
#include "lib_defs.h"
#include "lib_functions.h"
#include "stateV.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// int pop_prm(struct PRM *, tree *, char *);
int pop_led_pre(tree *, state_vector *, double, double);
int write_orb(state_vector *sv, FILE *fp, int);
double yds2ydf(state_vector);

char *USAGE = "\n\nUsage: ext_orb_lt1 name_of_prm name_of_orb_xml name_output\n"
              "\nExample: ext_orb_lt1 LT1_20230807.PRM "
              "LT1B_20240506084320700_V20240315T235500_20240317T000500_ABSORBIT_SCIE"
              ".xml output\n"
              "\nOutput: output.LED\n";

int main(int argc, char **argv) {

	FILE *XML_FILE, *INPUT_PRM, *OUTPUT_LED;
	char tmp_str[200];
	struct PRM prm;
	tree *xml_tree;
	state_vector *sv;
	int ch, n = 0, nc = 0, nlmx = 0;
	double t1, t2;

	if (argc < 3)
		die(USAGE, "");

	// find the number of lines and the maximum line length of the xml file
	if ((XML_FILE = fopen(argv[2], "r")) == NULL)
		die("Couldn't open xml file: \n", argv[2]);
	while (EOF != (ch = fgetc(XML_FILE))) {
		++nc;
		if (ch == '\n') {
			++n;
			if (nc > nlmx)
				nlmx = nc;
			nc = 0;
		}
	}
	xml_tree = (struct tree *)malloc(5 * n * sizeof(struct tree));
	sv = (struct state_vector *)malloc(n / 2 * sizeof(struct state_vector));
	fclose(XML_FILE);

	if ((XML_FILE = fopen(argv[2], "r")) == NULL)
		die("Couldn't open xml file: \n", argv[2]);
	get_tree(XML_FILE, xml_tree, 1);
	// show_tree(xml_tree,0,0);
	fclose(XML_FILE);

	// get the prm
	if ((INPUT_PRM = fopen(argv[1], "r")) == NULL)
		die("Couldn't open xml file: \n", argv[1]);
	get_sio_struct(INPUT_PRM, &prm);
	// fprintf(stderr,"%.12f  %.12f\n",prm.SC_clock_start,prm.SC_clock_stop);
    // revising t1 and t2 in case only one burst is used.
    // if smaller than 2 burst, extract more
	//t1 = prm.SC_clock_start - 10 * (prm.SC_clock_stop - prm.SC_clock_start);
	//t2 = prm.SC_clock_stop + 10 * (prm.SC_clock_stop - prm.SC_clock_start);
	t1 = prm.SC_clock_start - 200.0/86400.0;
	t2 = prm.SC_clock_stop +  200.0/86400.0;
//    if (fabs(t2-t1) < 1/86400.0*150) {
//        t1 = prm.SC_clock_start - 20 * (prm.SC_clock_stop - prm.SC_clock_start);
//        t2 = prm.SC_clock_stop + 20 * (prm.SC_clock_stop - prm.SC_clock_start);
//    }

	// generate the LED file
	n = pop_led_pre(xml_tree, sv, t1, t2);

	strcpy(tmp_str, argv[3]);
	strcat(tmp_str, ".LED");
	if ((OUTPUT_LED = fopen(tmp_str, "w")) == NULL)
		die("Couldn't open led file: \n", tmp_str);
	// tmp_str = search_tree()
	write_orb(sv, OUTPUT_LED, n);
	fclose(OUTPUT_LED);
	free(xml_tree);
	free(sv);
}

int write_orb(state_vector *sv, FILE *fp, int n) {
	int i;
	double dt;

	if (n <= 0) {
		fprintf(stderr, "[ERROR]: NO orbit coverage in the selected file...\n");
		return (-1);
	}
	else {
		printf("Writing %d lines of precise orbit for the LED file...\n", n);
	}

	dt = round((sv[1].sec) * 1000.0) / 1000.0 - round((sv[0].sec) * 1000.0) / 1000.0;
	// printf("%f,%f\n",sv[1].sec,sv[0].sec);
	if (n <= 1)
		return (-1);
	fprintf(fp, "%d %d %d %.6lf %.3lf \n", n, sv[0].yr, sv[0].jd, sv[0].sec, dt);
	for (i = 0; i < n; i++) {
		fprintf(fp, "%d %d %.6lf %.6lf %.6lf %.6lf %.8lf %.8lf %.8lf \n", sv[i].yr, sv[i].jd, sv[i].sec, sv[i].x, sv[i].y,
		        sv[i].z, sv[i].vx, sv[i].vy, sv[i].vz);
	}
	return (1);
}

int pop_led_pre(tree *xml_tree, state_vector *sv, double t1, double t2) {
	int i, count, num = 0;
	char tmp_c[200], tmp_y[200];
	double tmp_d, tmp_t;
	state_vector tmp_sv;

	search_tree(xml_tree, "/LT1_Orbit_File/Data_Block/List_of_OSVs/", tmp_c, 3, 0, 1);
	count = (int)str2double(tmp_c);
	// printf("Reading %d lines from precise orbit...(%s) \n",count,tmp_c);

//search_tree(xml_tree, "/LT1_Orbit_File/Data_Block/List_of_OSVs/OSV/X/", tmp_c, 1, 4, 37497);
//printf("%s\n",tmp_c);
//exit(1);

	for (i = 0; i < count; i++) {
		search_tree(xml_tree, "/LT1_Orbit_File/Data_Block/List_of_OSVs/OSV/UTC/", tmp_c, 2, 4, i + 1);
		tmp_d = str2double(tmp_c);
		search_tree(xml_tree, "/LT1_Orbit_File/Data_Block/List_of_OSVs/OSV/UTC/", tmp_c, 1, 4, i + 1);
		strasign(tmp_y, tmp_c, 0, 3);
		tmp_sv.yr = (int)(str2double(tmp_y));
		tmp_sv.jd = (int)(tmp_d - trunc(tmp_d / 1000.0) * 1000.0);
		tmp_sv.sec = (tmp_d - trunc(tmp_d)) * 86400;
		tmp_t = yds2ydf(tmp_sv);
//printf("%lf %lf %lf \n",t1,tmp_t,t2);
		if (tmp_t < t1 || tmp_t > t2) {
			continue;
		}
		else {
//printf("%d %d %.6f %s (%d)\n",tmp_sv.yr,tmp_sv.jd,tmp_sv.sec, tmp_c ,i);
			sv[num].yr = tmp_sv.yr;
			sv[num].jd = tmp_sv.jd;
			sv[num].sec = tmp_sv.sec;
			search_tree(xml_tree, "/LT1_Orbit_File/Data_Block/List_of_OSVs/OSV/X/", tmp_c, 1, 4, i + 1);
			sv[num].x = str2double(tmp_c);
			search_tree(xml_tree, "/LT1_Orbit_File/Data_Block/List_of_OSVs/OSV/Y/", tmp_c, 1, 4, i + 1);
			sv[num].y = str2double(tmp_c);
			search_tree(xml_tree, "/LT1_Orbit_File/Data_Block/List_of_OSVs/OSV/Z/", tmp_c, 1, 4, i + 1);
			sv[num].z = str2double(tmp_c);
			search_tree(xml_tree, "/LT1_Orbit_File/Data_Block/List_of_OSVs/OSV/VX/", tmp_c, 1, 4, i + 1);
			sv[num].vx = str2double(tmp_c);
			search_tree(xml_tree, "/LT1_Orbit_File/Data_Block/List_of_OSVs/OSV/VY/", tmp_c, 1, 4, i + 1);
			sv[num].vy = str2double(tmp_c);
			search_tree(xml_tree, "/LT1_Orbit_File/Data_Block/List_of_OSVs/OSV/VZ/", tmp_c, 1, 4, i + 1);
			sv[num].vz = str2double(tmp_c);
//search_tree(xml_tree, "/LT1_Orbit_File/Data_Block/List_of_OSVs/OSV/Y/", tmp_c, 1, 4, i + 1);
//printf("%.6f %d %d %.6f %.6f %.6f %.6f %.6f %.6f %.6f\n",str2double(tmp_c), sv[num].yr,sv[num].jd,sv[num].sec,sv[num].x,sv[num].y,sv[num].z,sv[num].vx,sv[num].vy,sv[num].vz);
//exit(1);
			num++;
		}
 //       if (i == 10) exit(1);
	}
	return (num);
}

double yds2ydf(state_vector s) {
	// convert year, day, sec to year, day, fraction of day
	double t = 0;
	t = t + (double)s.yr * 1000;
	t = t + (double)s.jd;
	t = t + (double)s.sec / 86400.;
	return (t);
}
