
/**
 * measure stream delay
 *
 * @author matecsaba
 */
public class measComp {

    /**
     * the main
     *
     * @param args arguments
     * @throws Exception on error
     */
    public static void main(String[] args) throws Exception {
        if (args.length < 5) {
            System.out.println("usage: java this <device> <group> <source> <port> <seconds>");
            return;
        }
        int sec = Integer.parseInt(args[4]);
        devicer dataLine = devicer.getRecord(args[0]);
        measCompOne dev = new measCompDev(dataLine, sec);
        packer channel = packer.receiver(args[1], args[2], args[3]);
        measCompOne net = new measCompNet(channel, sec);
        measCompOne d = new measCompOne(sec);
        measCompOne n = new measCompOne(sec);
        for (;;) {
            Thread.sleep(250);
            dev.doCopy(d);
            net.doCopy(n);
            d.doFull(n);
        }
    }

}

class measCompOne {

    public byte[] cur;

    public int pos;

    public long tot;

    public byte max;

    public float div;

    public measCompOne(int sec) {
        cur = new byte[devicer.rate * sec];
        pos = 0;
        tot = 0;
    }

    public void doCopy(measCompOne r) {
        System.arraycopy(cur, 0, r.cur, 0, cur.length);
        r.pos = pos;
        r.tot = tot;
    }

    public void addBuf(byte[] buf, int len) {
        int o = pos;
        for (int i = 0; i < len; i += devicer.smpb * 2) {
            int p = (int) buf[i + 0];
            p += (int) buf[i + devicer.smpb];
            if (p < 0) {
                p = -p;
            }
            p /= 2;
            cur[o] = (byte) p;
            o = (o + 1) % cur.length;
        }
        pos = o;
        tot += len;
    }

    public void doBuf() {
        max = Byte.MIN_VALUE;
        for (int i = 0; i < cur.length; i++) {
            byte p = cur[i];
            if (p < max) {
                continue;
            }
            max = p;
        }
        div = (float) max / 120.0f;
        for (int i = 0; i < cur.length; i++) {
            float p = (float) cur[i];
            p /= div;
            cur[i] = (byte) p;
        }
    }

    public int doDiff(measCompOne oth, int beg, int max) {
        int r = 0;
        int p = beg + pos;
        int o = oth.pos;
        for (int i = 0; i < (cur.length / 2); i++) {
            if (p >= cur.length) {
                p = 0;
            }
            if (o >= cur.length) {
                o = 0;
            }
            int q = (int) cur[p];
            q -= (int) oth.cur[o];
            if (q < 0) {
                q = -q;
            }
            r += q;
            if (r > max) {
                return r;
            }
            o++;
            p++;
        }
        return r;
    }

    public void doFull(measCompOne oth) {
        doBuf();
        oth.doBuf();
        int m = doDiff(oth, 0, Integer.MAX_VALUE);
        int p = 0;
        for (int i = 1; i < (cur.length / 2); i++) {
            int o = doDiff(oth, i, m);
            if (o >= m) {
                continue;
            }
            p = i;
            m = o;
        }
        m /= cur.length / devicer.rate;
        int q = (p * 1000) / devicer.rate;
        System.out.println(m + " @ " + p + " (" + q + "ms) dev=" + this + " net=" + oth);
    }

    public String toString() {
        return tot + " " + max;
    }

}

class measCompDev extends measCompOne implements Runnable {

    private devicer dataLine;

    public measCompDev(devicer dl, int sec) {
        super(sec);
        dataLine = dl;
        new Thread(this).start();
    }

    public void run() {
        byte[] buf = new byte[devicer.payl];
        for (;;) {
            int i = dataLine.read(buf);
            if (i < 1) {
                break;
            }
            addBuf(buf, i);
        }
    }

}

class measCompNet extends measCompOne implements Runnable {

    private packer channel;

    public measCompNet(packer ch, int sec) {
        super(sec);
        channel = ch;
        new Thread(this).start();
    }

    public void run() {
        byte[] buf = new byte[devicer.payl];
        for (;;) {
            int i = 0;
            try {
                i = channel.readRtp(buf);
            } catch (Exception e) {
            }
            if (i < 1) {
                break;
            }
            addBuf(buf, i);
        }

    }

}
