package ru.r2cloud.jradio.blocks;

import ru.r2cloud.jradio.crc.Crc16Ccitt;

public class HdlcTransmitter {

	private static final int CRC16_LEN_BYTES = 2;
	private static final int BITS_IN_BYTE = 8;
	private static final int BIT_STUFFING_PESSIMISTIC_EXCESS_MULTIPLIER = 2;
	private static final int FRAMING_BITS_LEN = 8;

	private byte[] bitsToSend;
	private int bitsToSendLength;
	private int successiveOnes;

	public byte[] encode(byte[] messageToSend) {
		bitsToSendLength = 0;
		int crc16 = Crc16Ccitt.calculateReverse(messageToSend);
		int requiredBitsToSendLength = (messageToSend.length + CRC16_LEN_BYTES) * BITS_IN_BYTE * BIT_STUFFING_PESSIMISTIC_EXCESS_MULTIPLIER + 2 * FRAMING_BITS_LEN;
		// init new buffer only if previous was smaller
		if (bitsToSend == null || requiredBitsToSendLength > bitsToSend.length) {
			bitsToSend = new byte[requiredBitsToSendLength];
		}

		appendNonStuffed(0x7E);
		for (int i = 0; i < messageToSend.length; i++) {
			appendStuffed(messageToSend[i] & 0xFF);
		}
		appendStuffed(crc16 & 0xFF);
		appendStuffed((crc16 >> 8) & 0xFF);
		appendNonStuffed(0x7E);

		byte[] result = new byte[bitsToSendLength];
		System.arraycopy(bitsToSend, 0, result, 0, result.length);
		return result;
	}

	private void appendStuffed(int curByte) {
		for (int i = 0; i < BITS_IN_BYTE; i++) {
			byte curBit = (byte) ((curByte >> i) & 0x1);
			if (curBit == 1) {
				successiveOnes++;
			} else {
				successiveOnes = 0;
			}
			bitsToSend[bitsToSendLength] = curBit;
			bitsToSendLength++;
			if (successiveOnes == 5) {
				bitsToSend[bitsToSendLength] = 0;
				bitsToSendLength++;
				successiveOnes = 0;
			}
		}
	}

	private void appendNonStuffed(int curByte) {
		for (int i = 0; i < BITS_IN_BYTE; i++) {
			bitsToSend[bitsToSendLength] = (byte) ((curByte >> i) & 0x1);
			bitsToSendLength++;
		}
	}

}

@@ -316,16 +316,71 @@
 N = 8;%0A%0A
+%09private final int prepend;%0A%09private final int append;%0A
 %09private
@@ -460,16 +460,167 @@
 eOnes;%0A%0A
+%09public HdlcTransmitter() %7B%0A%09%09this(0, 0);%0A%09%7D%0A%0A%09public HdlcTransmitter(int prepend, int append) %7B%0A%09%09this.prepend = prepend;%0A%09%09this.append = append;%0A%09%7D%0A%0A
 %09public 
@@ -1080,16 +1080,85 @@
 %5D;%0A%09%09%7D%0A%0A
+%09%09for (int i = 0; i %3C prepend; i++) %7B%0A%09%09%09appendNonStuffed(0x7E);%0A%09%09%7D%0A
 %09%09append
@@ -1367,16 +1367,84 @@
 d(0x7E);
+%0A%09%09for (int i = 0; i %3C append; i++) %7B%0A%09%09%09appendNonStuffed(0x7E);%0A%09%09%7D
 %0A%0A%09%09byte

support prepend and append hdlc tags