package org.maltparser.parser;

import org.maltparser.core.exception.MaltChainedException;
import org.maltparser.core.syntaxgraph.DependencyStructure;
import org.maltparser.parser.guide.ClassifierGuide;
import org.maltparser.parser.guide.OracleGuide;
import org.maltparser.parser.guide.SingleGuide;
import org.maltparser.parser.history.GuideHistory;
import org.maltparser.parser.history.action.GuideDecision;
import org.maltparser.parser.history.action.GuideUserAction;
import org.maltparser.core.syntaxgraph.DependencyGraph;
import org.maltparser.parser.algorithm.twoplanar3T.TwoPlanar3TConfig;
import org.maltparser.parser.algorithm.ucovington.UcovingtonConfig;

import java.util.SortedSet;
import java.util.Set;
import java.util.Iterator;
import java.util.TreeSet;
import org.maltparser.core.syntaxgraph.edge.Edge;
import org.maltparser.core.syntaxgraph.edge.GraphEdge;

public class BatchTrainer extends Trainer {
	private OracleGuide oracleGuide;
	private int parseCount;
	
	public BatchTrainer(DependencyParserConfig manager) throws MaltChainedException {
		super(manager);
		((SingleMalt)manager).addRegistry(org.maltparser.parser.Algorithm.class, this);
		setManager(manager);
		initParserState(1);
		setGuide(new SingleGuide(manager, (GuideHistory)parserState.getHistory(), ClassifierGuide.GuideMode.BATCH));
		oracleGuide = parserState.getFactory().makeOracleGuide(parserState.getHistory());
	}
	
	public DependencyStructure parse(DependencyStructure goldDependencyGraph, DependencyStructure parseDependencyGraph) throws MaltChainedException {
	
		String opcion="label";
		if	(parserState.getTransitionSystem().getName().compareTo("two-planar 3t arc-eager")==0){
			opcion=((TwoPlanar3TConfig)parserState.getConfiguration()).getMode();
			
		}
		if	(parserState.getTransitionSystem().getName().compareTo("ucovnonproj")==0){
			opcion=((UcovingtonConfig)parserState.getConfiguration()).getMode();
			
		}
		
		
		
		
	if(opcion.compareTo("root")==0){
		//2planar3tROOT
		parserState.clear();
		parserState.initialize(parseDependencyGraph);
		
		if(parserState.getTransitionSystem().getName().compareTo("planar 3t arc-eager")==0 
				|| parserState.getTransitionSystem().getName().compareTo("two-planar 3t arc-eager")==0
				|| parserState.getTransitionSystem().getName().compareTo("ucovnonproj")==0){

			((DependencyGraph)parseDependencyGraph).setSingleHeadedConstraint(false);
			dependencyTreeToRigthGraph(goldDependencyGraph);//NO SIRVE PARA NADA
		}
        
        if(parserState.getTransitionSystem().getName().compareTo("planar 3t label strategy arc-eager")==0) {

			((DependencyGraph)parseDependencyGraph).setSingleHeadedConstraint(false);
			depTreeToLabeledUndirectedGraph(goldDependencyGraph);
			
		}
		currentParserConfiguration = parserState.getConfiguration();
		parseCount++;
		if (diagnostics == true) {
			writeToDiaFile(parseCount + "");
		}
		while (!parserState.isTerminalState()) {
			GuideUserAction action = parserState.getTransitionSystem().getDeterministicAction(parserState.getHistory(), currentParserConfiguration);
			if (action == null) {
				
				action = oracleGuide.predict(goldDependencyGraph, currentParserConfiguration);
				try {
					classifierGuide.addInstance((GuideDecision)action);
				} catch (NullPointerException e) {
					throw new MaltChainedException("The guide cannot be found. ", e);
				}
			} else if (diagnostics == true) {
				writeToDiaFile(" *");
			}
			if (diagnostics == true) {
				writeToDiaFile(" " + parserState.getTransitionSystem().getActionString(action));
			}	
			parserState.apply(action);
			
		}
		
		if(parserState.getTransitionSystem().getName().compareTo("planar 3t arc-eager")==0 
				|| parserState.getTransitionSystem().getName().compareTo("planar 3t label strategy arc-eager")==0
				|| parserState.getTransitionSystem().getName().compareTo("two-planar 3t arc-eager")==0
				|| parserState.getTransitionSystem().getName().compareTo("ucovnonproj")==0){
			copyEdgesForPlanar3T(currentParserConfiguration.getDependencyGraph(), parseDependencyGraph);
		}else{
		   copyEdges(currentParserConfiguration.getDependencyGraph(), parseDependencyGraph);
		}
		
		
		
		
		parseDependencyGraph.linkAllTreesToRoot();
		oracleGuide.finalizeSentence(parseDependencyGraph);
		if (diagnostics == true) {
			writeToDiaFile("\n");
		}
		return parseDependencyGraph;
//-----------------------------------------------------------------------------------------------------------------------------------
	}else{	
		//2planar3tlab
		parserState.clear();
		parserState.initialize(parseDependencyGraph);
		
		if(parserState.getTransitionSystem().getName().compareTo("planar 3t arc-eager")==0){

			((DependencyGraph)parseDependencyGraph).setSingleHeadedConstraint(false);
			dependencyTreeToRigthGraph(goldDependencyGraph);//NO SIRVE PARA NADA
		}
        
        if(parserState.getTransitionSystem().getName().compareTo("planar 3t label strategy arc-eager")==0 
        		|| parserState.getTransitionSystem().getName().compareTo("two-planar 3t arc-eager")==0
				|| parserState.getTransitionSystem().getName().compareTo("ucovnonproj")==0){
        
			((DependencyGraph)parseDependencyGraph).setSingleHeadedConstraint(false);
			depTreeToLabeledUndirectedGraph(goldDependencyGraph);
			
		}
		currentParserConfiguration = parserState.getConfiguration();
		parseCount++;
		if (diagnostics == true) {
			writeToDiaFile(parseCount + "");
		}
		while (!parserState.isTerminalState()) {
			
			GuideUserAction action = parserState.getTransitionSystem().getDeterministicAction(parserState.getHistory(), currentParserConfiguration);
			
			if (action == null) {
				
				action = oracleGuide.predict(goldDependencyGraph, currentParserConfiguration);
			
				try {
					
					classifierGuide.addInstance((GuideDecision)action);
					
				} catch (NullPointerException e) {
					throw new MaltChainedException("The guide cannot be found. ", e);
				}
			} else if (diagnostics == true) {
				writeToDiaFile(" *");
			}
			if (diagnostics == true) {
				writeToDiaFile(" " + parserState.getTransitionSystem().getActionString(action));
			}	
			
			parserState.apply(action);
			
			
			
		}
	
		if(parserState.getTransitionSystem().getName().compareTo("planar 3t arc-eager")==0 
				|| parserState.getTransitionSystem().getName().compareTo("planar 3t label strategy arc-eager")==0
				|| parserState.getTransitionSystem().getName().compareTo("two-planar 3t arc-eager")==0
				|| parserState.getTransitionSystem().getName().compareTo("ucovnonproj")==0){
			copyEdgesForPlanar3T(currentParserConfiguration.getDependencyGraph(), parseDependencyGraph);
		}else{
		   copyEdges(currentParserConfiguration.getDependencyGraph(), parseDependencyGraph);
		}
		
       // System.out.println("GOLD: "+goldDependencyGraph.getEdges().toString());
       // System.out.println("----");
	//	System.out.println("Grafo resultante: "+parseDependencyGraph.getEdges().toString());
	//	System.out.println("----------------------------------");
		//System.exit(0);
		
		parseDependencyGraph.linkAllTreesToRoot();
		oracleGuide.finalizeSentence(parseDependencyGraph);
		if (diagnostics == true) {
			writeToDiaFile("\n");
		}
		
		
		return parseDependencyGraph;
	}
	}
	
	public OracleGuide getOracleGuide() {
		return oracleGuide;
	}
	
	public void train() throws MaltChainedException { }
	public void terminate() throws MaltChainedException {
		if (diagnostics == true) {
			closeDiaWriter();
		}
	}
	
	private void dependencyTreeToRigthGraph(DependencyStructure graph) throws MaltChainedException 
	{
		SortedSet<Edge> nuevosArcos=new TreeSet<Edge>();
		SortedSet<Edge> arcos=graph.getEdges();
		Iterator<Edge> itR=arcos.iterator();
		
		while(itR.hasNext())
		{
			Edge arco=itR.next();
			if(arco.getTarget().getIndex()<arco.getSource().getIndex())
			{
				nuevosArcos.add(arco);
			}
		}
		Iterator<Edge> itN=nuevosArcos.iterator();
		while(itN.hasNext())
		{
			Edge ne=itN.next();
			((GraphEdge)ne).changeSense(ne.getTarget(),ne.getSource(), 1);
			
		}
	     
	}
	
	private void depTreeToLabeledUndirectedGraph(DependencyStructure graph) throws MaltChainedException
	{
		SortedSet<Edge> edges=graph.getEdges();
		for(Edge edge:edges)
		{
			
			Set<String> names=graph.getSymbolTables().getSymbolTableNames();
			for(String name:names)
			{
				
			 if(name.compareTo("DEPREL")==0)
			 {
				 String label=edge.getLabelSymbol(graph.getSymbolTables().getSymbolTable(name));
				 if(edge.getSource().getIndex()<edge.getTarget().getIndex())
				 {
					 label=label+"R";
				 }else{
					 label=label+"L";
				 }
				 edge.addLabel(graph.getSymbolTables().getSymbolTable(name), label);
			 } 
            }
	       	
		}
		
	}
	
}
