package org.josast.EntrysatDecoder;

import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.Logger;

import javax.imageio.ImageIO;


import org.josast.EntrySat.Telemetry;
import org.josast.ModuleSoundModem.SoundModemConfiguration;
import org.josast.SIDS.Station;
import org.josast.kaikai.generated.FrameTlmEntrySat;
import org.josast.kaikai.generated.FrameTlmEntrySat.Ax25Frame;
import org.josast.kaikai.generated.FrameTlmEntrySat.UiFrameTlmEntrySat;
import org.josast.propertyHttp.ConfigHttp;

import javafx.application.Platform;
import javafx.concurrent.WorkerStateEvent;
import javafx.embed.swing.SwingFXUtils;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.stage.Stage;
import javafx.stage.Window;
import javafx.scene.control.Alert;

public class Controler {

	private static final String LINE_SEPARATOR = "\r\n";
	private Logger log = Logger.getLogger("EntrySatLogger");
	private String version = "0.8.1";

	@FXML
	private Button ButtonStart;
	@FXML
	private Button ButtonStop;
	@FXML
	private Button ButtonSave;
	@FXML
	private Label LabelIP;

	@FXML
	private Button ButtonFile;
	@FXML
	private Button ButtonSerial;
	@FXML
	private Button ButtonKiss;

	@FXML
	private TextField FieldIP;
	@FXML
	private TextField FieldPort;

	@FXML
	private Label labelStatus;
	@FXML
	private Label LabelFrame;

	@FXML
	private TextArea DecodedData;

	@FXML
	private TextArea TexAreaLog;

	@FXML
	private TextField textFieldMode;

	@FXML
	private TextField textFieldDate;

	@FXML
	private Label LabelInformation;
	@FXML
	private TextField textFieldbEps33VCurrent;
	@FXML
	private TextField TextFieldEps5VCurrent;
	@FXML
	private TextField TextFieldepsBattVcurrent;
	@FXML
	private TextField TextFieldEpsTemp;
	@FXML
	private TextField TextFieldTrxTemp;
	@FXML
	private TextField TextFieldEPSVBAT;

	@FXML
	private TextField TFBattTemp;

	@FXML
	private ImageView ImageViewAMSAT;

	@FXML
	private ImageView imageViewEntrysat;

	@FXML
	private TextField TextFieldCallsign;
	@FXML
	private TextField TextFieldLatitude;
	@FXML
	private TextField TextFieldLongitude;

	@FXML
	private CheckBox CheckbBoxEntrysat;
	@FXML
	private CheckBox CheckBoxSatNogs;

	@FXML
	private Button ButtonSaveConfiguration;

	@FXML
	TextField TextFieldSIDSEntrysat;
	@FXML
	TextField TextFieldSIDSSatnogs;

	Stage primaryStage = null;

	private String imgAmsat = "/logoAmsat.png";
	private String imgEntrysat = "/logo_pour_decodeur.jpg";

	Station station = new Station();

	ModelFrame receivedFrame = new ModelFrame();

	Configuration conf = Configuration.getInstance();

	private TaskSoundmodemTCP task;
	private SendSIDS SendSIDSSatnogs;
	private SendSIDS SendSIDSEntrysat;
	private PrintWriter pw;
	Logger logger = Logger.getLogger("EntrySatLogger");
	
	@FXML
	private void HandleSaveConfiguration(ActionEvent event) {
		Window owner = ButtonSaveConfiguration.getScene().getWindow();

		String erreurmsg = null;
		String Callsign = null;
		if (TextFieldCallsign.getText().isEmpty()) {
			erreurmsg += "please enter a CallSign \r\n";
		} else {
			Callsign = TextFieldCallsign.getText();
		}

		String Latitude = TextFieldLatitude.getText();
		String Longitude = TextFieldLongitude.getText();

		if (station.checkLatitude(Latitude) == false) {
			erreurmsg += "Wrong format for Latitude : XX.XXE/W \r\n";
		}

		if (station.checkLongitude(Longitude) == false) {
			erreurmsg += "Wrong format for Longitude : XX.XXS/N \r\n";
		}
		if (erreurmsg != null) {
			AlertHelper.showAlert(Alert.AlertType.ERROR, owner, "Form Error!", erreurmsg);
			return;
		}

		station.setCallsign(Callsign);
		station.setLatitude(Latitude);
		station.setLongitude(Longitude);

		conf.setCallsign(Callsign);
		conf.setLatitude(Latitude);
		conf.setLongitude(Longitude);

		conf.setSIDSEntrySatSource(TextFieldSIDSEntrysat.getText());
		conf.setSIDSSatnogsSource(TextFieldSIDSSatnogs.getText());
		conf.setSoundModemIP(FieldIP.getText());
		conf.setSoundModemPort(FieldPort.getText());

		Station StationSatnogs = new Station(conf.getSIDSSatnogsSource(), station.getLongitude(),
				station.getLatitude());
		Station StationEntry = new Station(conf.getSIDSEntrySatSource(), station.getLongitude(), station.getLatitude());

		if (CheckbBoxEntrysat.isSelected() == true) {
			conf.setSIDSEntrySat("1");
			SendSIDSEntrysat = new SendSIDS(StationEntry, conf.getNorad(), conf.getSIDSEntryUrl());
		} else {
			conf.setSIDSEntrySat("0");

		}

		if (CheckBoxSatNogs.isSelected() == true) {
			conf.setSIDSSatnogs("1");
			SendSIDSSatnogs = new SendSIDS(StationSatnogs, conf.getNorad(), conf.getSIDSSatnogsURL());
		} else {
			conf.setSIDSSatnogs("0");
		}

		conf.save();

		displayLog("Configuration Saved");
		labelStatus.setText("Configuration Saved");
	}

	@FXML
	private void handleStart(ActionEvent event) {

		labelStatus.setText("KISS TCP Start");
		displayLog("KISS TCP Start");
		ButtonStop.setDisable(false);
		ButtonStart.setDisable(true);
		ButtonSave.setDisable(false);

		SoundModemConfiguration smc = new SoundModemConfiguration("default");
		smc.setSmIPadress(FieldIP.getText());
		smc.setSmPort(Integer.parseInt(FieldPort.getText()));
		
		if (task == null) {
			receivedFrame.addPropertyChangeListener(new PropertyChangeListener() {

				@Override
				public void propertyChange(PropertyChangeEvent evt) {
					final FrameTlmEntrySat tlmEntrySat = receivedFrame.getLastFrame();
					final EntryFrame tlmEntrySatKISS = receivedFrame.getLastKissFrame();
					if (conf.isSIDS_EntrySat()) {
						// Generation SIDS
					}
					Platform.runLater(new Runnable() {
						@Override
						public void run() {
							try {
						
								if (tlmEntrySat != null) {

									// update data
									Ax25Frame ax = tlmEntrySat.frameTlmEntrySat();
									DecodedData.appendText("destSsidRaw : " + ax.ax25Header().destSsidRaw() + "\t");
									DecodedData.appendText("srcSsidRaw : " + ax.ax25Header().srcSsidRaw() + "\t");
									DecodedData.appendText("destCallsign : "
											+ ax.ax25Header().destCallsignRaw().destCallsignRor().destCallsign()
											+ "\t");
									DecodedData.appendText("srcCallsign : "
											+ ax.ax25Header().srcCallsignRaw().srcCallsignRor().srcCallsign() + "\t");
									DecodedData.appendText("ctl" + ax.ax25Header().ctl() + "\r\n");
									displayLog(tlmEntrySatKISS.toString());
									if ((ax.ax25Header().ctl() & 0x13) == 0x03) {
										// identified trame 
										
										displayLog("Entrysat Telemetry Identified \r\n");
										UiFrameTlmEntrySat Ui = (UiFrameTlmEntrySat) ax.payload();
										// verifie que c'est bien la trame avec SID 6
										if (Ui.telemetryData().sid() == 6) {

											Telemetry tlm = new Telemetry();
											tlm.setValue(tlmEntrySat.frameTlmEntrySat());
											DecodedData.appendText(tlm.toStringHeader());
											DecodedData.appendText(tlm.afficheTLM());
											textFieldDate.setText(tlm.getTimetoSting());
											textFieldMode.setText(tlm.getValueDecoded(Telemetry.ModeSafe));
											textFieldbEps33VCurrent.setText(tlm.getValueDecoded(Telemetry.EPS_3_3V_C));
											TextFieldEps5VCurrent.setText(tlm.getValueDecoded(Telemetry.EPS_5_V_C));
											TextFieldepsBattVcurrent
													.setText(tlm.getValueDecoded(Telemetry.EPS_BATT_VCURRENT));
											TextFieldEpsTemp.setText(tlm.getValueDecoded(Telemetry.EPS_TEMP));
											TextFieldTrxTemp.setText(tlm.getValueDecoded(Telemetry.TRX_TEMP));
											TFBattTemp.setText(tlm.getValueDecoded(Telemetry.BATT_TEMP));
											TextFieldEPSVBAT.setText(tlm.getValueDecoded(Telemetry.EPS_VBATT));
										}
										else
										{
											displayLog("Entrysat Telemetry with SID : "+Ui.telemetryData().sid()+"\r\n");
										}
									}
									updateFrame(receivedFrame.getNumberFrame());

									if (conf.isSIDS_EntrySat() == true) {
										int results = SendSIDSEntrysat.Send(tlmEntrySatKISS );
										displayLog("Send SIDS ENtry Sat ; "+results);
									}

									if (conf.isSISD_SatNogs() == true) {
										int results = SendSIDSSatnogs.Send(tlmEntrySatKISS );
										displayLog("Send SIDS Sat NOGS : "+results );
									}

								} else {
									displayLog("received frame  : null");
								}

							} catch (Exception e) {
								displayLog("Run - error");
								displayLog(e.toString());
								e.printStackTrace();
							}

						}

					});
				}

			}

			);

		}
		task = new TaskSoundmodemTCP(smc, receivedFrame);

		task.setOnSucceeded(new EventHandler<WorkerStateEvent>() {

			@Override
			public void handle(WorkerStateEvent event) {
				// La tache s'est correctement terminee.

				labelStatus.setText("KISS TCP DISCONNECTED");
				displayLog("KISS TCP DISCONNECTED");
				ButtonStop.setDisable(true);
				ButtonStart.setDisable(false);
				ButtonSave.setDisable(false);
			}

		});

		task.setOnFailed(new EventHandler<WorkerStateEvent>() {

			@Override
			public void handle(WorkerStateEvent event) {
				// La tache s'est correctement terminee.
				displayLog("Deconnection");
				displayLog(event.toString());
				displayLog(event.getSource().toString());

				labelStatus.setText("KISS TCP CONNECTION FAILED");
				displayLog("KISS TCP DISCONNECTED - Connection failed");
				ButtonStop.setDisable(true);
				ButtonStart.setDisable(false);
				ButtonSave.setDisable(false);
			}

		});

		Thread backgroundThread = new Thread(task);
		backgroundThread.setDaemon(true);
		backgroundThread.start();

	}

	@FXML
	private void handleStop(ActionEvent event) {

		ButtonStop.setDisable(true);
		ButtonStart.setDisable(false);
		ButtonSave.setDisable(false);
		task.arreter();

		labelStatus.setText("Stop received data");
		displayLog("Stop task to receive telemetrie");
	}

	@FXML
	private void handleSave(ActionEvent event) {

		ButtonStop.setDisable(true);
		ButtonStart.setDisable(false);
		ButtonSave.setDisable(true);
		saveDataFile();
		labelStatus.setText("Data Saved");
		displayLog("Telemetry Data saved in file");
	}

	@FXML
	private void HandleIP(ActionEvent event) {
	}

	@FXML
	private void HandlePort(ActionEvent event) {
	}

	/**
	 * Save telemetry data received in text file. The file is stored in data folder.
	 */
	public void saveDataFile() {
		SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd-HHmmss");
		Date aujourdhui = new Date();

		// 

		String path = System.getProperty("user.dir") + "/data";
		File apath = new File(path);

		if (!apath.exists()) {
			if (apath.mkdir() == false) {
				log.severe("fail to create " + path);
			}
		}

		PrintWriter pw = null;

		long NbFrame = receivedFrame.getNumberFrame();

		try {
			pw = new PrintWriter(new FileWriter(path + "/" + formater.format(aujourdhui) + "-tlm-Hexa.txt"));
			for (int i = 0; i < NbFrame; i++) {
				pw.write(receivedFrame.getFrame(i));
				pw.write(LINE_SEPARATOR);
			}

			pw.flush();
			pw.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	private void updateFrame(long nbframe) {
		LabelFrame.setText("frame : " + nbframe);

	}


	public void initMMI() {

		// initialise le log
		initdisplayLogFile();
		displayLog("ENTRY SAT - LOG ");
		log.warning("Initialise ");
		primaryStage.setTitle("EntrySat Decoder - " + version);

		station.setCallsign(conf.getCallsign());
		station.setLatitude(conf.getLatitude());
		station.setLongitude(conf.getLongitude());

		TextFieldCallsign.setText(station.getCallsign());
		TextFieldLatitude.setText(station.getLatitude());
		TextFieldLongitude.setText(station.getLongitude());

		TextFieldSIDSEntrysat.setText(conf.getSIDSEntrySatSource());
		TextFieldSIDSSatnogs.setText(conf.getSIDSSatnogsSource());

		 
		if (conf.isSIDS_EntrySat()) {
			CheckbBoxEntrysat.setSelected(true);
		}
		if (conf.isSISD_SatNogs()) {
			CheckBoxSatNogs.setSelected(true);
		}

		displayLog(conf.getSIDSSatnogsURL());
		displayLog(conf.getSIDSEntryUrl());
		displayLog("Initialisation with Properties File Done ");

		BufferedImage bufferedImage1 = null;
		BufferedImage bufferedImage2 = null;
		try {
			bufferedImage1 = ImageIO.read(getClass().getResource((imgAmsat)));
			bufferedImage2 = ImageIO.read(getClass().getResource((imgEntrysat)));
		} catch (IOException e) {

			log.severe("Error loading Image resources");
			log.severe(e.toString());
		}
		Image imageamsat = SwingFXUtils.toFXImage(bufferedImage1, null);
		;
		ImageViewAMSAT.setImage(imageamsat);
		Image imgQB = SwingFXUtils.toFXImage(bufferedImage2, null);
		;
		imageViewEntrysat.setImage(imgQB);

//		ConfigHttp c = new  ConfigHttp("http://amsat-f.org/sitewordpress/Documents/EntrysatVersion.txt");
		ConfigHttp c = new ConfigHttp("http://site.amsat-f.org/download/116451");
		String ver;
		String message;
		int NoradIdConf=conf.getNorad();
		if(c.isConnected())
		{
		ver = c.GetProperty("EntrySatVersion");
		message = c.GetProperty("Message");
		NoradIdConf= Integer.parseUnsignedInt(c.GetProperty("NoradID").trim());
		}
		else
		{
			ver = version;
			message = "not connected to internet";
		}
		if (NoradIdConf!=conf.getNorad())
		{
			conf.setNorad(NoradIdConf);
			conf.save();
			displayLog("Norad ID updated  ");
		}
		ButtonStop.setDisable(true);
		ButtonStart.setDisable(false);
		ButtonSave.setDisable(true);
		this.LabelInformation.setText("");

		// initialise SIDS

		Station StationSatnogs = new Station(conf.getSIDSSatnogsSource(), station.getLongitude(),
				station.getLatitude());
		Station StationEntry = new Station(conf.getSIDSEntrySatSource(), station.getLongitude(), station.getLatitude());

		if (conf.isSISD_SatNogs() == true) {
			SendSIDSSatnogs = new SendSIDS(StationSatnogs, conf.getNorad(), conf.getSIDSSatnogsURL());
		}

		if (conf.isSIDS_EntrySat() == true) {
			SendSIDSEntrysat = new SendSIDS(StationEntry, conf.getNorad(), conf.getSIDSEntryUrl());
		}

		String erreurmsg = message;

		if (ver.equals(version) == false) {
			erreurmsg += " New version " + ver + " available ! ";

		}
		this.LabelInformation.setText(erreurmsg);

	}

	public void setPrimaryStage(Stage primaryStage) {
		this.primaryStage = primaryStage;

	}
	
	private void displayLog(String log) {
		  pw.println(log);
		  pw.flush();
		  logger.info(log);
		  TexAreaLog.appendText(log);
		 TexAreaLog.appendText("\r\n");
	}

	private void initdisplayLogFile()
	{
		SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd-HHmmss");
		Date aujourdhui = new Date();

		//  

		String path = System.getProperty("user.dir") + "/log";
		File apath = new File(path);

		if (!apath.exists()) {
			if (apath.mkdir() == false) {
				log.severe("fail to create " + path);
			}
		}
		try {
			 pw = new PrintWriter (new FileWriter(path+"/"+formater.format(aujourdhui)+"-"+".log"));
			 displayLog("log error during decoding data");
			
		} catch (IOException e) {
			logger.severe("erreur creating log file");
			logger.severe (e.toString());
		}
	}
}
