package genesom;


import java.io.Reader;
import java.io.LineNumberReader;
import java.io.InputStreamReader;
import java.util.Vector;
import java.util.StringTokenizer;
import java.util.NoSuchElementException;


public class InputPatterns {

  public final static String DEFAULT_COMMENT_INDICATOR = "#";

  protected double[][] data;
  protected double[] first;
  protected int cols;
  protected int rows;
  protected String delimiters;
  protected String comment_indicator;
  protected boolean blockmode;
  protected ShuffleIndex shuffle_index;
  protected LineNumberReader in;

  public InputPatterns(Reader source)
    throws java.io.IOException
  {
    this(source, " \t\n\r\f");
  }


  public InputPatterns(Reader source, String delimiters)
    throws java.io.IOException
  {
    this(source, delimiters, DEFAULT_COMMENT_INDICATOR);
  }


  public InputPatterns(Reader source,
                       String delimiters,
                       String comment_indicator)

  {
    this.delimiters = delimiters;
    this.comment_indicator = comment_indicator;
    in = new LineNumberReader(source);
    first = next();
  }


  public double[] next() {

    if(blockmode) {

      if(shuffle_index == null) shuffle_index = new ShuffleIndex(rows);

      return data[shuffle_index.next()];

    }
    else {

      double[] columns = null;

      if(first != null) { columns = first; first = null; return columns; }

      String line = "(empty)";

      try {

        while( (line = in.readLine()) != null &&
               (line = line.trim()).startsWith(comment_indicator));

        if(line != null) {

          StringTokenizer st = new StringTokenizer(line, delimiters);

          if(cols == 0) cols = st.countTokens();

          columns = new double[cols];

          for(int i = 0; i < cols; i++)
            columns[i] = new Double(st.nextToken()).doubleValue();
        }
      }
      catch(Exception nse) {
        System.err.println("Unexpected value in line " + in.getLineNumber());
        System.err.println(">>\t" + line);
      }

      return columns;
    }
  }


  public void blockMode() {

    double[] row;

    Vector rows = new Vector();


    while((row = next()) != null)
       rows.addElement(row);

    data = new double[this.rows = rows.size()][];

    rows.copyInto(data);

    rows.removeAllElements();

    blockmode = true;
  }

  /******************************************************/

  public int numberOfColumns() { return cols; }
  public int numberOfRows()    { return blockmode ? rows : 1; }

  /******************************************************/


  public double[] row(int row) { return blockmode ? data[row] : null; }


  public double[] column(int column)
  {

    if(!blockmode) return null;

    double[] res = new double[rows];

    for(int i = 0; i < rows; i++) res[i] = data[i][column];

    return res;
  }


  public double[][] matrix()
  {
    return data;
  }


}

