/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.solr.common.util;

import java.io.*;

/** Single threaded buffered InputStream
 *  Internal Solr use only, subject to change.
 */
public class FastInputStream extends DataInputInputStream {
  protected final InputStream in;
  protected final byte[] buf;
  protected int pos;
  protected int end;
  protected long readFromStream; // number of bytes read from the underlying inputstream

  public FastInputStream(InputStream in) {
  // use default BUFSIZE of BufferedOutputStream so if we wrap that
  // it won't cause double buffering.
    this(in, new byte[8192], 0, 0);
  }

  public FastInputStream(InputStream in, byte[] tempBuffer, int start, int end) {
    this.in = in;
    this.buf = tempBuffer;
    this.pos = start;
    this.end = end;
  }


  public static FastInputStream wrap(InputStream in) {
    return (in instanceof FastInputStream) ? (FastInputStream)in : new FastInputStream(in);
  }

  @Override
  public int read() throws IOException {
    if (pos >= end) {
      refill();
      if (pos >= end) return -1;
    }
    return buf[pos++] & 0xff;     
  }

  public int peek() throws IOException {
    if (pos >= end) {
      refill();
      if (pos >= end) return -1;
    }
    return buf[pos] & 0xff;
  }


  @Override
  public int readUnsignedByte() throws IOException {
    if (pos >= end) {
      refill();
      if (pos >= end) {
        throw new EOFException();
      }
    }
    return buf[pos++] & 0xff;
  }

  public int readWrappedStream(byte[] target, int offset, int len) throws IOException {
    return in.read(target, offset, len);
  }

  public long position() {
    return readFromStream - (end - pos);
  }

  public void refill() throws IOException {
    // this will set end to -1 at EOF
    end = readWrappedStream(buf, 0, buf.length);
    if (end > 0) readFromStream += end;
    pos = 0;
  }

  @Override
  public int available() throws IOException {
    return end - pos;
  }

  @Override
  public int read(byte b[], int off, int len) throws IOException {
    int r=0;  // number of bytes we have read

    // first read from our buffer;
    if (end-pos > 0) {
      r = Math.min(end-pos, len);
      System.arraycopy(buf, pos, b, off, r);
      pos += r;
    }

    if (r == len) return r;

    // amount left to read is >= buffer size
    if (len-r >= buf.length) {
      int ret = readWrappedStream(b, off+r, len-r);
      if (ret >= 0) {
        readFromStream += ret;
        r += ret;
        return r;
      } else {
        // negative return code
        return r > 0 ? r : -1;
      }
    }

    refill();

    // read rest from our buffer
    if (end-pos > 0) {
      int toRead = Math.min(end-pos, len-r);
      System.arraycopy(buf, pos, b, off+r, toRead);
      pos += toRead;
      r += toRead;
      return r;
    }

    return r > 0 ? r : -1;
  }

  @Override
  public void close() throws IOException {
    in.close();
  }

  @Override
  public void readFully(byte b[]) throws IOException {
    readFully(b, 0, b.length);
  }

  @Override
  public void readFully(byte b[], int off, int len) throws IOException {
    while (len>0) {
      int ret = read(b, off, len);
      if (ret==-1) {
        throw new EOFException();
      }
      off += ret;
      len -= ret;
    }
  }

  @Override
  public int skipBytes(int n) throws IOException {
    if (end-pos >= n) {
      pos += n;
      return n;
    }

    if (end-pos<0) return -1;
    
    int r = end-pos;
    pos = end;

    while (r < n) {
      refill();
      if (end-pos <= 0) return r;
      int toRead = Math.min(end-pos, n-r);
      r += toRead;
      pos += toRead;
    }

    return r;
  }

  @Override
  public boolean readBoolean() throws IOException {
    return readByte()==1;
  }

  @Override
  public byte readByte() throws IOException {
    if (pos >= end) {
      refill();
      if (pos >= end) throw new EOFException();
    }
    return buf[pos++];
  }


  @Override
  public short readShort() throws IOException {
    return (short)((readUnsignedByte() << 8) | readUnsignedByte());
  }

  @Override
  public int readUnsignedShort() throws IOException {
    return (readUnsignedByte() << 8) | readUnsignedByte();
  }

  @Override
  public char readChar() throws IOException {
    return (char)((readUnsignedByte() << 8) | readUnsignedByte());
  }

  @Override
  public int readInt() throws IOException {
    return  ((readUnsignedByte() << 24)
            |(readUnsignedByte() << 16)
            |(readUnsignedByte() << 8)
            | readUnsignedByte());
  }

  @Override
  public long readLong() throws IOException {
    return  (((long)readUnsignedByte()) << 56)
            | (((long)readUnsignedByte()) << 48)
            | (((long)readUnsignedByte()) << 40)
            | (((long)readUnsignedByte()) << 32)
            | (((long)readUnsignedByte()) << 24)
            | (readUnsignedByte() << 16)
            | (readUnsignedByte() << 8)
            | (readUnsignedByte());
  }

  @Override
  public float readFloat() throws IOException {
    return Float.intBitsToFloat(readInt());    
  }

  @Override
  public double readDouble() throws IOException {
    return Double.longBitsToDouble(readLong());    
  }

  @Override
  public String readLine() throws IOException {
    throw new UnsupportedOperationException();
  }

  @Override
  public String readUTF() throws IOException {
    return new DataInputStream(this).readUTF();
  }
}
