/*
 *  gnu/regexp/CharIndexedReader.java
 *  Copyright (C) 1998-2001 Wes Biggs
 *
 *  This library is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published
 *  by the Free Software Foundation; either version 2.1 of the License, or
 *  (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

package gnu.regexp;
import java.io.InputStream;
import java.io.BufferedInputStream;
import java.io.IOException;

// FIXME: Integer.MAX_VALUE is a hack
// TODO: move(x) shouldn't rely on calling next() x times

class CharIndexedInputStream implements CharIndexed {
  private static final int BUFFER_INCREMENT = 1024;

  private BufferedInputStream br;
  private int m_index, m_end, m_bufsize;
  private char cached;
  
  CharIndexedInputStream(InputStream str, int index) {
    if (str instanceof BufferedInputStream) br = (BufferedInputStream) str;
    else br = new BufferedInputStream(str,BUFFER_INCREMENT);
    m_bufsize = BUFFER_INCREMENT;
    m_index = -1;
    m_end = Integer.MAX_VALUE; // end is unknown
    next();
    if (index > 0) move(index);
  }

  private boolean next() {
    if (m_end == 1) return false;
    m_end--; // closer to end
    try {
      if (m_index != -1) {
	br.reset();
      }
      int i = br.read();
      br.mark(m_bufsize);
      if (i == -1) {
	m_end = 1;
	cached = CharIndexed.OUT_OF_BOUNDS;
	return false;
      }
      cached = (char) i;
      m_index = 1;
    } catch (IOException e) { 
      e.printStackTrace();
      cached = CharIndexed.OUT_OF_BOUNDS;
      return false; 
    }
    return true;
  }

  public char charAt(int index) {
    if (index == 0) return cached;
    if (index >= m_end) return CharIndexed.OUT_OF_BOUNDS;
    if (index >= m_bufsize) {
      // Allocate more space in the buffer.
      try {
	while (m_bufsize <= index) m_bufsize += BUFFER_INCREMENT;
	br.reset();
	br.mark(m_bufsize);
	br.skip(index-1);
      } catch (IOException e) { }
    } else if (m_index != index) {
      try {
	br.reset();
	br.skip(index-1);
      } catch (IOException e) { }
    }
    char ch = CharIndexed.OUT_OF_BOUNDS;

    try {
      int i = br.read();
      m_index = index+1; // m_index is index of next pos relative to charAt(0)
      if (i == -1) {
	// set flag that next should fail next time?
	m_end = index;
	return ch;
      }
      ch = (char) i;
    } catch (IOException ie) { }

    return ch;
  }

  public boolean move(int index) {
    // move read position [index] clicks from 'charAt(0)'
    boolean retval = true;
    while (retval && (index-- > 0)) retval = next();
    return retval;
  }

  public boolean isValid() {
    return (cached != CharIndexed.OUT_OF_BOUNDS);
  }
}

