//package bouboule;

import java.io.*;
import java.util.*;
import javax.comm.*;

public class ES implements Runnable, SerialPortEventListener {
	
	private static boolean boucle = false;
	public final static boolean debug = false;
	
	static final int enTete = 16;
	static final String synchro = "API";
	static final int vitesse = 4800;
	static final int bitsDonnees = SerialPort.DATABITS_8;
	static final int bitStop = SerialPort.STOPBITS_1;
	static final int parite = SerialPort.PARITY_NONE;
	
	private CommPortIdentifier portId;
	private String portName = "COM1";	
	private SerialPort portSerie;
	private OutputStream sortie;
	private InputStream entree;
	private StringBuffer inputBuffer  = new StringBuffer();;
	
	static final int timeOut = 500;
	private boolean ouvert = false;
	private boolean donnee = false;
	private boolean tropTard = false;
	
	Thread mainThread = Thread.currentThread();
	Thread waitThread;
	
	public ES() {
	}
	
	public ES(String port) {
		portName = port;
	}
	
	public ES(String port, boolean b) {
		portName = port;
		boucle = b;
	}
	
	public void setBoucle(boolean b) {
		boucle = b;
	}
	
	public boolean isBoucle() {
		return boucle;
	}
	
	public void ouvrir()
	throws NoSuchPortException, IOException, TooManyListenersException, UnsupportedCommOperationException, PortInUseException {
		
		portId = CommPortIdentifier.getPortIdentifier(portName);
		portSerie = (SerialPort)portId.open("Bouboule soft", 1000);
		ouvert = true;
		try {
			sortie = portSerie.getOutputStream();
			entree = portSerie.getInputStream();
		} catch (IOException e) {
			 portSerie.close();
			 throw new IOException();
		}
		portSerie.setSerialPortParams(vitesse, bitsDonnees, bitStop, parite);		
	}
	
	public void fermer() throws IOException {
		if(ouvert) {
			if(portSerie != null) {
				sortie.close();
				entree.close();
			}
			portSerie.close();
			ouvert = false;
		}
	}
	
	public void envoyer(String data) throws IOException {
		portSerie.notifyOnDataAvailable(boucle);
		portSerie.setDTR(boucle);
		char tab[] = new char[enTete];
		for(int i=0; i<enTete; i++) {
			tab[i] = (char)i;
		}
		String s = new String(tab);
		s += synchro;
		String s2 = (char)(data.length()) + data;
		int chk = 0;
		for(int i=0; i<s2.length(); i++) {
			chk += (int)(s2.charAt(i));
		}
		s += s2;
		chk %= 256;
		s += (char)chk;
		sortie.write(s.getBytes());
		sortie.flush();
		if (debug) System.out.println(s);
	}
	
	public String recevoir() throws Exception {
		inputBuffer = new StringBuffer();
		donnee = false;
		tropTard = false;
		try {
			portSerie.addEventListener(this);
		} catch (TooManyListenersException e) {
				portSerie.close();
				throw new TooManyListenersException();
		}
		portSerie.setDTR(true);
		portSerie.notifyOnDataAvailable(true);
		waitThread = new Thread(this);
		waitThread.start();
		while(!donnee && !tropTard) ;
		waitThread.interrupt();
		String s = new String(inputBuffer);
		if (debug) { for(int j=0;j<s.length();j++) System.out.print((int)s.charAt(j) + " ") ; System.out.println("");}
		if(donnee) {
			portSerie.notifyOnDataAvailable(boucle);
			portSerie.setDTR(boucle);
			int k = s.indexOf(synchro);
			if(k == -1) {
				throw new Exception("Trame non reconnue");
			}
			s = s.substring(k+3);
			if(s.length() < 2) {
				throw new Exception("Trame invalide");
			}
			int longueur = (int)(s.charAt(0));
			if(longueur+2 != s.length()) {
				throw new Exception("Longueur de trame incorrecte");			
			}
			int chk1 = (int)(s.charAt(longueur+1));
			int chk2 = 0;
			for(int i=0; i<=longueur; i++) {
				chk2 += (int)(s.charAt(i));
			}
			chk2 %= 256;
			if(chk1 != chk2) {
				throw new Exception("Erreur de checksum");
			}
		} else {
			if(tropTard) {
				throw new Exception("Timeout");
			}
		}		
		return s.substring(1,s.length()-1);
	}
	
	public void run() {
		try {
			Thread.sleep(timeOut);
			tropTard = true;
		} catch (InterruptedException e) {}
	}
	
	public void serialEvent(SerialPortEvent event) {
		switch(event.getEventType()) {
		case SerialPortEvent.DATA_AVAILABLE :
			try {
				int data;
				while (entree.available() > 0) {
					data = entree.read();
					inputBuffer.append((char)data);
				}
				donnee = true;
			} catch (IOException e) {}
			break;
		}
	}
	
}

	//if (debug) { for(int j=0;j<s.length();j++) System.out.println((int)s.charAt(j)) ; }
	//if (debug) System.out.println(s);