package decoder;

import is2.data.DataF;
import is2.data.Edges;
import is2.data.Parse;
import is2.data.ParseNBest;

import java.util.ArrayList;
import java.util.concurrent.Callable;

import extractors.Extractor;

/**
 * @author Dr. Bernd Bohnet, 30.08.2009
 * 
 * This class implements a parallel edge rearrangement for non-projective parsing;
 * The linear method was first suggest by Rayn McDonald et. al. 2005.  
 */
final public class ParallelRearrangeNBest implements Callable<Object> {

	// new parent child combination to explore
	final static class PA {
		final float p;
		final short ch, pa;
		
		float best;
		
	
		
		public PA(float p2, short ch2, short pa2) { p=p2; ch=ch2;pa=pa2;}
	}

	// list of parent child combinations
	private static ArrayList<PA> parents = new ArrayList<PA>();

	// some data from the dependency tree
	private short[] pos;
	private DataF x;
	private boolean[][] isChild ;	
	public short[] heads,types;
	private float lastNBest;
	private float best; // best so far 
	private float threshold;
	private Extractor extractor;
	
	
	/**
	 * Initialize the parallel rearrange thread
	 * 
	 * @param isChild2 is a child
	 * @param edgesC the part-of-speech edge mapping
	 * @param pos the part-of-speech 
	 * @param x the data
	 * @param lastNBest 
	 * @param s the heads
	 * @param ts the types
	 */
	public ParallelRearrangeNBest(short[] pos , DataF x, Parse p, float lastNBest, Extractor extractor, float best, float threshold) {
		
	
		heads=p.heads;

		types= p.labels;
		
		isChild = new boolean[heads.length][heads.length];

		for(int i = 1, l1=1; i < heads.length; i++,l1=i)  
			while((l1= heads[l1]) != -1) isChild[l1][i] = true;
	

		this.lastNBest =lastNBest;
		this.pos =pos;
		this.x=x;
		
		this.extractor = extractor;
		this.best=best;
		this.threshold = threshold;
	}

	public ArrayList<ParseNBest> parses = new  ArrayList<ParseNBest>();

	@Override
	public Object call() {
		
		// check the list of new possible parents and children for a better combination
		for(int ch = 1; ch < heads.length; ch++) {
			for(short pa = 0; pa < heads.length; pa++) {
				if(ch == pa || pa == heads[ch] || isChild[ch][pa]) continue;

			short oldP = heads[ch], oldT = types[ch]; 
			heads[ch]=pa;

			short[] labels = Edges.get(pos[pa], pos[ch],ch<pa);

			for(int l=0;l<labels.length;l++) {

				types[ch]=labels[l];
				float p_new = extractor.encode3(pos, heads, types, x);

				if (p_new<lastNBest || ((best+this.threshold)>p_new)) continue;
				
				ParseNBest p = new ParseNBest();
				p.signature(heads, types);
				p.f1=p_new;
				parses.add(p);
			}
			
			// change back
			heads[ch]= oldP; types[ch]=oldT;
			
			// consider changes to labels only
			labels = Edges.get(pos[oldP], pos[ch],ch<oldP);

			for(int l=0;l<labels.length;l++) {

				types[ch]=labels[l];	
				float p_new = (float) extractor.encode3(pos, heads, types, x);

				// optimization: add only if larger than smallest of n-best
				if (p_new<lastNBest || ((best+this.threshold)>p_new)) continue;

				ParseNBest p = new ParseNBest();
				p.signature(heads, types);
				p.f1=p_new;
				parses.add(p);
			}

			heads[ch]= oldP; types[ch]=oldT;
		}
		}
		return parses;
	}

	
	
}
