package de.dwerth.audiowakeup.input;

import de.dwerth.audiowakeup.main.WiringComponent;

import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Line;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.Mixer;
import javax.sound.sampled.TargetDataLine;

import org.apache.log4j.Logger;

public class LineInConnector implements IAudioInput {

    private static final Logger log = Logger.getLogger(LineInConnector.class);
    private static final String FOUND = "FOUND";
    private static final String NOT_FOUND = "NOT_FOUND";

    private String lineName;
    private int signalThreshold;

    private List<String> lastSignals = Collections.synchronizedList(new LinkedList<String>());

    public LineInConnector(String lineName, int signalThreshold) {
        this.lineName = lineName;
        this.signalThreshold = signalThreshold;
        getHandlerThread().start();
    }

    public static HashMap<String, Line> enumerateLines() {
        HashMap<String, Line> out = new HashMap<String, Line>();
        Mixer.Info[] mixerInfos = AudioSystem.getMixerInfo();
        for (Mixer.Info mixerInfo : mixerInfos) {
            log.debug("Mixer: " + mixerInfo.getName() + " " + mixerInfo.getDescription());
            Mixer m = AudioSystem.getMixer(mixerInfo);
            Line.Info[] lineInfos = m.getTargetLineInfo();
            for (Line.Info lineInfo : lineInfos) {
                if (lineInfo.getLineClass().equals(TargetDataLine.class)) {
                    log.debug("\tLine: " + lineInfo.toString());
                    try {
                        out.put(mixerInfo.getName() + ": " + lineInfo.toString(), m.getLine(lineInfo));
                    } catch (LineUnavailableException e) {
                        log.error("Line Unavailable: " + e.getMessage());
                    }
                }
            }
        }
        return out;
    }

    @Override
    public boolean shouldIncreaseBrightness() {
        if (lastSignals.size() == 10) {
            ListIterator<String> listIterator = lastSignals.listIterator(7);
            while (listIterator.hasNext()) {
                String signal = listIterator.next();
                if (!signal.equals(FOUND)) {
                    return false;
                }
            }
            return true;
        }
        return false;
    }

    public void pushSignal(String signal) {
        if (lastSignals.size() >= 10) {
            Iterator<String> iter = lastSignals.iterator();
            iter.next();
            iter.remove();
        }
        lastSignals.add(signal);
        if (lastSignals.size() == 10) {
            ListIterator<String> listIterator = lastSignals.listIterator(6);
            String lastSignal6 = listIterator.next();
            String lastSignal7 = listIterator.next();
            String lastSignal8 = listIterator.next();
            String lastSignal9 = listIterator.next();
            if (lastSignal7.equals(lastSignal8) && lastSignal7.equals(lastSignal9) && !lastSignal7.equals(lastSignal6)) {
                if (signal.equals(NOT_FOUND)) {
                    WiringComponent.getInstance().triggerWakeupDone();
                } else {
                    WiringComponent.getInstance().triggerWakeup();
                }
            }
        }
    }

    public Thread getHandlerThread() {
        Thread t = new Thread() {
            public void run() {
                TargetDataLine targetDataLine = getLine();
                if (targetDataLine != null) {
                    try {
                        targetDataLine.open();
                    } catch (LineUnavailableException e) {
                        log.error("Line Unavailable: " + e.getMessage());
                    }
                    targetDataLine.start();
                    while (true) {
                        byte[] buffer = new byte[2000];
                        int bytesRead = targetDataLine.read(buffer, 0, buffer.length);

                        short max;
                        if (bytesRead >= 0) {
                            max = (short) (buffer[0] + (buffer[1] << 8));
                            for (int p = 2; p < bytesRead - 1; p += 2) {
                                short thisValue = (short) (buffer[p] + (buffer[p + 1] << 8));
                                if (thisValue > max) max = thisValue;
                            }
                            log.debug("Line in signal: " + max);
                            if (max > signalThreshold) {
                                pushSignal(FOUND);
                            } else {
                                pushSignal(NOT_FOUND);
                            }
                        }
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                } else {
                    log.error("No Line found!");
                }
            }
        };
        return t;
    }

    public TargetDataLine getLine() {
        AudioFormat format = new AudioFormat(8000.0f, 16, 1, true, true);
        try {
            HashMap<String, Line> out = enumerateLines();
            for (String key : out.keySet()) {
                if (key.contains(lineName)) {
                    log.info("Found Line: " + key);
                    return (TargetDataLine) out.get(key);
                }
            }
            log.info("Returning OS Default Line");
            return AudioSystem.getTargetDataLine(format);
        } catch (LineUnavailableException e) {
            e.printStackTrace();
        }
        return null;
    }
}

@@ -86,172 +86,37 @@
 nt;%0A
-%0A
 import 
-java.util.Collections;%0Aimport java.util.HashMap;%0Aimport java.util.Iterator;%0Aimport java.util.LinkedList;%0Aimport java.util.List;%0Aimport java.util.ListIterato
+org.apache.log4j.Logge
 r;%0A%0A
@@ -142,27 +142,17 @@
 sampled.
-AudioFormat
+*
 ;%0Aimport
@@ -160,231 +160,15 @@
 java
-x.sound.sampled.AudioSystem;%0Aimport javax.sound.sampled.Line;%0Aimport javax.sound.sampled.LineUnavailableException;%0Aimport javax.sound.sampled.Mixer;%0Aimport javax.sound.sampled.TargetDataLine;%0A%0Aimport org.apache.log4j.Logger
+.util.*
 ;%0A%0Ap
@@ -936,32 +936,78 @@
 getMixerInfo();%0A
+        log.debug(%22Available Mixers/Lines:%22);%0A
         for (Mix
@@ -1407,10 +1407,12 @@
 ug(%22
-%5Ct
+- - 
 Line
@@ -1518,16 +1518,51 @@
 Name() +
+ %22 %22 + mixerInfo.getDescription() +
  %22: %22 + 
@@ -5194,24 +5194,81 @@
 ateLines();%0A
+            log.debug(%22Looking for '%22 + lineName + %22'%22);%0A
             

better output for finding the right line