package org.josast.ModuleSoundModem;

import java.io.*;
import java.net.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.josast.AX25.AX25Frame;
import org.josast.AX25.KissData;
import org.josast.AX25.KissFrame;

public class SoundModemClient {

	private Logger log = Logger.getLogger(getClass().getName());

	private SoundModemConfiguration smConfiguration = null;
	private Socket skt = null;
	private InputStream in = null;
	private boolean open = false;
	private int bufferSize = 1024;

	private Path filepath;

	/**
	 * Initialise connection to soundmodem application with default value
	 * 
	 */
	public SoundModemClient() {

		smConfiguration = new SoundModemConfiguration("config.ini");
		openSocket();
		initialiseFile();
	}

	/**
	 * Initialise connection to soundmodem application with configuration
	 * 
	 */
	public SoundModemClient(SoundModemConfiguration smConfig) {

		smConfiguration = smConfig;
		openSocket();
		initialiseFile();

	}

	/**
	 * Initialise connection to soundmodem application with configuration file
	 * 
	 */
	public SoundModemClient(String filename) {

		smConfiguration = new SoundModemConfiguration(filename);
		openSocket();
		initialiseFile();

	}

	private void openSocket() {

		try {
			skt = new Socket(smConfiguration.getIPadress(), smConfiguration.getPort());
			in = skt.getInputStream();
			open = true;
		} catch (IOException e) {
			log.log(Level.SEVERE, "create stream " + e.toString());
		}

	}

	private void initialiseFile() {

		if (smConfiguration.isSmGenerateBinarieFile()) {

			Path path = Paths.get(smConfiguration.getSmBinarieOutputDirectory());
			// if directory exists?
			if (!Files.exists(path)) {
				try {
					Files.createDirectories(path);
				} catch (IOException e) {
					log.log(Level.SEVERE, "cannot create outpout directorie " + e.toString());
				}
			}

			String creationdate = "";
			if (smConfiguration.isSmBinarieFilePrefixDate()) {
				SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd-HHmmss");
				Date aujourdhui = new Date();
				creationdate = formater.format(aujourdhui) + "-";
			}

			filepath =  Paths.get(smConfiguration.getSmBinarieOutputDirectory() + "\\" + creationdate
					+ smConfiguration.getSmBinarieOutputFile());

		}

	}

	/**
	 * wait bytes from sound modem
	 * 
	 * @return bytes received in KISS format
	 */
	public byte[] receivedKissData() {
		byte[] cbuf = new byte[bufferSize];
		int nbbyteread = 0;

		try {
			nbbyteread = in.read(cbuf);

		} catch (IOException e) {

			log.log(Level.SEVERE, "Error Read data " + e.toString());
			try {
				in.close();
			} catch (IOException e1) {
				log.log(Level.SEVERE, "Closing " + e1.toString());
			}
		}

		byte[] temp =Arrays.copyOf(cbuf, nbbyteread);
			
		if (smConfiguration.isSmGenerateBinarieFile()) {
			
			try {
				Files.write(filepath, temp,StandardOpenOption.APPEND);
			} catch (IOException e) {
				log.severe(e.toString());
			}
			
		}
		return Arrays.copyOf(cbuf, nbbyteread);
	}

	@Deprecated
	public int receiveData(byte[] cbuf) {
		try {
			return in.read(cbuf);
		} catch (IOException e) {

			log.log(Level.SEVERE, "Error Read data " + e.toString());

			try {
				in.close();
			} catch (IOException e1) {
				log.log(Level.SEVERE, "Closing " + e1.toString());
			}
		}
		return 0;

	}

	@Deprecated
	public AX25Frame decode(byte[] frame, int nb) {

		KissFrame kf = new KissFrame();
		KissData kissData = kf.extactMessage(frame, nb);

//		if (type==kf.AX25)
//		{
		AX25Frame ax = new AX25Frame();
		ax.decodeAX25Frame(kissData.getData(), kissData.getSize());
//		}
		System.out.println(kissData.toString());
		System.out.println(ax.toString());
		return ax;

	}

	public void close() {
		try {
			in.close();
		} catch (IOException e1) {
			log.log(Level.SEVERE, "Closing " + e1.toString());
		}
	}

	public boolean isOpen() {
		return open;
	}

	public byte[] receivedRawData() {
		byte[] temp = receivedKissData();
		kiss k = new kiss(temp);
		try {
			temp = k.toRaw();
		} catch (KissException e) {
			log.log(Level.SEVERE, "Extract Raw data " + e.toString());
		}
		return temp;
	}

}
