package io;

import java.io.BufferedReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.NoSuchElementException;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import lexicon.Categories;
import lexicon.Category;

public class Sentences implements Iterator<Sentence> {
	private int MAX_WORDS;
	private BufferedReader in;
	private BufferedReader stagsIn;
	private Categories categories;
	private Sentence next;

	private boolean sentenceRead = false;

	public static final Logger logger = LogManager.getLogger(Sentences.class);

	public Sentences(BufferedReader in,
			BufferedReader stagsIn,
			Categories categories,
			int MAX_WORDS) {
		this.MAX_WORDS = MAX_WORDS;
		this.in = in;
		this.stagsIn = stagsIn;
		this.categories = categories;
	}

	public void skip(int n) {
		for ( int i = 0; i < n; i++ ) {
			readSentence();
		}
	}

	private void readSentence() {
		Sentence sentence = new Sentence(MAX_WORDS);

		try {
			while ( true ) {
				String line = in.readLine();
				String stagsLine = null;
				if ( stagsIn != null ) {
					stagsLine = stagsIn.readLine();
				}

				if ( line == null ) {
					// no valid sentence
					next = null;
					return;
				} else if ( line.isEmpty() ) {
					// end of sentence
					next = sentence;
					return;
				}

				String[] tokens = line.split("\\s");
				sentence.addWord(tokens[0]);
				sentence.addPostag(tokens[1]);

				int numSupertags = Integer.parseInt(tokens[2]);
				ArrayList<Supertag> supertags = new ArrayList<Supertag>(numSupertags);

				String supertagString = null;
				String goldSupertagString = null;
				String[] stagTokens;

				boolean seenGold = false;
				double lowestProb = 1.0;

				if ( stagsIn != null ) {
					if ( stagsLine != null ) {
						stagTokens = stagsLine.split("\\s");
					} else {
						throw new IllegalArgumentException("Unexpected end of stream");
					}

					if ( stagTokens.length != 3 || !stagTokens[0].equals(tokens[0]) || !stagTokens[1].equals(tokens[1]) ) {
						throw new IllegalArgumentException("Mismatch between input and gold supertags: " + tokens[0] + " " + tokens[1] + " " + stagTokens[0] + " " + stagTokens[1]);
					}

					goldSupertagString = stagTokens[2];
				}

				for ( int i = 0; i < numSupertags; i++ ) {
					supertagString = tokens[2 * i + 3];
					double probability = Double.parseDouble(tokens[2 * i + 4]);
					lowestProb = probability;
					// assumes supertags are ordered by probability (highest first)
					// TODO: bad assumption
					// further more lowestProb gets assigned prob at every iteration
					// if assumption holds, can optimise by assuming lowestProb = probability after loop

					if ( supertagString.equals(goldSupertagString) ) {
						seenGold = true;
					}

					Category lexicalCategory = categories.getCategory(supertagString);

					if ( lexicalCategory == null ) {
						throw new IllegalArgumentException("No such supertag: " + supertagString);
					}

					Supertag supertag = new Supertag(supertagString, lexicalCategory, probability);
					supertags.add(supertag);
				}

				if ( stagsIn != null && seenGold == false ) {
					Category goldLexicalCategory = categories.getCategory(goldSupertagString);

					if ( goldLexicalCategory == null ) {
						throw new IllegalArgumentException("No such gold supertag: " + goldSupertagString);
					}

					Supertag goldSupertag = new Supertag(goldSupertagString, goldLexicalCategory, lowestProb);
					// use the lowest probability
					supertags.add(goldSupertag);
				}

				sentence.addSupertags(supertags);
			}
		} catch ( IOException e ) {
			logger.error(e);
			next = null;
		}
	}

	@Override
	public boolean hasNext() {
		if ( !sentenceRead ) {
			readSentence();
			sentenceRead = true;
		}

		return next != null;
	}

	@Override
	public Sentence next() {
		if ( !sentenceRead ) {
			readSentence();
			sentenceRead = true;
		}

		if ( next == null ) {
			throw new NoSuchElementException();
		} else {
			sentenceRead = false;
			return next;
		}
	}

	@Override
	public void remove() {
		throw new UnsupportedOperationException();
	}
}

@@ -1659,93 +1659,8 @@
 ull;
-%0A%09%09%09%09String%5B%5D stagTokens;%0A%0A%09%09%09%09boolean seenGold = false;%0A%09%09%09%09double lowestProb = 1.0;
 %0A%0A%09%09
@@ -1695,41 +1695,17 @@
 %09%09%09%09
-if ( stagsLine != null ) %7B%0A%09%09%09%09%09%09
+String%5B%5D 
 stag
@@ -1740,99 +1740,8 @@
 s%22);
-%0A%09%09%09%09%09%7D else %7B%0A%09%09%09%09%09%09throw new IllegalArgumentException(%22Unexpected end of stream%22);%0A%09%09%09%09%09%7D
 %0A%0A%09%09
@@ -2223,307 +2223,37 @@
 %5D);%0A
-%09%09%09%09%09lowestProb = probability;%0A%09%09%09%09%09// assumes supertags are ordered by probability (highest first)%0A%09%09%09%09%09// TODO: bad assumption%0A%09%09%09%09%09// further more lowestProb gets assigned prob at every iteration%0A%09%09%09%09%09// if assumption holds, can optimise by assuming lowestProb = probability after loop%0A%0A%09%09%09%09%09if (
+%0A%09%09%09%09%09if ( stagsIn != null &&
  sup
@@ -2305,21 +2305,14 @@
 %09%09%09%09
-seenGold = tr
+contin
 ue;%0A
@@ -2528,28 +2528,22 @@
 %09%09%09%09
-S
+s
 upertag
- supertag = 
+s.add(
 new 
@@ -2600,37 +2600,8 @@
 ity)
-;%0A%09%09%09%09%09supertags.add(supertag
 );%0A%09
@@ -2635,29 +2635,8 @@
 ull 
-&& seenGold == false 
 ) %7B%0A
@@ -2865,31 +2865,24 @@
 %09%09%09%09
-S
+s
 upertag
- goldSupertag =
+s.add(0,
  new
@@ -2936,87 +2936,12 @@
 ry, 
-lowestProb);%0A%09%09%09%09%09// use the lowest probability%0A%09%09%09%09%09supertags.add(goldSupertag
+1.0)
 );%0A%09

Refactor readSentence()