package com.jscape.inet.ssh.protocol.v2.marshaling.algorithms.zlib;

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

public class GZIPInputStream
        extends InflaterInputStream {

    public GZIPInputStream(InputStream in)
            throws IOException {
        this(in, DEFAULT_BUFSIZE, true);
    }

    public GZIPInputStream(InputStream in,
                           int size,
                           boolean closeIn)
            throws IOException {
        this(in, new Inflater(15 + 16), size, closeIn);
        myinflater = true;
    }

    public GZIPInputStream(InputStream in,
                           Inflater inflater,
                           int size,
                           boolean closeIn)
            throws IOException {
        super(in, inflater, size, closeIn);
    }

    public long getModifiedtime() {
        return inflater.istate.getGZIPHeader().getModifiedTime();
    }

    public int getOS() {
        return inflater.istate.getGZIPHeader().getOS();
    }

    public String getName() {
        return inflater.istate.getGZIPHeader().getName();
    }

    public String getComment() {
        return inflater.istate.getGZIPHeader().getComment();
    }

    public long getCRC()
            throws GZIPException {
        if (inflater.istate.mode != 12 /*DONE*/) {
            throw new GZIPException("checksum is not calculated yet.");
        }

        return inflater.istate.getGZIPHeader().getCRC();
    }

    public void readHeader()
            throws IOException {

        byte[] empty = new byte[0];
        inflater.setOutput(empty, 0, 0);
        inflater.setInput(empty, 0, 0, false);

        byte[] b = new byte[10];

        int n = fill(b);
        if (n != 10) {
            if (n > 0) {
                inflater.setInput(b, 0, n, false);
                //inflater.next_in_index = n;
                inflater.nextInIndex = 0;
                inflater.availIn = n;
            }
            throw new IOException("no input");
        }

        inflater.setInput(b, 0, n, false);

        byte[] b1 = new byte[1];
        do {
            if (inflater.availIn <= 0) {
                int i = in.read(b1);
                if (i <= 0) {
                    throw new IOException("no input");
                }
                inflater.setInput(b1, 0, 1, true);
            }

            int err = inflater.inflate(JZlib.Z_NO_FLUSH);

            if (err != 0/*Z_OK*/) {
                int len = 2048 - inflater.nextIn.length;
                if (len > 0) {
                    byte[] tmp = new byte[len];
                    n = fill(tmp);
                    if (n > 0) {
                        inflater.availIn += inflater.nextInIndex;
                        inflater.nextInIndex = 0;
                        inflater.setInput(tmp, 0, n, true);
                    }
                }
                //inflater.next_in_index = inflater.next_in.length;
                inflater.availIn += inflater.nextInIndex;
                inflater.nextInIndex = 0;
                throw new IOException(inflater.msg);
            }
        }
        while (inflater.istate.inParsingHeader());
    }

    private int fill(byte[] buf) {
        int len = buf.length;
        int n = 0;
        do {
            int i = -1;
            try {
                i = in.read(buf, n, buf.length - n);
            } catch (IOException e) {
                // todo: ignore?
            }
            if (i == -1) {
                break;
            }
            n += i;
        }
        while (n < len);
        return n;
    }
}