package chart_parser;

import io.Sentence;

import java.util.ArrayList;
import java.util.HashSet;

import lexicon.Category;
import cat_combination.FilledDependency;
import cat_combination.SuperCategory;

public class CellTrainBeam extends Cell {
	public double violation;

	public SuperCategory maxSuper = null;
	public SuperCategory goldSuperCat = null;

	private int sentIndex;
	private double maxScore = Double.NEGATIVE_INFINITY;

	private HashSet<FilledDependency> goldDeps;

	public CellTrainBeam() {
		super();
		this.goldDeps = new HashSet<FilledDependency>();
	}

	/**
	 * Calculates violation of a cell i.e. the difference in scores of the
	 * highest scoring supercategory in the cell and the highest scoring
	 * gold supercategory, if the former is greater or equal to the latter.
	 * 
	 * The method assumes that the supercategories have been sorted in
	 * descending order.
	 * 
	 * The violation is cached in the violation field of the cell.
	 * 
	 * @return violation of cell if it exists, -1 if violation does not exist
	 * (i.e. gold score is higher than highest score), -2 if cell does not have
	 * gold supercategory.
	 */
	public double calcViolation() {
		if ( goldSuperCat != null ) {
			/*
			 * removed linear search in cell for maxSuper, because the prior
			 * applyBeam() would have sorted superCategories in the cell;
			 * hence it suffices to get the first superCategory i.e. highest
			 * scoring superCategory in superCategories
			 */
			if ( !getSuperCategories().isEmpty() ) {
				maxSuper = getSuperCategories().get(0);
				maxScore = maxSuper.score;
			}

			if ( maxScore >= goldSuperCat.score ) {
				violation = maxScore - goldSuperCat.score;
			} else {
				violation = -1;
			}
		} else {
			violation = -2;
		}

		return violation;
	}

	/**
	 * Calculates violation of a cell i.e. the difference in scores of the
	 * highest scoring supercategory in the cell and the highest scoring
	 * gold supercategory, if the former is greater or equal to the latter.
	 * 
	 * The method assumes that the supercategories have been sorted in
	 * descending order.
	 * 
	 * @param sentence training sentence
	 * @param oracleDecoder oracle decoder
	 * @param oracleSupertags oracle supertags
	 * @param index index
	 * @return violation of cell if it exists, -1 if violation does not exist
	 * (i.e. gold score is higher than highest score), -2 if cell does not have
	 * gold supercategory, -3 if cell does not gold dependencies.
	 */
	public double calcViolation(Sentence sentence, OracleDecoder oracleDecoder, ArrayList<Category> oracleSupertags, int index) {
		int numGoldDeps = numGoldDepsIgnoreEval(sentence, oracleDecoder);

		if ( numGoldDeps == 0 ) {
			return -3;
		}

		/*
		 * superCategories would have been sorted by applyBeam() before,
		 * so the first gold supercategory is the highest scoring one.
		 */
		for ( SuperCategory superCat : getSuperCategories() ) {
			sentIndex = index;
			int numGoldSeen = countGoldDeps(superCat, sentence, oracleDecoder, oracleSupertags);
			if ( numGoldSeen == numGoldDeps ) {
				goldSuperCat = superCat;
				break;
			}
		}

		return calcViolation();
	}

	/**
	 * Adds a FilledDependency to goldDeps.
	 * 
	 * @param filledDep FilledDependency to be added
	 */
	public void addDep(FilledDependency filledDep) {
		goldDeps.add(filledDep);
	}

	/**
	 * Returns number of gold dependencies in the cell that are not ignored
	 * in the evaluation script.
	 * 
	 * @param sentence training sentence
	 * @param oracleDecoder oracle decoder
	 * @return number of gold dependencies in the cell that are not ignored
	 * in the evaluation script
	 */
	private int numGoldDepsIgnoreEval(Sentence sentence, OracleDecoder oracleDecoder) {
		int numGoldDeps = 0;

		for (FilledDependency filledDep : goldDeps) {
			if ( !oracleDecoder.ignoreDeps.ignoreDependency(filledDep, sentence)) {
				numGoldDeps++;
			}
		}

		return numGoldDeps;
	}

	/**
	 * Counts number of gold dependencies generated by a supercategory.
	 * 
	 * @param superCat supercategory
	 * @param sentence training sentence
	 * @param oracleDecoder oracle decoder
	 * @param oracleSupertags oracle supertags
	 * @return number of gold dependencies generated by a supercategory if
	 * all dependencies generated are gold, -1 otherwise.
	 */
	private int countGoldDeps(SuperCategory superCat, Sentence sentence, OracleDecoder oracleDecoder, ArrayList<Category> oracleSupertags) {
		int numGoldSeen = 0;

		for ( FilledDependency filledDep = superCat.filledDeps; filledDep != null; filledDep = filledDep.next ) {
			if ( !oracleDecoder.ignoreDeps.ignoreDependency(filledDep, sentence) ) {
				if ( goldDeps.contains(filledDep) ) {
					numGoldSeen++;
				} else {
					return -1;
				}
			}
		}

		SuperCategory leftChild = superCat.leftChild;
		SuperCategory rightChild = superCat.rightChild;

		if ( leftChild != null ) {
			int leftGoldSeen = countGoldDeps(leftChild, sentence, oracleDecoder, oracleSupertags);
			if ( leftGoldSeen != -1 ) {
				numGoldSeen += leftGoldSeen;
			} else {
				return -1;
			}

			if ( rightChild != null ) {
				int rightGoldSeen = countGoldDeps(rightChild, sentence, oracleDecoder, oracleSupertags);
				if ( leftGoldSeen != -1 ) {
					numGoldSeen += rightGoldSeen;
				} else {
					return -1;
				}
			}
		} else {
			if ( superCat.cat != oracleSupertags.get(sentIndex) ) {
				return -1;
			}

			sentIndex++;
		}

		return numGoldSeen;
	}

	@Override
	public void clear() {
		getSuperCategories().clear();
		goldDeps.clear();

		sentIndex = 0;
		maxScore = Double.NEGATIVE_INFINITY;
		violation = 0;
		maxSuper = null;
		goldSuperCat = null;
	}
}

@@ -5162,35 +5162,36 @@
 tags);%0A%09%09%09%09if ( 
-lef
+righ
 tGoldSeen != -1 

Fix bug in countGoldDeps().