package org.oskari.wcs.geotiff;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;

/**
 * Very basic TIFF file reader
 *
 * For a nice summary of the TIFF file format
 * @see http://www.fileformat.info/format/tiff/egff.htm
 */
public class TIFFReader {

    private final ByteBuffer bb;
    private final List<IFD> ifds;

    public TIFFReader(byte[] b) throws IllegalArgumentException {
        this(ByteBuffer.wrap(b));
    }

    public TIFFReader(ByteBuffer bb) throws IllegalArgumentException {
        this.bb = bb;
        parseHeader();
        ifds = new ArrayList<>();
        parseIFDs();
    }

    private void parseHeader() throws IllegalArgumentException {
        ByteOrder order;

        bb.position(0);
        int bom = bb.getShort() & 0xffff;
        switch (bom) {
        case 0x4949:
            order = ByteOrder.LITTLE_ENDIAN;
            break;
        case 0x4D4D:
            order = ByteOrder.BIG_ENDIAN;
            break;
        default:
            throw new IllegalArgumentException("Invalid byte order value " + bom);
        }

        bb.order(order);

        if ((bb.getShort() & 0xffff) != 42) {
            throw new IllegalArgumentException("Magic version number wasn't 42!");
        }
    }

    private void parseIFDs() {
        // TIFF file can contain zero images
        // offset should be handled as uint32
        int off;
        while ((off = bb.getInt()) != 0) {
            ifds.add(new IFD(bb, off));
        }
    }

    public int getIFDCount() {
        return ifds.size();
    }

    public IFD getIFD(int i) {
        return ifds.get(i);
    }

    public void readTile(int ifdIdx, int tileIdx, float[] dst)
            throws IllegalArgumentException {
        IFD ifd = ifds.get(ifdIdx);

        if (ifd.getTileOffsets() == null) {
            throw new IllegalArgumentException("Specified IFD is not tiled");
        }

        for (int sf : ifd.getSampleFormat()) {
            if (sf != 3) {
                throw new IllegalArgumentException("Specified IFD sampleFormat is not Float32");
            }
        }

        ByteBuffer.wrap(getTileData(ifd, tileIdx, null))
                .order(bb.order())
                .asFloatBuffer()
                .get(dst);
    }

    private byte[] getTileData(IFD ifd, int tileIdx, byte[] data)
            throws IllegalArgumentException {
        int off = ifd.getTileOffsets()[tileIdx];
        int len = ifd.getTileByteCounts()[tileIdx];

        int c = ifd.getCompression();
        switch (c) {
        case 1:
            if (data == null || data.length != len) {
                data = new byte[len];
            }
            bb.position(off);
            bb.get(data);
            break;
        default:
            throw new IllegalArgumentException("Can't decompress compression " + c);
        }

        return data;
    }

}

@@ -1650,32 +1650,1246 @@
 .get(i);%0A    %7D%0A%0A
+    public void readStrip(int ifdIdx, int stripIdx, float%5B%5D dst) %7B%0A        IFD ifd = ifds.get(ifdIdx);%0A%0A        if (ifd.getStripOffsets() == null) %7B%0A            throw new IllegalArgumentException(%22Specified IFD is not striped%22);%0A        %7D%0A%0A        for (int sf : ifd.getSampleFormat()) %7B%0A            if (sf != 3) %7B%0A                throw new IllegalArgumentException(%22Specified IFD sampleFormat is not Float32%22);%0A            %7D%0A        %7D%0A%0A        ByteBuffer.wrap(getStripData(ifd, stripIdx, null))%0A                .order(bb.order())%0A                .asFloatBuffer()%0A                .get(dst);%0A    %7D%0A%0A    private byte%5B%5D getStripData(IFD ifd, int stripIdx, byte%5B%5D data)%0A            throws IllegalArgumentException %7B%0A        int off = ifd.getStripOffsets()%5BstripIdx%5D;%0A        int len = ifd.getStripByteCounts()%5BstripIdx%5D;%0A%0A        int c = ifd.getCompression();%0A        switch (c) %7B%0A        case 1:%0A            if (data == null %7C%7C data.length != len) %7B%0A                data = new byte%5Blen%5D;%0A            %7D%0A            bb.position(off);%0A            bb.get(data);%0A            break;%0A        default:%0A            throw new IllegalArgumentException(%22Can't decompress compression %22 + c);%0A        %7D%0A%0A        return data;%0A    %7D%0A%0A
     public void 

Add readStrip() to TIFFReader