package com.macetech;

import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;
import gnu.io.UnsupportedCommOperationException;
import gnu.io.PortInUseException;

import java.io.*;
import java.util.*;

public class SerialWriter {
	protected static long CLOSING_SLEEP_SECONDS = 2;
	protected static long WRITE_SLEEP_MILLIS = 100;

	public static byte[] COMMAND_PACKET_START = new byte[]{(byte)255};
	public static byte[] COMMAND_PACKET_STOP = new byte[]{(byte)255, (byte)254};
	public static byte[] COMMAND_FULL_CLEAR = new byte[]{(byte)255, (byte)253};

	protected SerialPort mSerialPort = null;
	protected OutputStream mOutputStream = null;

	public boolean init(String portName) {
		mSerialPort = getSerialPort(portName);

		if (mSerialPort != null) {
			try {
				mSerialPort.setSerialPortParams(57600,
				 SerialPort.DATABITS_8,
				 SerialPort.STOPBITS_1,
				 SerialPort.PARITY_NONE);
				mSerialPort.notifyOnOutputEmpty(true);
			}
			catch (UnsupportedCommOperationException e) {
				System.out.println(e);
			}

			mOutputStream = getOutputStream(mSerialPort);

			if (mSerialPort != null && mOutputStream != null) {
				return true;
			}
			else {
				return false;
			}
		}
		else {
			return false;
		}
	}

	public void close() {
		try {
			Thread.sleep(CLOSING_SLEEP_SECONDS * 1000);
		}
		catch (InterruptedException e) {
			e.printStackTrace();
		}

		try {
			mOutputStream.close();
		}
		catch (IOException e) {
			e.printStackTrace();
		}

		mSerialPort.close();
	}

	protected SerialPort getSerialPort(String portName) {
		SerialPort serialPort = null;

		CommPortIdentifier portId = getSerialPortIdentifier(portName);

		if (portId != null) {
			try {
				serialPort = (SerialPort)portId.open("SimpleWrite", 2000);
			}
			catch (PortInUseException e) {
				System.out.println("Port in use.");
			}
		}

		return serialPort;
	}

	protected CommPortIdentifier getSerialPortIdentifier(String portName) {
		CommPortIdentifier portId = null;

		Enumeration portList = CommPortIdentifier.getPortIdentifiers();

		while (portList.hasMoreElements()) {
			portId = (CommPortIdentifier)portList.nextElement();
			if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL && portId.getName().equals(portName)) {
				return portId;
			}
		}

		return portId;
	}

	protected OutputStream getOutputStream(SerialPort serialPort) {
		OutputStream outputStream = null;

		try {
			outputStream = serialPort.getOutputStream();
		}
		catch (IOException e) {
			System.out.println(e);
		}

		return outputStream;
	}

	protected boolean writePacketAndSleep(byte[] bytes, long sleepMillis) {
		try {
			mOutputStream.write(bytes);
		}
		catch (IOException e) {
			e.printStackTrace();
			return false;
		}

		try {
			Thread.sleep(sleepMillis);
		}
		catch (Exception e) {
			System.out.println(e);
		}

		return true;
	}

	public boolean writePacketStart() {
		return writePacketAndSleep(COMMAND_PACKET_START, 0);
	}

	public boolean writePacket(byte[] bytes) {
		return writePacketAndSleep(bytes, 0);
	}

	public boolean writePacketStop() {
		return writePacketAndSleep(COMMAND_PACKET_STOP, WRITE_SLEEP_MILLIS);
	}

	public static void main(String[] args) {
		SerialWriter writer = new SerialWriter();
		if (!writer.init("/dev/tty.EPBMX-COM-DevB-1")) {
			System.out.println("Could not connect to serial port");
		}
		else {
			System.out.println("Succesfully connected to serial port");

			System.out.println("Writing data");

			for (int i = 0; i < 100; i++) {
				byte x = (byte)(Math.random() * 9);
				byte y = (byte)(Math.random() * 9);

				byte r = (byte)(Math.random() * 255);
				byte g = (byte)(Math.random() * 255);
				byte b = (byte)(Math.random() * 255);

				if (Math.random() * 10 < 3) {
					r = 0;
					g = 0;
					b = 0;
				}

				if (writer.writePacketStart()) {
					writer.writePacket(new byte[]{x, y, r, g, b});
				}
				writer.writePacketStop();

			}

			System.out.println("Finished writing data");

			writer.close();
		}
	}
}
