package com.google.android.exoplayer2.metadata.dvbsi;

import com.google.android.exoplayer2.metadata.Metadata;
import com.google.android.exoplayer2.metadata.MetadataDecoder;
import com.google.android.exoplayer2.metadata.MetadataInputBuffer;
import com.google.android.exoplayer2.util.ParsableByteArray;
import com.google.android.exoplayer2.util.TimestampAdjuster;

import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.ArrayList;

public class AitDecoder implements MetadataDecoder {
    // Specification of AIT can be found in 5.3.4 of TS 102 809 v1.1.1
    // https://www.etsi.org/deliver/etsi_ts/102800_102899/102809/01.01.01_60/ts_102809v010101p.pdf
    private final static int DESCRIPTOR_TRANSPORT_PROTOCOL = 0x02;

    private final static int DESCRIPTOR_SIMPLE_APPLICATION_LOCATION = 0x15;

    private final static int TRANSPORT_PROTOCOL_HTTP = 3;

    private TimestampAdjuster timestampAdjuster;

    private final ParsableByteArray sectionData;

    public AitDecoder() {
        sectionData = new ParsableByteArray();
    }

    @Override
    public Metadata decode(MetadataInputBuffer inputBuffer) {
        if (timestampAdjuster == null
                || inputBuffer.subsampleOffsetUs != timestampAdjuster.getTimestampOffsetUs()) {
            timestampAdjuster = new TimestampAdjuster(inputBuffer.timeUs);
            timestampAdjuster.adjustSampleTimestamp(inputBuffer.timeUs - inputBuffer.subsampleOffsetUs);
        }

        ByteBuffer buffer = inputBuffer.data;
        byte[] data = buffer.array();
        int size = buffer.limit();
        sectionData.reset(data, size);

        int tableId = sectionData.peekUnsignedByte();

        //Only this table is allowed in AIT streams
        if (tableId == 0x74) {
            return parseAit(sectionData);
        }

        return new Metadata();
    }

    private Metadata parseAit(ParsableByteArray sectionData) {
        int tmp;

        int tableId = sectionData.readUnsignedByte();

        tmp = sectionData.readUnsignedShort();
        int endOfSection = sectionData.getPosition() + (tmp & 4095) - 4 /* Ignore leading CRC */;

        tmp = sectionData.readUnsignedShort();
        int applicationType = tmp & 0x7fff;

        tmp = sectionData.readUnsignedByte();
        int versionNumber = (tmp & 0x3e) >> 1;
        boolean current = (tmp & 1) == 1;

        int section_number = sectionData.readUnsignedByte();
        int last_section_number = sectionData.readUnsignedByte();

        tmp = sectionData.readUnsignedShort();
        int commonDescriptorsLength = tmp & 4095;

        //Since we currently only keep url and control code, which are unique per application,
        //there is no useful information in common descriptor.
        sectionData.skipBytes(commonDescriptorsLength);

        tmp = sectionData.readUnsignedShort();
        int appLoopLength = tmp & 4095;

        ArrayList<Ait> aits = new ArrayList<>();
        while(sectionData.getPosition() < endOfSection) {
            // Values that will be stored in Ait()
            String aitUrlBase = null;
            String aitUrlExtension = null;
            int aitControlCode = -1;

            long application_identifier = sectionData.readUnsignedInt24() << 24L;
            application_identifier |= sectionData.readUnsignedInt24();
            int controlCode = sectionData.readUnsignedByte();

            aitControlCode = controlCode;

            tmp = sectionData.readUnsignedShort();
            int sectionLength = tmp & 4095;
            int positionOfNextSection = sectionData.getPosition() + sectionLength;
            while(sectionData.getPosition() < positionOfNextSection) {
                int type = sectionData.readUnsignedByte();
                int l = sectionData.readUnsignedByte();
                int positionOfNextSection2 = sectionData.getPosition() + l;

                if(type == DESCRIPTOR_TRANSPORT_PROTOCOL) {
                    int protocolId = sectionData.readUnsignedShort();
                    int label = sectionData.readUnsignedByte();

                    if(protocolId == TRANSPORT_PROTOCOL_HTTP) {
                        while (sectionData.getPosition() < positionOfNextSection2) {
                            int urlBaseLength = sectionData.readUnsignedByte();
                            String urlBase = sectionData.readString(urlBaseLength);
                            int extensionCount = sectionData.readUnsignedByte();
                            aitUrlBase = urlBase;
                            for (int i = 0; i < extensionCount; i++) {
                                int len = sectionData.readUnsignedByte();
                                sectionData.skipBytes(len);
                            }
                        }
                    }
                } else if(type == DESCRIPTOR_SIMPLE_APPLICATION_LOCATION) {
                    String url = sectionData.readString(l);
                    aitUrlExtension = url;
                }

                sectionData.setPosition(positionOfNextSection2);
            }

            sectionData.setPosition(positionOfNextSection);

            if(aitControlCode != -1 && aitUrlBase != null && aitUrlExtension != null) {
                aits.add(new Ait(aitControlCode, aitUrlBase + aitUrlExtension));
            }
        }

        return new Metadata(aits);
    }

    static final String dvbCharset[] = {
        "ISO-8859-15",
        "ISO-8859-5",
        "ISO-8859-6",
        "ISO-8859-7",
        "ISO-8859-8",
        "ISO-8859-9",
        null,
        "ISO-8859-11",
        null,
        "ISO-8859-13",
        null,
        "ISO-8859-15",
        null,
        null,
        null,
        null,
        //0x10
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        null,
    };

    static String readDvbString(ParsableByteArray data, int length) {
        if(length == 0) return null;
        int charsetSelect = data.peekUnsignedByte();
        if(charsetSelect >= 0x20)
            return data.readString(length, Charset.forName("ISO-8859-15"));
        data.skipBytes(1);
        if(charsetSelect == 0x1f) {
            data.skipBytes(length - 1);
            return null;
        }
        if(charsetSelect != 0x10)
            return data.readString(length-1, Charset.forName(dvbCharset[charsetSelect]));
        if(length == 2) {
            data.skipBytes(1);
            return null;
        }
        charsetSelect = data.readUnsignedShort();
        if(charsetSelect > 1 && charsetSelect < 0x10) {
            String charsetName = "ISO-8859-" + charsetSelect;
            return data.readString(length-3, Charset.forName(charsetName));
        }
        return null;
    }
}

@@ -5360,1499 +5360,6 @@
  %7D%0A%0A
-    static final String dvbCharset%5B%5D = %7B%0A        %22ISO-8859-15%22,%0A        %22ISO-8859-5%22,%0A        %22ISO-8859-6%22,%0A        %22ISO-8859-7%22,%0A        %22ISO-8859-8%22,%0A        %22ISO-8859-9%22,%0A        null,%0A        %22ISO-8859-11%22,%0A        null,%0A        %22ISO-8859-13%22,%0A        null,%0A        %22ISO-8859-15%22,%0A        null,%0A        null,%0A        null,%0A        null,%0A        //0x10%0A        null,%0A        null,%0A        null,%0A        null,%0A        null,%0A        null,%0A        null,%0A        null,%0A        null,%0A        null,%0A        null,%0A        null,%0A        null,%0A        null,%0A        null,%0A        null,%0A    %7D;%0A%0A    static String readDvbString(ParsableByteArray data, int length) %7B%0A        if(length == 0) return null;%0A        int charsetSelect = data.peekUnsignedByte();%0A        if(charsetSelect %3E= 0x20)%0A            return data.readString(length, Charset.forName(%22ISO-8859-15%22));%0A        data.skipBytes(1);%0A        if(charsetSelect == 0x1f) %7B%0A            data.skipBytes(length - 1);%0A            return null;%0A        %7D%0A        if(charsetSelect != 0x10)%0A            return data.readString(length-1, Charset.forName(dvbCharset%5BcharsetSelect%5D));%0A        if(length == 2) %7B%0A            data.skipBytes(1);%0A            return null;%0A        %7D%0A        charsetSelect = data.readUnsignedShort();%0A        if(charsetSelect %3E 1 && charsetSelect %3C 0x10) %7B%0A            String charsetName = %22ISO-8859-%22 + charsetSelect;%0A            return data.readString(length-3, Charset.forName(charsetName));%0A        %7D%0A        return null;%0A    %7D%0A
 %7D%0A

Remove dead-code readDvbString