package org.gnu.readline;

import java.io.File;
import java.io.Reader;
import java.io.IOException;
import java.io.EOFException;
import java.io.UnsupportedEncodingException;

/**
 * A <code>Reader</code> wrapper for the Readline classes.  This seems
 * to work fine in conjunction with such classes as BufferedReader,
 * but it hasn't been tested well enough to see if this will work well
 * in all cases.
 *
 * This was implemented to make it easier to supplant Readline's
 * functionality [shrug] anywhere and everywhere, but specifically in
 * <a href="http://www.beanshell.org">BeanShell</a>.
 *
 * @version $Revision: 1.2 $
 * @author Shane Celis <shane@terrapsring.com>
 **/

public class ReadlineReader extends Reader {

  public static final String DEFAULT_PROMPT = "";
  private StringBuffer iBuff;	
  private String       iLineSeparator;
  private String iPrompt;
  private File iHistoryFile;
  
  /**
   * Constructs a ReadlineReader object with the given prompt.
   **/
  
  public ReadlineReader(String prompt,ReadlineLibrary lib) { 
    iBuff = new StringBuffer();
    setPrompt(prompt);
    Readline.load(lib);
    Readline.initReadline("ReadlineReader");
    iLineSeparator = System.getProperty("line.separator", "\n");
  }

  /**
   * Constructs a ReadlineReader object with the default prompt.
   **/

  public ReadlineReader(ReadlineLibrary lib) {
    this(DEFAULT_PROMPT,lib);
  }

  /**
   * Constructs a ReadlineReader object with an associated history
   * file.
   **/

  public ReadlineReader(File history,ReadlineLibrary lib) throws IOException {
    this(DEFAULT_PROMPT,lib);
    Readline.readHistoryFile(history.getAbsolutePath());
    iHistoryFile = history; // only set this if we can read the file
  }

  /**
   * Constructs a ReadlineReader object with an associated history
   * file and prompt.
   **/

  public ReadlineReader(String prompt, File history,ReadlineLibrary lib)
                                                         throws IOException {
    this(history,lib);
    setPrompt(prompt);
  }

  /**
   * Returns the current prompt.
   **/

  public String getPrompt() {
    return iPrompt;
  }
    
  /**
   * Sets the prompt to the given value.
   **/

  public void setPrompt(String prompt) {
    iPrompt = prompt;
  }

  /**
   * Reads what's given from <code>readline()</code> into a buffer.
   * When that buffer is emptied, <code>readline()</code> is called
   * again to replenish that buffer.  This seems to work fine in
   * conjunction with such classes as BufferedReader, but it hasn't
   * been tested well enough to see if this will work well in all
   * cases.
   **/

  public int read(char[] cbuf, int off, int len) 
    throws IOException {
    try {
      if (iBuff.length() == 0) {
	String line = Readline.readline(iPrompt);
	iBuff.append((line == null ? "" : line) + iLineSeparator);
      }
      if (len > iBuff.length())
	len = iBuff.length();
      if (len == 0) 
	return 0;
      char[] sbuf = iBuff.substring(0, len).toCharArray();
      System.arraycopy(sbuf, 0, cbuf, off, len);
      iBuff.delete(0, len);
      return len;
    } catch (EOFException eof) {
      throw eof;
    } catch (UnsupportedEncodingException uee) {
      throw uee;
    }
  }

  /**
   * Nullifies all buffers and writes history file if one was given
   * at construction time.
   **/

  public void close()
    throws IOException {
    iBuff = null;
    iPrompt = null;
    if (iHistoryFile != null) {
      Readline.writeHistoryFile(iHistoryFile.getAbsolutePath());
      iHistoryFile = null;
    }
  }

  public static void main(String[] args) throws Exception {
    java.io.BufferedReader rd = 
      new java.io.BufferedReader(new 
	  ReadlineReader("hmm ", new File("test"),ReadlineLibrary.GnuReadline));
    String line;
    try {
      while ((line = rd.readLine()) != null) {
	System.out.println("got: " + line);
      }
    } finally {
      rd.close();
    }
  }
}

