package net.yak.kiwi;

import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

public class RadioHarness {
    public enum Mode {
        NONE("", 0, 0, 0),
        AM("am", -5000, 5000, 0),
        CW("cw", 300, 700, -500),
        LSB("lsb", -2800, -200, 0),
        USB("usb", 200, 2800, 0),
        AM_Narrow("am", -3000, 3000, 0),
        CW_Narrow("cw", 470, 530, -500),
        LSB_Narrow("lsb", -2200, -300, 0),
        USB_Narrow("usb", 300, 2200, 0);

        Mode(String name, int low_cut, int high_cut, int offset) {
            this.name = name;
            this.low_cut = low_cut;
            this.high_cut = high_cut;
            this.offset = offset;
        }
        public String name;
        public int low_cut;
        public int high_cut;
        public int offset;

        public String pickle() {
            return String.format(Locale.ROOT,"%s:%d:%d:%d", name, low_cut, high_cut, offset);
        }

        public static Mode unpickle(String s) {
            String[] words = s.split(":");
            if (words.length == 6) {
                int lo = Integer.parseInt(words[1]);
                int hi = Integer.parseInt(words[2]);
                int off = Integer.parseInt(words[3]);
                int rate = Integer.parseInt(words[4]);
                int gain = Integer.parseInt(words[5]);
                for (Mode m : values()) {
                    if (m.name.equals(words[0]) && m.low_cut == lo && m.high_cut == hi && m.offset == off) {
                        return m;
                    }
                }
            }
            return NONE;
        }
    }

    public static class Config {
        public String server;   // "" for none.
        public long frequency;  // in Hz
        public Mode mode;       // using enum
        public int gain;
        public int rate;
        public boolean compress;  // ImaAdpcm compresses one sample to 4 bits.

        public Config(String server, long frequency, Mode mode, int gain, int rate, boolean compress) {
            this.server = server;
            this.frequency = frequency;
            this.mode = mode;
            this.gain = gain;
            this.rate = rate;
            this.compress = compress;
        }
    }

    public  RadioHarness() {
        current = new Config("", 0, Mode.NONE, 1000, 12000, true);
        reset();
    }

    public synchronized void stop() {
        if (client != null) client.stop();
        client = null;
        if (speaker != null) speaker.stop();
        speaker = null;
    }

    public synchronized void setConfig(Config cfg) {
        if (cfg.server.equals("") || !cfg.server.equals(current.server)) {
            stop();
        }

        if (!cfg.server.equals("") && speaker == null) {
            next = cfg;
        }

        next = cfg;
    }

    public synchronized Config getConfig() {
        return current;
    }

    public synchronized void start() {
        if (speaker != null) speaker.stop();
        if (client != null) client.stop();

        if (next != null) {
            current = next;
        }

        if (current.server.equals("")) return;
        if (current.frequency < 10000) return;
        if (current.mode == Mode.NONE) return;

        speaker = new Speaker(current.rate);
        client = new KiwiClient(this, current, speaker);
        serverValues = new HashMap<>();
        new Thread(speaker).start();
        new Thread(client).start();
    }

    public synchronized void restart() {
        if (speaker == null || client == null) {
            start();
        } else {
            if (current.server == next.server && current.compress == next.compress && current.rate == next.rate) {
                client.addCommand(next);
            } else {
                start();
            }
        }
    }

    // private

    private void reset () {
        current.server = "";
        current.frequency = 5_000_000;
        current.mode = Mode.AM;
    }


    private Config next;
    private Config current;
    private Speaker speaker;
    private KiwiClient client;
    public Map<String,String> serverValues;
}
