package org.josast.EntrySat;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Set;

import org.josast.TLM.AxBEqx;
import org.josast.TLM.TlmData;
import org.josast.TLM.xEqx;
import org.josast.kaikai.generated.FrameTlmEntrySat.Ax25Frame;
import org.josast.kaikai.generated.FrameTlmEntrySat.TelemetryDataFiledHearder;
import org.josast.kaikai.generated.FrameTlmEntrySat.UiFrameTlmEntrySat;

/**
 * This class give access to data form Entrysat TLM data
 * 
 * @author christophe
 * 
 */
public class Telemetry {

	public static final String BATT_TEMP = "BATT TEMP";
	public static final String EPS_TEMP = "EPS TEMP";
	public static final String EPS_3_3V_C = "EPS 3.3 V Current";
	public static final String EPS_5_V_C = "EPS 5 V Current";
	public static final String EPS_VBATT = "EPS VBATT";
	public static final String TRX_TEMP = "TRX TEMP";
	public static final String ModeSafe = "Mode Safe";
	public static final String SID = "SID";
	public static final String EPS_BATT_VCURRENT = "EPS BATTVCURRENT";
//	private static final String TIME = "Time";

	private SimpleDateFormat ft = new SimpleDateFormat("dd MM yyyy - HH:mm:ss zzz");

	/**
	 * dataDescription list with description of each telemetry data
	 */
	private Hashtable<String, TlmData> dataDescription = new Hashtable<String, TlmData>();
	/**
	 * dataValue list to store value of 1 frame
	 */
	private Hashtable<String, Integer> dataValue = new Hashtable<String, Integer>();

	private String timeformat;
	private long timeFrame;

	/**
	 * 
	 */
	public Telemetry() {
		init();
	}

	/**
	 * Initialise all telemetry data with associated formulea
	 */

	private void init() {

		dataDescription.put(SID, new TlmData(SID, new xEqx(), "", "%.0f"));
		dataDescription.put(ModeSafe, new TlmData(ModeSafe, new xEqx(), "", "%2.0f"));
		dataDescription.put(EPS_VBATT, new TlmData(EPS_VBATT, new AxBEqx(0.05, 3.0), "", "%.5f"));
		dataDescription.put(EPS_BATT_VCURRENT, new TlmData(EPS_BATT_VCURRENT, new AxBEqx(0.0078740, -1.0), "", "%.3f"));
		dataDescription.put(EPS_3_3V_C, new TlmData(EPS_3_3V_C, new AxBEqx(0.025, 0), "", "%.5f"));
		dataDescription.put(EPS_5_V_C, new TlmData(EPS_5_V_C, new AxBEqx(0.025, 0), "", "%.5f"));
		dataDescription.put(TRX_TEMP, new TlmData(TRX_TEMP, new AxBEqx(0.25, -15.0), "", "%.3f"));
		dataDescription.put(EPS_TEMP, new TlmData(EPS_TEMP, new AxBEqx(0.25, -15.0), "", "%.3f"));
		dataDescription.put(BATT_TEMP, new TlmData(BATT_TEMP, new AxBEqx(0.25, -15.0), "", "%.3f"));

	}

	public static int unsignedByteToInt(byte b) {
		return (int) b & 0xFF;
	}

	/**
	 * From an Ax25Frame (generated by Kaitai), the function extract data and fill
	 * hastable with value
	 * 
	 * @param ax Ax25Frame
	 */
	public void setValue(Ax25Frame ax) {

		UiFrameTlmEntrySat Ui = (UiFrameTlmEntrySat) ax.payload();

		TelemetryDataFiledHearder TDF = Ui.telemetryDataFiledHearder();

		// Compute time

		byte[] b = TDF.time2();
		long times = unsignedByteToInt(b[0]) * 256 * 256 * 256 + unsignedByteToInt(b[1]) * 256 * 256
				+ unsignedByteToInt(b[2]) * 256 + unsignedByteToInt(b[3]);
		long timems = (long) ((float) (unsignedByteToInt(b[4]) / 256.0) * 1000);
		GregorianCalendar gcalendar = new GregorianCalendar(2000, 0, 1, 0, 0, 0);
		Date time = gcalendar.getTime();
		long value = time.getTime();
		value = value + times * 1000;
		value = value + timems;
		time.setTime(value);
		setTimeFrame(value);
		timeformat = ft.format(time);

		dataValue.put(SID, Ui.telemetryData().sid());
		dataValue.put(ModeSafe, Ui.telemetryData().modeSafe());
		dataValue.put(EPS_VBATT, Ui.telemetryData().epsVbatt());
		dataValue.put(EPS_BATT_VCURRENT, Ui.telemetryData().epsBattVcurrent());
		dataValue.put(EPS_3_3V_C, Ui.telemetryData().eps33VCurrent());
		dataValue.put(EPS_5_V_C, Ui.telemetryData().eps5VCurrent());
		dataValue.put(TRX_TEMP, Ui.telemetryData().trxTemp());
		dataValue.put(EPS_TEMP, Ui.telemetryData().epsTemp());
		dataValue.put(BATT_TEMP, Ui.telemetryData().battTemp());
	}

	/**
	 * @return TIME - time interpreted
	 */
	public String getTimetoSting() {
		return timeformat;
	}

	/**
	 * return string with all decoded value of the frame
	 * 
	 * @return String with all decoded data, ";' is used as separator
	 */
	public String afficheTLM() {

		StringBuilder stringBuilder = new StringBuilder();
		Set<String> keys = dataDescription.keySet();

		// Obtaining iterator over set entries
		Iterator<String> itr = keys.iterator();
		String strvalue;
		// Displaying Key and value pairs
		while (itr.hasNext()) {
			// Getting Key
			strvalue = itr.next();

			TlmData tlm = dataDescription.get(strvalue);
			int value = dataValue.get(strvalue);
			String valueS = String.format(tlm.getFormat(), tlm.getFormulae().calcul(value));
			stringBuilder.append(valueS);
			stringBuilder.append(";\t");
		}

		stringBuilder.append("\r\n");
		return stringBuilder.toString();
	}

	/**
	 * Compute the raw value with formulea and format the string
	 * 
	 * @param dataName
	 * @return value interpreted
	 */
	public String getValueDecoded(String dataName) {

		TlmData tlm = dataDescription.get(dataName);
		int value = dataValue.get(dataName);
		return String.format(tlm.getFormat(), tlm.getFormulae().calcul(value));
	}

	/**
	 * Compute the raw value with formulea
	 * 
	 * @param dataName
	 * @return value interpreted
	 */
	public double getValueDec(String dataName) {

		TlmData tlm = dataDescription.get(dataName);
		int value = dataValue.get(dataName);
		return tlm.getFormulae().calcul(value);
	}

	/**
	 * display list of data decoded
	 * 
	 * @return name of data decoded separated by ","
	 */
	public String toStringHeader() {
		StringBuilder stringBuilder = new StringBuilder();
		Set<String> keys = dataDescription.keySet();

		// Obtaining iterator over set entries
		Iterator<String> itr = keys.iterator();
		String strvalue;
		// Displaying Key and value pairs
		while (itr.hasNext()) {
			// Getting Key
			strvalue = itr.next();

			stringBuilder.append(strvalue);
			stringBuilder.append(";\t");
		}

		stringBuilder.append("\r\n");
		return stringBuilder.toString();

	}

	public long getTimeFrame() {
		return timeFrame;
	}

	public void setTimeFrame(long timeFrame) {
		this.timeFrame = timeFrame;
	}

}
