package wc;

import java.io.FilterReader;
import java.io.IOException;
import java.io.Reader;

/**
 * Kleine Unterklasse von <tt>java.io.FilterReader</tt>
 * die die Wort-, Zeilen- und Zeichenanzahl einer Datei feststellen kann,
 * waehrend die Datei ausgelesen wird.
 * @author  Ralf Kunze (rkunze@uos.de), Institut fuer Informatik, Universitaet Osnabrueck
 * @version 
 */
public class CountedReader extends FilterReader {
  /**
   * Systemabhaengiger Zeilentrenner
   */
  public final static char linesep;

  /*
   * Statischer Konstruktor:
   * Dieser Konstruktor wird einmal zur Ladezeit der Klasse ausgefuehrt.
   */
  static {
    String str = System.getProperty("line.separator");
    //Nur das letzte Zeichen nehmen.
    linesep = str.charAt(str.length() - 1);
  }

  /**
   * Anzahl der gezaehlten Woerter.
   */
  private long words;

  /**
   * Gibt an, ob man sich innerhalb eines Worters befindet.
   */
  private boolean inWord = false;

  /**
   * Zeilenanzahl
   */
  private long lines;

  /**
   * Zeichenanzahl
   */
  private long chars;

  /**
   * Initialisiert einen neuen CountedReader (filter reader).
   */
  public CountedReader(Reader in) {
    super(in);
  }

  /**
   * Setzt die Zaehlvariablen zurueck.
   */
  public void resetCounters() {
    words = lines = chars = 0;
  }

  /**
   * Gibt die bisher ermittelte Zeilenanzahl zurueck.
   * 
   * @see #lines
   */
  public long getLineCounter() {
    return lines;
  }

  /**
   * Gibt die bisher ermittelte Wortanzahl zurueck.
   * 
   * @see #words
   */
  public long getWordCounter() {
    return words;
  }

  /**
   * Gibt die bisher ermittelte Zeichenanzahl zurueck.
   * 
   * @see #chars
   */
  public long getCharCounter() {
    return chars;
  }

  /**
   * Liest das naechste Zeichen
   * 
   * @return das naechste Zeichen oder <tt>-1</tt> am Ende der Datei
   */
  public int read() throws IOException {
    int chr = in.read();

    if ( (Character.isWhitespace(chr) ) && inWord) {
      ++words;
      inWord = false;
    } else if(!Character.isWhitespace(chr)) 
      inWord = true;
    
    if (chr == linesep) 
      ++lines; // end of line
    
    if (chr != -1)
      ++chars; // don't count EOF

    return chr;
  }

  /**
   * Liest einen Block von char in einen Teil eines Arrays.
   * 
   * @param buffer
   *            Puffer in den die Daten eingelesen werden
   * @param offset
   *            Offset ab dem in das Array geschrieben werden soll
   * @param length
   *            Anzahl der Zeichen die maximal geschrieben werden koennen
   * @return Anzahl der ausgelesenen Zeichen
   */
  public int read(char buffer[], int offset, int length) throws IOException {
    int len = in.read(buffer, offset, length);

    for (int i = 0; i < len; ++i) {
      // end of line?
      if (buffer[offset + i] == linesep)
        ++lines;
      
      if (Character.isWhitespace(buffer[offset + i]) && inWord) {
        ++words;
        inWord = false;
      } else if(!Character.isWhitespace(buffer[offset+i])) 
        inWord = true;
    }

    if (len != -1)
      chars += len; // don't count EOF
    return len;
  }
  
//  public int read(char[] buffer) throws IOException {
//    return read(buffer,0,buffer.length);
//  }
}
