/**
 **
 ** Did_strobe_in_time.java - InertialSense DID_STROBE_IN_TIME message decoder for sync events
 **
 ** Copyright (C) 2023 Elphel, Inc.
 **
 ** -----------------------------------------------------------------------------**
 **
 **  Did_strobe_in_time.java is free software: you can redistribute it and/or modify
 **  it under the terms of the GNU General Public License as published by
 **  the Free Software Foundation, either version 3 of the License, or
 **  (at your option) any later version.
 **
 **  This program is distributed in the hope that it will be useful,
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 **  GNU General Public License for more details.
 **
 **  You should have received a copy of the GNU General Public License
 **  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 ** -----------------------------------------------------------------------------**
 **
 */
package com.elphel.imagej.ims;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Properties;

import com.elphel.imagej.tileprocessor.IntersceneMatchParameters;

/* (DID_STROBE_IN_TIME) Timestamp for input strobe.
typedef struct PACKED
{
	// GPS number of weeks since January 6th, 1980
	uint32_t				week;
	// GPS time of week (since Sunday morning) in milliseconds
	uint32_t				timeOfWeekMs;
	// Strobe input pin (i.e. G1, G2, G5, or G9)
	uint16_t				pin;
	// Strobe serial index number 
	uint16_t				count;
} strobe_in_time_t;
*/
public class Did_strobe_in_time {
	public final static long WEEK_MS = 7 * 24 * 3600 * 1000; // milliseconds in a week
	public int 	week;

	/** GPS time of week (since Sunday morning) in milliseconds */
	public int 	timeOfWeekMs;

	/** Strobe input pin (i.e. G1, G2, G5, or G9) */
	public int 	pin;

	/** Strobe serial index number */
	public int 	count;
	
	public Did_strobe_in_time (ByteBuffer bb) {
		bb.order(ByteOrder.LITTLE_ENDIAN);		
		week =         bb.getInt();
		timeOfWeekMs = bb.getInt();
		pin =          bb.getShort();
		count =        bb.getShort();
	}
	public Did_strobe_in_time() {}

	public Did_strobe_in_time interpolate(double frac, Did_strobe_in_time next_did) {
		Did_strobe_in_time new_did = new Did_strobe_in_time();
		double time_ms_this = timeOfWeekMs + WEEK_MS * week;
		double time_ms_next = timeOfWeekMs + WEEK_MS * week;
		long   time_ms = (long) Did_ins.interpolateDouble(frac, time_ms_this, time_ms_next);
		new_did.week = (int) Math.floor(time_ms / WEEK_MS);
		new_did.timeOfWeekMs = (int) (time_ms - new_did.week * WEEK_MS); 
		new_did.pin = pin;
		new_did.count = count;
		return new_did;
	}
	
	/**
	 * Get a pair of integers: week and time of week (from January 6, 1980) in milliseconds
	 * @return {week, time_of_week in ms}
	 */
	public int [] getWeekTimeMs() {
		return new int [] {week, timeOfWeekMs};
	}
	
	/**
	 * Get week/week_time_in_ms pair offset from the given one by specified seconds 
	 * @param week_time_ms integer week (from January 6, 1980)
	 * @param offset_sec integer milliseconds from start of the week
	 * @return week/time pair offset from the given one
	 */
	public static int [] getWeekTimeMs(
			int [] week_time_ms,
			double offset_sec) {
		int [] new_week_time_ms = week_time_ms.clone();
		new_week_time_ms[1] = (int) Math.round(week_time_ms[1] + 1000*offset_sec);
		while (new_week_time_ms[1] < 0) {
			new_week_time_ms[0]--;
			new_week_time_ms[1] += WEEK_MS;
		}
		while (new_week_time_ms[1] >= WEEK_MS) {
			new_week_time_ms[0]++;
			new_week_time_ms[1] -= WEEK_MS;
		}
		return new_week_time_ms;
	}
	
	/**
	 * Calculate delta in seconds between two pairs of (week, time_of_week_in_ms) integers
	 * @param week_time_start 
	 * @param week_time_end
	 * @return time difference in seconds
	 */
	public static double getWeekTimeMsDelta(
			int [] week_time_start,
			int [] week_time_end) {
		return 0.001 * ((week_time_end[1] - week_time_start[1]) +
				((double) (week_time_end[0] - week_time_start[0]) ) * WEEK_MS);
		
	}
	/**
	 * Get a pair of integers: week (from January 6, 1980) and time of week in milliseconds
	 * @param offset_sec  offset week/time by this seconds
	 * @return {week, time_of_week in ms}
	 */
	public int [] getWeekTimeMs(
			double offset_sec) {
		return getWeekTimeMs ( new int [] {week, timeOfWeekMs},offset_sec);
	}
	
	public int pack(ByteBuffer bb) {
		int p_start = bb.position();
		bb.putInt(week);
		bb.putInt(timeOfWeekMs);
		bb.putInt(pin);
		bb.putInt(count);
		int p_end = bb.position();
		return p_end - p_start;
	}
	
	public String toString() {
		String s = "DID_STROBE_IN_TIME\n";
		s += String.format("week:         %d\n", week); 
		s += String.format("timeOfWeekMs: %d\n", timeOfWeekMs); 
		s += String.format("pin:          %d\n", pin); 
		s += String.format("count:        %d\n", count); 
		return s;
	}
	
	
 	public void getProperties(String prefix, Properties properties) {
		if (properties.getProperty(prefix+"week")!=null)         this.week= Integer.parseInt(properties.getProperty(prefix+"week"));
		if (properties.getProperty(prefix+"timeOfWeekMs")!=null) this.timeOfWeekMs= Integer.parseInt(properties.getProperty(prefix+"week"));
		if (properties.getProperty(prefix+"pin")!=null)          this.pin= Integer.parseInt(properties.getProperty(prefix+"pin"));
		if (properties.getProperty(prefix+"count")!=null)        this.count= Integer.parseInt(properties.getProperty(prefix+"count"));
	}
 	
	public Properties setProperties(String prefix, Properties properties){ // save // USED in lwir
		if (properties == null) {
			properties = new Properties();
		}
		properties.setProperty(prefix+"week",         this.week+"");
		properties.setProperty(prefix+"timeOfWeekMs", this.timeOfWeekMs+"");
		properties.setProperty(prefix+"pin",          this.pin+"");
		properties.setProperty(prefix+"count",        this.count+"");
		return properties;
	}
	
	
}