package ru.r2cloud.jradio.blocks;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import ru.r2cloud.jradio.ByteInput;
import ru.r2cloud.jradio.Context;
import ru.r2cloud.jradio.Tag;

public class FixedLengthTagger implements ByteInput {

	public static final String BEGIN_SAMPLE = "beginSample";
	public static final String LENGTH = "length";

	private final ByteInput input;
	private final Context context;
	private int packet_len;
	private int read = 0;

	private List<Byte> packet;
	private int currentIndex = -1;
	private LinkedList<Byte> window;
	private List<Tag> currentTags = new ArrayList<>();

	public FixedLengthTagger(Context context, ByteInput input, int packet_len) {
		this.input = input;
		this.context = context;
		this.packet_len = packet_len;
		this.packet = new ArrayList<Byte>(packet_len);
		this.window = new LinkedList<Byte>();
	}

	@Override
	public byte readByte() throws IOException {
		// output current packet
		if (currentIndex >= 0 && currentIndex < packet.size()) {
			//indicate tag only for the first byte
			if( currentIndex > 0 ) {
				context.resetCurrent();
			}
			byte result = packet.get(currentIndex);
			currentIndex++;
			return result;
		}
		packet.clear();
		currentIndex = 0;
		// search for the next packet
		searchForNext: while (true) {
			byte curByte = input.readByte();
			window.offerLast(curByte);
			if (window.size() > packet_len) {
				window.removeFirst();
			}

			// tags are lazily calculated during readByte
			Tag tag = context.getCurrent();
			if (tag != null) {
				tag.put(BEGIN_SAMPLE, read);
				currentTags.add(tag);
			}
			
			if (!currentTags.isEmpty()) {
				Iterator<Tag> it = currentTags.iterator();
				while (it.hasNext()) {
					Tag cur = it.next();
					if ((Integer) cur.get(BEGIN_SAMPLE) + packet_len <= read + 1) {
						it.remove();
						packet.addAll(window);
						cur.put(LENGTH, packet_len);
						context.setCurrent(cur);
						read++;
						break searchForNext;
					}
				}
			}

			read++;
		}
		return readByte();
	}

	@Override
	public void close() throws IOException {
		input.close();
	}

}

@@ -115,37 +115,8 @@
 or;%0A
-import java.util.LinkedList;%0A
 impo
@@ -466,24 +466,30 @@
 t;%0A%09private 
+final 
 int packet_l
@@ -505,22 +505,28 @@
 ate 
+f
 in
-t read = 0;%0A
+al byte%5B%5D window;
 %0A%09pr
@@ -531,26 +531,28 @@
 private 
-List%3CByte%3E
+final byte%5B%5D
  packet;
@@ -565,31 +565,53 @@
 ate int 
-current
+read = 0;%0A%09private int window
 Index = 
 -1;%0A%09pri
@@ -606,11 +606,11 @@
 x = 
--1;
+0;%0A
 %0A%09pr
@@ -619,31 +619,29 @@
 ate 
-L
 in
-kedList%3CByte%3E window
+t currentIndex = -1
 ;%0A%09p
@@ -873,24 +873,13 @@
 new 
-ArrayList%3CByte%3E(
+byte%5B
 pack
@@ -880,25 +880,25 @@
 e%5Bpacket_len
-)
+%5D
 ;%0A%09%09this.win
@@ -911,26 +911,24 @@
 new 
-LinkedList%3CByte%3E()
+byte%5Bpacket_len%5D
 ;%0A%09%7D
@@ -1061,22 +1061,22 @@
  packet.
-size()
+length
 ) %7B%0A%09%09%09/
@@ -1197,21 +1197,17 @@
 = packet
-.get(
+%5B
 currentI
@@ -1210,17 +1210,17 @@
 entIndex
-)
+%5D
 ;%0A%09%09%09cur
@@ -1258,26 +1258,8 @@
 %09%09%7D%0A
-%09%09packet.clear();%0A
 %09%09cu
@@ -1271,17 +1271,18 @@
 Index = 
-0
+-1
 ;%0A%09%09// s
@@ -1388,90 +1388,110 @@
 ndow
-.offerLast(curByte)
+%5BwindowIndex%5D = curByte;%0A%09%09%09windowIndex++
 ;%0A%09%09%09if
- 
 (
+ 
 window
-.size() %3E packet_len) %7B%0A%09%09%09%09window.removeFirst()
+Index %3E= window.length ) %7B%0A%09%09%09%09windowIndex = 0
 ;%0A%09%09
@@ -1899,28 +1899,193 @@
 %09%09%09%09
-packet.addAll(window
+currentIndex = 0;%0A%09%09%09%09%09%09System.arraycopy(window, windowIndex, packet, 0, window.length - windowIndex);%0A%09%09%09%09%09%09System.arraycopy(window, 0, packet, window.length - windowIndex, windowIndex
 );%0A%09

replace collection with ring array