package com.elphel.imagej.ims;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;

public class DjiSrt {
	static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
	final static String [] SRT_KEYWORDS = {
			"iso",      // 0
			"shutter",  // 1
			"fnum",     // 2
			"ev",       // 3
			"color_md", // 4
			"focal_len",// 5
			"latitude", // 6
			"longitude",// 7
			"rel_alt",  // 8
			"abs_alt",  // 9 - not at the beginning
			"ct"};      // 10
	final static int I_iso =      0;
	final static int I_shutter  = 1;
	final static int I_fnum     = 2;
	final static int I_ev       = 3;
	final static int I_color_md = 4;
	final static int I_focal_len= 5;
	final static int I_latitude = 6;
	final static int I_longitude= 7;
	final static int I_rel_alt  = 8;
	final static int I_abs_alt  = 9;//- not at the beginning
	final static int I_ct      = 10;
	
	int    frameCnt = -1;
	double diffTime =  Double.NaN;
	Date   date =      null;
	int    iso =      -1;
	double shutter =   Double.NaN;
	double fnum =      Double.NaN;
	double ev =        Double.NaN;
	String color_md =  "";
	double focal_len = Double.NaN;
	double latitude =  Double.NaN;
	double longitude = Double.NaN;
	double rel_alt =   Double.NaN;
	double abs_alt =   Double.NaN;
	int    ct =       -1; // incremented by 1 for each frame
/*
00:00:00,066 --> 00:00:00,099
<font size="28">FrameCnt: 3, DiffTime: 33ms
2025-05-15 12:24:25.129
[iso: 110] [shutter: 1/5000.0] [fnum: 1.7] [ev: 0] [color_md: default] [focal_len: 24.00] [latitude: 38.621147] [longitude: -110.720468] [rel_alt: 192.800 abs_alt: 1788.479] [ct: 5415] </font>
 */
	public static ArrayList<DjiSrt>  parseDjiSrt(String srt_path){
		ArrayList<DjiSrt> srtList = new ArrayList<DjiSrt>();
		List<String> lines;
		Path seq_path = Paths.get(srt_path);
		try {
			lines = Files.readAllLines(seq_path, StandardCharsets.UTF_8);
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
		int line = 0;
		double min_abs_rel = Double.NaN, max_abs_rel = Double.NaN;
		while (line < lines.size()) {
			// skip till has "-->"
			while ((line < lines.size()) && (lines.get(line).indexOf("-->") < 0)) line++;
			line++; // now <font size="28">FrameCnt: 3, DiffTime: 33ms
			if (line >= lines.size()) {
				break;
			}
			String line_frameCnt = lines.get(line);
			int ifcnt = (line_frameCnt.indexOf("FrameCnt:"));
			DjiSrt djiSrt = new DjiSrt();
			if (ifcnt >= 0){
				ifcnt += "FrameCnt:".length();
				int icomma = line_frameCnt.indexOf(",",ifcnt);
				if (icomma > ifcnt) {
					djiSrt.frameCnt = Integer.parseInt(line_frameCnt.substring(ifcnt,icomma).trim());
					int idtim = line_frameCnt.indexOf("DiffTime:",icomma);
					if (idtim >= 0){
						idtim+="DiffTime:".length();
						int isec = line_frameCnt.indexOf("s",idtim);
						if (isec >= 0) {
							int im = line_frameCnt.indexOf("m",idtim);
							if (im >=0) {
								djiSrt.diffTime = Double.parseDouble(line_frameCnt.substring(idtim,im).trim())/1000;
							} else {
								djiSrt.diffTime = Double.parseDouble(line_frameCnt.substring(idtim,isec).trim());
							}
						}
					}
				}
				line++;
			}
			if (line >= lines.size()) {
				break;
			}
			// 2025-05-15 12:24:25.129
			try {
				djiSrt.date = dateFormat.parse(lines.get(line));
			} catch (ParseException e) {
				// TODO Auto-generated catch block
//				e.printStackTrace();
				break; // no date found for this record
			}
			line++;
			if (line >= lines.size()) {
				break;
			}
			//
			//[iso: 110] [shutter: 1/5000.0] [fnum: 1.7] [ev: 0] [color_md: default] [focal_len: 24.00] [latitude: 38.621147] [longitude: -110.720468] [rel_alt: 192.800 abs_alt: 1788.479] [ct: 5415] </font>
			String s = lines.get(line);
			String [] tokens = s.split("\\[");
//			System.out.println(tokens);
			for (int ntok = 1; ntok < tokens.length; ntok++) {
				int iclos = tokens[ntok].indexOf("]");
				if (iclos > 0) {
					s = tokens[ntok].substring(0, iclos);
					for (int k = 0; k < SRT_KEYWORDS.length; k++) {
						if (s.startsWith(SRT_KEYWORDS[k])){
							String sv = s.substring(SRT_KEYWORDS[k].length()+1,iclos).trim();
							try {
								switch (k) {
								case I_iso:      djiSrt.iso =       Integer.parseInt(sv); break;
								case I_shutter:  djiSrt.shutter =   1.0/Double.parseDouble(sv.substring(2)); break;
								case I_fnum:     djiSrt.fnum =      Double.parseDouble(sv); break;
								case I_ev:       djiSrt.ev =        Double.parseDouble(sv); break;
								case I_color_md: djiSrt.color_md =  sv; break;
								case I_focal_len:djiSrt.focal_len = Double.parseDouble(sv); break;
								case I_latitude: djiSrt.latitude =  Double.parseDouble(sv); break;
								case I_longitude:djiSrt.longitude = Double.parseDouble(sv); break;
								case I_rel_alt:
									int ispilt = sv.indexOf(" ");
									if (ispilt > 0) {
										djiSrt.rel_alt = Double.parseDouble(sv.substring(0,ispilt));
										String sv2 = sv.substring(ispilt).trim();
										if (sv2.startsWith(SRT_KEYWORDS[I_abs_alt])) {
											sv2 = sv2.substring(SRT_KEYWORDS[I_abs_alt].length() + 1).trim();
											djiSrt.abs_alt = Double.parseDouble(sv2);
										}
									} else {
										djiSrt.rel_alt = Double.parseDouble(sv);
									}
									break;
								case I_ct:       djiSrt.ct =        Integer.parseInt(sv); break;
								}
							} catch (RuntimeException e) {
								// Keep NaN/default values for malformed fields and continue parsing.
							}
						}
					}
				}
			}
//			double min_abs_rel = Double.NaN, max_abs_rel = Double.NaN;
			double abs_rel = djiSrt.abs_alt-djiSrt.rel_alt;
			if (!(min_abs_rel < abs_rel)) min_abs_rel = abs_rel;
			if (!(max_abs_rel > abs_rel)) max_abs_rel = abs_rel;
			srtList.add(djiSrt);
		}
		// No need to compare - difference is home position
		System.out.println("abs_alt-rel_alt: min="+min_abs_rel+", max="+max_abs_rel+" (are the same)");
		return srtList;
	}
	
	public static boolean srtToKml(
			String srt_path,
			String kml_path,
			String icon_url,
			String name,
			String time_zone, // "MDT", "UTC"
			double time_step, // interval in seconds
			double alt_corr // add to altitude
			) {
		int step_millis = (int) Math.round(1000*time_step);
        SimpleDateFormat dateFormatZ = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
		
		ArrayList<DjiSrt> srtList = parseDjiSrt(srt_path);
		StringBuffer sb = new StringBuffer();
		// Generate header
		sb.append(    "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
		sb.append(    "<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n");
		sb.append(    "  <Document>\n");
		if (alt_corr != 0) {
			sb.append(    "    <name>"+name+" Altitude corrected by "+alt_corr+"m. "+"</name>\n");
		} else {
			sb.append(    "    <name>"+name+"</name>\n");
		}
		if (icon_url != null) {
			sb.append("    <Style id=\"style_icon\">\n");
			sb.append("      <IconStyle>\n");
			sb.append("        <Icon>\n");
			sb.append("          <href>"+icon_url+"</href>\n");
			sb.append("        </Icon>\n");
			sb.append("        <hotSpot x=\"32\" y=\"1\" xunits=\"pixels\" yunits=\"pixels\"/>\n");
			sb.append("      </IconStyle>\n");
			sb.append("    </Style>\n");
		}
	    sb.append(    "    <Style id=\"check-hide-children\">\n");
	    sb.append(    "      <ListStyle>\n");
	    sb.append(    "        <listItemType>checkHideChildren</listItemType>\n");
	    sb.append(    "      </ListStyle>\n");
	    sb.append(    "    </Style>\n");
	    sb.append(    "    <styleUrl>#check-hide-children</styleUrl>\n");
	    
	    Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone(time_zone));
        calendar.setTime(srtList.get(0).date);
///        Calendar calendar_utc = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
 //       calendar.add(Calendar.MILLISECOND, -step_millis);
        Instant last_instant = calendar.toInstant();
//        last_instant = last_instant.plusMillis(-step_millis);
        Instant next_instant = last_instant.plusMillis(step_millis);
		for (DjiSrt point:srtList) {
			calendar.setTime(point.date);
			Instant instant = calendar.toInstant();
			if (!instant.isBefore(next_instant)) {
///				calendar_utc.setTime(calendar.getTime());
				// add new placemark
			    sb.append("    <Placemark>\n");
			    sb.append("      <TimeStamp>\n");
///			    sb.append("        <when>"+dateFormatZ.format(calendar_utc.getTime())+"</when>\n");
			    sb.append("        <when>"+dateFormatZ.format(calendar.getTime())+"</when>\n");
			    sb.append("      </TimeStamp>\n");
			    if (icon_url != null) {
			    	sb.append("      <styleUrl>#style_icon</styleUrl>\n");
			    }
			    sb.append("      <Point>\n");
			    sb.append("        <altitudeMode>absolute</altitudeMode>\n");
			    sb.append("        <coordinates>"+String.format("%f,%f,%f",point.longitude,point.latitude,point.abs_alt+alt_corr)+"</coordinates>\n");
			    sb.append("      </Point>\n");
			    sb.append("    </Placemark>\n");
				next_instant = next_instant.plusMillis(step_millis);
			}
		}
		
/*
 * https://developers.google.com/kml/documentation/time
    <Placemark>
      <TimeStamp>
        <when>2007-01-14T21:05:02Z</when>
      </TimeStamp>
      <styleUrl>#paddle-a</styleUrl>
      <Point>
        <coordinates>-122.536226,37.86047,0</coordinates>
      </Point>
    </Placemark>
 * 
 */
		// Generate footer
		sb.append("  </Document>\n");
		sb.append("</kml>\n");
		
		try {
			BufferedWriter out = new BufferedWriter(
					new FileWriter(kml_path)); // , true)); true is for append!
			out.write(sb.toString());
			out.close();
			System.out.println("Written KML to: "+kml_path);
			return true;
        } catch (IOException e) {
            // Display message when exception occurs
            System.out.println("exception occurred" + e);
            return false;
        }
		
	}
	
	
	
	
}
