/*
 * Copyright (c) 2002-2009 JSCAPE
 * 1147 S. 53rd Pl., Mesa, Arizona, 85206, U.S.A.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * JSCAPE. ("Confidential Information").  You shall not disclose such
 * Confidential Information and shall use it only in accordance with
 *  the terms of the license agreement you entered into with JSCAPE.
 */

package com.jscape.util.io;

import com.jscape.util.Limit;

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

import static com.jscape.util.Parameters.assertNotNull;

/**
 * @author Alex Usun
 */
public class LimitedInputStream
        extends InputStream {

    protected final InputStream base;
    protected final Limit limit;
    protected final boolean owner;

    public LimitedInputStream(InputStream base, long limit, boolean owner) {
        assertNotNull(base);
        this.base = base;

        this.limit = new Limit(limit);
        this.owner = owner;
    }

    @Override
    public int available()
            throws IOException {
        return (int) Math.min(this.limit.remained(), this.base.available());
    }

    public int read()
            throws IOException {
        if (this.limit.isExceeded()) {
            return -1;
        }

        int ret = this.base.read();
        this.limit.increment();

        return ret;
    }

    @Override
    public int read(byte[] buffer, int offset, int length)
            throws IOException {
        if (this.limit.isExceeded()) {
            return -1;
        }

        length = (int) Math.min(this.limit.remained(), length);
        int ret = this.base.read(buffer, offset, length);

        if (ret != -1) {
            this.limit.increment(ret);
        }

        return ret;
    }

    @Override
    public void close()
            throws IOException {
        if (this.owner) {
            this.base.close();
        }
    }

    public long remained() {
        return this.limit.remained();
    }

    @Override
    public String toString() {
        return "LimitedInputStream {"
                + "base=" + this.base
                + ", limit=" + this.limit
                + ", owner=" + this.owner
                + '}';
    }
}
