package com.brackeen.javagamebook.sound;

import java.io.FilterInputStream;
import java.io.InputStream;
import java.io.IOException;

/**
    Klasa FilteredSoundStream dziedziczy po FilterInputStream i przesyła
    wejściowy strumień dźwiękowy do SoundFilter.
    @see SoundFilter
*/
public class FilteredSoundStream extends FilterInputStream {

    private static final int REMAINING_SIZE_UNKNOWN = -1;

    private SoundFilter soundFilter;
    private int remainingSize;

    /**
        Tworzy nowy obiekt FilteredSoundStream z podanymi obiektami
        InputStream oraz SoundFilter.
    */
    public FilteredSoundStream(InputStream in,
        SoundFilter soundFilter)
    {
        super(in);
        this.soundFilter = soundFilter;
        remainingSize = REMAINING_SIZE_UNKNOWN;
    }

    /**
        Przesłania metodę z FilterInputStream w celu zastosowania filtra
        w czasie odczytu danych.
    */
    public int read(byte[] samples, int offset, int length)
        throws IOException
    {
        // Odczytuje i filtruje próbki dźwiękowe w strumieniu.
        int bytesRead = super.read(samples, offset, length);
        if (bytesRead > 0) {
            soundFilter.filter(samples, offset, bytesRead);
            return bytesRead;
        }

        // Jeżeli nie ma już bajtów w strumieniu dźwiękowym,
        // sprawdza, czy filtr nie zawiera dodatkowych bajtów ("echo").
        if (remainingSize == REMAINING_SIZE_UNKNOWN) {
            remainingSize = soundFilter.getRemainingSize();
            // Zaokrąglenie w dół do najbliższej wielokrotności 4
            // (typowa wielkość ramki).
            remainingSize = remainingSize / 4 * 4;
        }
        if (remainingSize > 0) {
            length = Math.min(length, remainingSize);

            // Czyszczenie bufora.
            for (int i=offset; i<offset+length; i++) {
                samples[i] = 0;
            }

            // Filtrowanie pozostałych bajtów.
            soundFilter.filter(samples, offset, length);
            remainingSize-=length;

            // Koniec.
            return length;
        }
        else {
            // Koniec strumienia.
            return -1;
        }
    }
}
