package org.maltparser.parser.algorithm.ucovington;

import java.util.Iterator;
import java.util.Set;
import java.util.SortedSet;

import org.maltparser.core.exception.MaltChainedException;
import org.maltparser.core.syntaxgraph.DependencyStructure;
import org.maltparser.core.syntaxgraph.edge.Edge;
import org.maltparser.core.syntaxgraph.node.DependencyNode;
import org.maltparser.core.syntaxgraph.node.TokenNode;
import org.maltparser.parser.DependencyParserConfig;
import org.maltparser.parser.Oracle;
import org.maltparser.parser.ParserConfiguration;
import org.maltparser.parser.algorithm.planar3TLabelStrat.Planar3TLabelStrat;
import org.maltparser.parser.history.GuideUserHistory;
import org.maltparser.parser.history.action.GuideUserAction;
/**
 * @author Johan Hall
 *
 */
public class UcovingtonOracle extends Oracle {
	public UcovingtonOracle(DependencyParserConfig manager, GuideUserHistory history) throws MaltChainedException {
		super(manager, history);
		setGuideName("NonProjective");
	}
	
	public GuideUserAction predict(DependencyStructure gold, ParserConfiguration config) throws MaltChainedException {
		UcovingtonConfig covingtonConfig = (UcovingtonConfig)config;
		DependencyNode leftTarget = covingtonConfig.getLeftTarget();
		int leftTargetIndex = leftTarget.getIndex();
		int rightTargetIndex = covingtonConfig.getRightTarget().getIndex();
		
		//if (!leftTarget.isRoot() && gold.getTokenNode(leftTargetIndex).getHead().getIndex() == rightTargetIndex) {
		//No se comprueba si ya hemos añadido este arco a la solución como se hacía en el PLANAR
		if (checkIfNodesAreRelated(gold, leftTargetIndex , rightTargetIndex)) {
			//return updateActionContainers(UNonProjective.ARC, gold.getTokenNode(leftTargetIndex).getHeadEdge().getLabelSet());
			//System.out.println("ARC");
			
			return updateActionContainers(UNonProjective.ARC, getEdgeGraph( gold , leftTargetIndex , rightTargetIndex ).getLabelSet());
			
			//No la usa de momento
		} else if (covingtonConfig.isAllowShift() == true && (!(gold.getTokenNode(rightTargetIndex).hasLeftDependent() 
				&& gold.getTokenNode(rightTargetIndex).getLeftmostDependent().getIndex() < leftTargetIndex)
				&& !(gold.getTokenNode(rightTargetIndex).getHead().getIndex() < leftTargetIndex 
						&& (!gold.getTokenNode(rightTargetIndex).getHead().isRoot() || covingtonConfig.getLeftstop() == 0)))) {
			return updateActionContainers(UNonProjective.SHIFT, null);
		} else {
			return updateActionContainers(UNonProjective.NOARC, null);
		}
	}
	
	public void finalizeSentence(DependencyStructure dependencyGraph) throws MaltChainedException {
		
	}
	
	public void terminate() throws MaltChainedException {
		
	}
	
	private boolean checkIfNodesAreRelated( DependencyStructure dg , int index1 , int index2 ) throws MaltChainedException
	{
		TokenNode tk=dg.getTokenNode(index1);
		Set<DependencyNode> heads=null;
		if(tk!=null){
		   heads=tk.getHeads();
		
		   for (DependencyNode head : heads) {
			if(head.getIndex()==index2)
			{
				return true;
			}
		   }
		}   
		
		tk=dg.getTokenNode(index2);
		if(tk!=null){
		   heads=tk.getHeads();
		   for (DependencyNode head : heads) {
			if(head.getIndex()==index1)
			{
				return true;
			}
		  }
		}   
		return false;
	}
	private Edge getEdgeGraph( DependencyStructure dg , int index1 , int index2 ) throws MaltChainedException
	{
		
	  SortedSet<Edge> arcos=dg.getEdges();
	  Iterator<Edge> it=arcos.iterator();
	  while(it.hasNext())
	  {
		Edge arco=it.next();
		if(arco.getSource().getIndex()==index1 && arco.getTarget().getIndex()==index2)
		{
			return arco;
		}
		if(arco.getSource().getIndex()==index2 && arco.getTarget().getIndex()==index1)
		{
			return arco;
		}
	  }
	  return null;
	}

}

