package de.ctdo.crashtest.domotics;

import de.ctdo.crashtest.log.Logger;
import gnu.io.*;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Enumeration;

public class Relaisboard implements IRelaisboard {
    private SerialPort serialPort;
    private OutputStream outputStream;
    private Boolean serialPortGeoeffnet = false;
    private String portName = "/dev/ttyUSB0";
    private Object mLock = new Object();

    public Relaisboard(final String port) {
        this.portName = port;
    }

    private void sendData(final int relais, final boolean state) {
        synchronized (outputStream) {
            if(relais >= 0 && relais < 8 && outputStream != null) {
                char charsOff[] = { 'a','b','c','d','e','f','g','h' };
                char charsOn[] = { 'A','B','C','D','E','F','G','H' };

                try {
                    if(state) {
                        outputStream.write(charsOn[relais]);
                    } else {
                        outputStream.write(charsOff[relais]);
                    }

                    outputStream.flush();
                } catch (IOException e) {
                    Logger.sLog("Relaisboard error: Fehler beim Senden");
                }
            }
        }
    }


    @Override
    public boolean open() {
        serialPortGeoeffnet = false;
        Boolean foundPort = false;

        if (serialPortGeoeffnet != false) {
            Logger.sLog("Serialport bereits geöffnet");
            return false;
        }

        Enumeration enumComm = CommPortIdentifier.getPortIdentifiers();
        CommPortIdentifier serialPortId = null;

        while(enumComm.hasMoreElements()) {
            serialPortId = (CommPortIdentifier) enumComm.nextElement();
            if (portName.contentEquals(serialPortId.getName())) {
                foundPort = true;
                break;
            }
        }
        if (foundPort != true) {
            Logger.sLog("Serialport nicht gefunden: " + portName);
            return false;
        }

        try {
            // open port and tell the OS who we are. Wait max 500ms for release if port is currently owned.
            serialPort = (SerialPort) serialPortId.open("crashtest app", 500);
            serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
            serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);

            outputStream = serialPort.getOutputStream();
            serialPortGeoeffnet = true;

            return true;
        } catch (PortInUseException e) {
            Logger.sLog("Relaisboard error: Port belegt " + portName);
        } catch (IOException e) {
            Logger.sLog("Relaisboard error: Keinen Zugriff auf OutputStream");
        } catch(UnsupportedCommOperationException e) {
            Logger.sLog("Relaisboard error: Konnte Schnittstellen-Paramter nicht setzen");
        }

        return false;
    }

    @Override
    public void close() {
        if ( serialPortGeoeffnet ) {
            serialPort.close();
            serialPortGeoeffnet = false;
            outputStream = null;
        }
    }

    @Override
    public void setRelais(final int relais, final boolean state) {
        if(!serialPortGeoeffnet) return;

        Runnable r = new Runnable() {
            @Override
            public void run() {
                sendData(relais, state);
            }
        };

        new Thread(r).start();
    }

    @Override
    public void toggleRelais(final int relais, final int milliseconds) {
        if(!serialPortGeoeffnet) return;

        Runnable r = new Runnable() {
            @Override
            public void run() {
                sendData(relais, true);

                try {
                    Thread.sleep(milliseconds);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                sendData(relais, false);
            }
        };

        new Thread(r).start();
    }

    @Override
    public void blinkRelais(final int relais, final int pause, final int count) {
        if(!serialPortGeoeffnet) return;

        Runnable r = new Runnable() {
            @Override
            public void run() {
                int i;

                for(i = 0; i< count; i++) {
                    sendData(relais, true);

                    try {
                        Thread.sleep(pause);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    sendData(relais, false);

                    try {
                        Thread.sleep(pause);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };

        new Thread(r).start();
    }
}
