package uk.ac.ox.krr.logmap2;


import java.io.*;


import java.util.HashMap;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Set;
import java.util.Map;
import java.util.TreeSet;

import java.util.HashSet;


import org.semanticweb.owlapi.model.OWLEntity;
import org.semanticweb.owlapi.model.OWLOntology;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.semanticweb.owlapi.model.OWLDataFactory;

import uk.ac.manchester.syntactic_locality.ModuleExtractor;
import uk.ac.ox.krr.logmap2.background.CategoryMappingsLoader;
import uk.ac.ox.krr.logmap2.io.*;
import uk.ac.ox.krr.logmap2.reasoning.SatisfiabilityIntegration;
import uk.ac.ox.krr.logmap2.repair.*;
import uk.ac.ox.krr.logmap2.mappings.objects.*;
import uk.ac.ox.krr.logmap2.oaei.oracle.OracleManager;
import uk.ac.ox.krr.logmap2.overlapping.*;
import uk.ac.ox.krr.logmap2.owlapi.SynchronizedOWLManager;
import uk.ac.ox.krr.logmap2.utilities.Lib;
import uk.ac.ox.krr.logmap2.utilities.PrecomputeIndexCombination;

import uk.ac.ox.krr.logmap2.lexicon.LexicalUtilities;
import uk.ac.ox.krr.logmap2.utilities.Utilities;

import uk.ac.ox.krr.logmap2.indexing.*;
import uk.ac.ox.krr.logmap2.indexing.entities.ClassIndex;
import uk.ac.ox.krr.logmap2.interactive.*;

import uk.ac.ox.krr.logmap2.interactive.objects.MappingObjectInteractivity;
import uk.ac.ox.krr.logmap2.mappings.MappingManager;
import uk.ac.ox.krr.logmap2.mappings.CandidateMappingManager;

import uk.ac.ox.krr.logmap2.io.LogOutput;

import uk.ac.ox.krr.logmap2.statistics.*;


/**
 * This class implements LogMap 2 algorithm calling it main functionalities
 * 
 * @author ernesto
 *
 */
public class LogMap2Core {
	
	private OverlappingExtractor overlappingExtractor;
	
	private IndexManager index;
	
	private OntologyProcessing onto_process1;
	private OntologyProcessing onto_process2;
	
	//private AnchorExtraction mapping_extractor;
	private MappingManager mapping_extractor;
	
	private AnchorAssessment mappings_assessment;
	
	private InteractiveProcess interactiveProcessManager;
	
	//For precission and recall
	private Set<MappingObjectStr> mappings_gs = new HashSet<MappingObjectStr>();
	
	private LexicalUtilities lexicalUtilities = new LexicalUtilities();
	
	private CategoryMappingsLoader categoryMappingsLoader = new CategoryMappingsLoader();
	
	private OWLDataFactory dataFactory;

	private String prefix4IRIs;
	private String logmap_mappings_path="";
	private String gs_mappings="";
	
	long init;
	
	

	//boolean cleanD_G=true;

	
	boolean useInteractivity=true;
	boolean useHeuristics=true;
	boolean orderQuestions=true;
	int error_user = 0; //%error for user
	boolean record_interactivity=false;
	
	boolean ask_everything=false;
	
	boolean evaluate_impact=false;
	
	//boolean overlapping=true;
	//String interactivityFile;
	
	
	private static final Logger LOGGER = LoggerFactory.getLogger(LogMap2Core.class);

	
	/**
	 * OAEI constructor
	 * @param iri1_str
	 * @param iri2_str
	 * @throws Exception
	 */
	public LogMap2Core(
			String iri1_str, 
			String iri2_str) throws Exception{
		
		this(iri1_str, iri2_str, "", "", "", "", false, false, false, 0, false, false, false);
		
	}
	
	
	/**
	 * Constructor for tests: conference task with gold standard
	 * @param iri1_str
	 * @param iri2_str
	 * @param evaluate_impact
	 * @param file_gs Gold standard file
	 * @throws Exception
	 */
	public LogMap2Core(
			String iri1_str, 
			String iri2_str,
			boolean evaluate_impact,
			String file_gs) throws Exception{
		
		this(iri1_str, iri2_str, "", "", file_gs, "", false, false, false, 0, false, false, evaluate_impact);
		
	}
	
	
	/**
	 * Constructor for tests: conference/multifarm task
	 * @param iri1_str
	 * @param iri2_str
	 * @param evaluate_impact
	 */
	public LogMap2Core(
			String iri1_str, 
			String iri2_str,
			boolean evaluate_impact) throws Exception {
		
		this(iri1_str, iri2_str, "", "", "", "", false, false, false, 0, false, false, evaluate_impact); //eval impact
		
	}
	
	
	/**
	 * Constructor for tests: instance matching task
	 * @param iri1_str
	 * @param iri2_str
	 * @param output_path
	 * @param gs_file
	 * @param evaluate_impact
	 * @throws Exception
	 */
	public LogMap2Core(
			String iri1_str, 
			String iri2_str, 
			String output_path,
			String gs_file,
			boolean evaluate_impact) throws Exception {
		
		this(iri1_str, iri2_str, "", "", gs_file, output_path, false, false, false, 0, false, false, evaluate_impact); //eval impact
		
	}
	

	
	
	/**
	 * basic constructor: currently only from LogMap2_launch
	 * @param iri1_str
	 * @param iri2_str
	 * @param output_path
	 * @param eval_impact
	 * @throws Exception
	 */
	public LogMap2Core(
			String iri1_str, 
			String iri2_str, 
			String output_path,
			boolean eval_impact) throws Exception{
		
		this(iri1_str, iri2_str, "", "", "", output_path, false, false, false, 0, false, false, eval_impact);
		
	}
	
	
	
	/**
	 * Constructor from a java application
	 */
	public LogMap2Core(
			OWLOntology onto1,
			OWLOntology onto2,
			boolean only_achors) throws Exception{
		
		this(onto1, onto2, new HashSet<MappingObjectStr>(), only_achors);
		
	}
	
	
	/**
	 * Constructor from a java application
	 */
	public LogMap2Core(
			OWLOntology onto1,
			OWLOntology onto2) throws Exception{
		
		this(onto1, onto2, new HashSet<MappingObjectStr>(), false);
		
	}
	
	/**
	 * Constructor from a java application with input mapping (e.g. composed mappings)
	 */
	public LogMap2Core(
			OWLOntology onto1,
			OWLOntology onto2,
			Set<MappingObjectStr> input_mappings) throws Exception{
	
		this(onto1, onto2, input_mappings, false);
	}
	
	/**
	 * Constructor from a java application with input mapping (e.g. composed mappings). If validated_input_mappings = true, 
	 * then the input mappings are added to the anchor set as they are  
	 * @param onto1
	 * @param onto2
	 * @param input_mappings
	 * @param are_input_mappings_validated
	 * @throws Exception
	 */
	public LogMap2Core(
			OWLOntology onto1,
			OWLOntology onto2,
			Set<MappingObjectStr> input_mappings,
			boolean are_input_mappings_validated) throws Exception{
		
		
		boolean only_anchors=false;
		
		//we keep true in order to not to delete modules overlappings
		//See IndexLexiconAndStructure
		//Furthremore we may want to evaluate impact at some point
		//Although in this constructor it does NIT evaluate impact
		evaluate_impact=true;
		
		//dataFactory = OWLManager.getOWLDataFactory();
		dataFactory = SynchronizedOWLManager.createOWLDataFactory();
		
		
				
		StatisticsTimeMappings.setInitGlobalTime();
		init = StatisticsTimeMappings.getCurrentTimeInMillis();
		
		
		//INIT LOGMAP: lex and precomp integer combinations
		InitLogMap();
		
		
		//Overlapping estimation
		OverlappingEstimation(onto1, onto2);
		

		//Indexes lexicon (IF creation) and structure
		IndexLexiconAndStructure(input_mappings);
				
		
		LogOutput.printAlways("Time Parsing and Index Lexicon (s): " + StatisticsTimeMappings.getRunningTime(init));
							
		
		//EXTRACT, CLEAN ANCHORS and INDEX INTLABELLING
		createAndCleanAnchors(are_input_mappings_validated);
		//System.out.println("Anchors completed");
		
		if (!only_anchors){
			//Extract new candidates (Level 1), clean them and index labelling
			createCandidateMappings();
			//System.out.println("Candidate mappings completed");
			
			
			//Extract more candidates Level 2 (If interactivity is active then those are the mappings to ask)
			createCandidateMappingsLevel2();
			//System.out.println("Candidate mappings level 2 completed");
			
			//Last Cleaning
			//lastLogicalCleaning();
			
			
			
			
			if (Parameters.perform_property_matching){
				createAndAssessPropertyMappings();
			}			
			//System.out.println("Property mappings completed.");
			
			//Optional (see parameters file)
			if (Parameters.perform_instance_matching){
				createAndAssessInstanceMappings();
			}
			//System.out.println("Instance mappings completed.");
			
			
			//System.out.println("TOTAL MATCHING TIME (s): " + StatisticsTimeMappings.getTotalRunningTime());
			//System.out.println("LogMap 2 Total Matching Time (s): " + StatisticsTimeMappings.getTotalRunningTime());
			
			
			//Clean index structures and others...
			//Not here because OAEI and call from other application
			//index.clearTaxonomicalStructures();		
		}
		
		
	}
	
	
	/**
	 * Constructor for test (implementation process)
	 * @param iri1_str
	 * @param iri2_str
	 * @param iri1_str_out
	 * @param iri2_str_out
	 * @param gs_mappings
	 * @param logmap_mappings_path
	 * @param useInteractivity
	 * @param useHeuristics
	 * @param orderQuestions
	 * @throws Exception
	 */
	public LogMap2Core(
			String iri1_str, 
			String iri2_str, 
			String iri1_str_out, 
			String iri2_str_out, 
			String gs_mappings, 
			String logmap_mappings_path,
			boolean useInteractivity,
			boolean useHeuristics, //should be an input parameter
			boolean orderQuestions,
			int error_user,
			boolean ask_everything,
			boolean record_interactivity,
			boolean evaluate_impact) throws Exception{
		
		
		this.logmap_mappings_path = logmap_mappings_path;
		this.gs_mappings = gs_mappings;
		//this.interactivityFile=interactivityFile;
		
		this.useInteractivity=useInteractivity;
		this.useHeuristics=useHeuristics;
		this.orderQuestions=orderQuestions;
		
		this.error_user = error_user;
		
		this.record_interactivity=record_interactivity;
		
		this.ask_everything=ask_everything;
		
		
		this.evaluate_impact=evaluate_impact;
		
		
		//dataFactory = OWLManager.getOWLDataFactory();
		dataFactory = SynchronizedOWLManager.createOWLDataFactory();
		
		if (logmap_mappings_path.startsWith("/"))
			prefix4IRIs = "file:";
		else
			prefix4IRIs = "file:/";
		
		
		
		StatisticsTimeMappings.setInitGlobalTime();
		init = StatisticsTimeMappings.getCurrentTimeInMillis();
		
		
		//INIT LOGMAP: lex and precomp integer combinations
		InitLogMap();
		
		
		LOGGER.info("LogMap: ontology loading and overlapping extraction");
		
		//Overlapping estimation
		OverlappingEstimation(iri1_str, iri2_str);
		//OverlappingEstimation(iri1_str, iri2_str, iri1_str_out, iri2_str_out);//test
		//if (true)
		//	return;
		
		
		LOGGER.info("LogMap indexation");
		
		//Indexes lexicon (IF creation) and structure
		IndexLexiconAndStructure();
		
		
		LogOutput.printAlways("Time Parsing and Index Lexicon (s): " + StatisticsTimeMappings.getRunningTime(init));
		
		
		
		
		//Only for statistical purposes (and interactivity)
		if (!gs_mappings.equals("")){
			loadMappingsGS();
		}
		//printStatisticsGoldStandard();
		
		
		//EXTRACT, CLEAN ANCHORS and INDEX INTLABELLING
		LOGGER.info("LogMap anchor extraction");
		createAndCleanAnchors();
		
		
		//Extract new candidates (Level 1), clean them and index labelling
		LOGGER.info("LogMap class mapping extraction");
		createCandidateMappings();
		//mapping_extractor.printStatisticsMappingEvaluation();
		
		
		//Anchors should be non ambiguous for interval labelling index 
		//LogOutput.print("AMBIGUOUS ANCHORS: " + areAnchorsdAmbiguous());
		
		
		
		StatisticsManager.setPrecisionAndRecallAnchors(mapping_extractor.getStringGoldStandardAnchors().size());				
		//Statistics before interactivity
		StatisticsManager.printStatisticsLogMap_mappings();
		
		
		
		//Extract more candidates Level 2 (If interactivity is active then those are the mappings to ask)
		//Also weakened in previous iterations
		createCandidateMappingsLevel2();
		
		
		//mapping_extractor.printAllDicoveredMappingsStatistics();				
		//mapping_extractor.printHarDiscardedStatistics();	
		//mapping_extractor.printStatisticsMappingEvaluation();//|Everything
		
		
		StatisticsManager.printMappingsAskedHeur();
		
		
		//mapping_extractor.printStatisticsLogMap_mappings();
		
		//Tests
		//outputMappings(mapping_extractor.getAnchors(), logmap_mappings_path + "all_extracted.txt");
		//outputMappings(mapping_extractor.getDircardedAnchors(), logmap_mappings_path + "discarded.txt");
		//orderedOutputMappings(true);   //For LUCADA
		
		
		
		//Last cleaning just in case
		//lastLogicalCleaning();
		
		
		if (Parameters.perform_property_matching){
			LOGGER.info("LogMap property mapping extraction");
			createAndAssessPropertyMappings();
		}
		
		
		//Optional (see parameters file)
		if (Parameters.perform_instance_matching){
			
			LOGGER.info("LogMap instance mapping extraction");
			
			createAndAssessInstanceMappings();
			
			if (Parameters.output_instance_mapping_files && !logmap_mappings_path.equals("")){
				
				outputInstaceMappings4Evaluation();
				
			}
			
		}
		
		
				
		//TODO Delete OntologyProcessing if possible
			
	
		//OUTPUT
		//P&R wrt GS
		if (!gs_mappings.equals("")){
			getPrecisionAndRecallMappings();
		}
		
		
		File file_folder = new File(logmap_mappings_path);
		
		
		if (!logmap_mappings_path.equals("") && file_folder.exists() && file_folder.isAbsolute()){ //Some experiments do not provide path...
			
			//if (!file_folder.isAbsolute()){
			//	logmap_mappings_path = file_folder.getAbsolutePath();
			//}
			
			//FINAL OVERLAPPING
			//Extracts new overlapping for anchors and saves overlapping as OWL files
			LogOutput.print("Creating overlapping output");
			createOutput4Overlapping(true); //TODO UNCOMMENT (just removed for tests)
			
			//Mapping OUTPUTFILES
			LogOutput.print("Saving output mapping files");
			saveExtractedMappings("logmap2_mappings");
		}
		else{
			//System.err.println("The given output path is not absolute or it does not exist. The output mappings cannot be stored.");
			LogOutput.print("The given output path is not absolute or it does not exist. The output mappings cannot be stored.");
		}
		
		
		
		LogOutput.print("Average time taxonomic queries: " + 
				index.getAvgTime4TaxCalls() + ". Total: " + index.getTime4TaxCalls()  + ". Num calls: " + index.getNumberOfTaxCalls());
		
		LogOutput.print("Average time disjointness queries: " + 
				index.getAvgTime4DisjCalls() + ". Total: " + index.getTime4DisjCalls()  + ". Num calls: " + index.getNumberOfDisjCalls());
		
		
		
		
		//System.out.println("Number of computed mappings: " + getLogMapMappings());
		LogOutput.printAlways("Number of computed mappings: " + getLogMapMappings().size());
		
		//System.out.println("TOTAL MATCHING TIME (s): " + StatisticsTimeMappings.getTotalRunningTime());
		LogOutput.printAlways("LogMap 2 Total Matching Time (s): " + StatisticsTimeMappings.getTotalRunningTime());
		
		
		if (evaluate_impact){
			init = StatisticsTimeMappings.getCurrentTimeInMillis();
			//impactIntegration();
			impactIntegration(iri1_str, iri2_str);			
			LogOutput.printAlways("Time checking impact integration (s): " + StatisticsTimeMappings.getRunningTime(init));
		}
		
		
		
		
		
		//Clean index structures and others...
		//Not here because OAEI
		//index.clearTaxonomicalStructures();
		//Since we need to return the mappings! We cannot remove the index!
		
		
	}
	
	SatisfiabilityIntegration sat_checker;
	boolean hasUnSat = false;
	int numUnsat = 0;
	
	public boolean hasUnsatClasses(){
		
		return hasUnSat;
	}
	
	public int getNumUnsatClasses(){
		
		return numUnsat;
	}
	
	
	private void impactIntegration() throws Exception {
		
		OWLOntology mappins_owl_onto = getOWLOntology4Mappings();
		
		LogOutput.print(overlappingExtractor.getOverlappingOnto1().getAxiomCount());
		LogOutput.print(overlappingExtractor.getOverlappingOnto2().getAxiomCount());
		LogOutput.print(mappins_owl_onto.getAxiomCount());
		
		
		
		sat_checker = new SatisfiabilityIntegration(
				overlappingExtractor.getOverlappingOnto1(), 
				overlappingExtractor.getOverlappingOnto2(),
				mappins_owl_onto,
				true,//Time_Out_Class
				false); //use factory
		
		hasUnSat=sat_checker.hasUnsatClasses();
		numUnsat=sat_checker.getNumUnsatClasses();
		
		LogOutput.print("Num unsat classes: " + sat_checker.getNumUnsatClasses());
		
		
		/*ImpactAuditedIntegration impact = new ImpactAuditedIntegration();
		
		try{
			impact.reasonWithGivenOntologiesHermit(
				overlappingExtractor.getOverlappingOnto1(), 
				overlappingExtractor.getOverlappingOnto2(),
				getOWLOntology4Mappings());
		}
		catch (Exception e){
			System.err.println("HermiT could not deal with these ontologies: " + e.getMessage());
		}
		
		try{
			impact.reasonWithGivenOntologiesPellet(
				overlappingExtractor.getOverlappingOnto1(), 
				overlappingExtractor.getOverlappingOnto2(),
				getOWLOntology4Mappings());
		}
		catch (Exception e){
			System.err.println("Pellet could not deal with these ontologies: " + e.getMessage());
		}
		*/
		
		
	}
	
	private void impactIntegration(String iri1, String iri2) throws Exception {
		
		OWLOntology mappings_owl_onto = getOWLOntology4Mappings();
		
		OntologyLoader loader1 = new OntologyLoader(iri1);
		OntologyLoader loader2 = new OntologyLoader(iri2);
		
		LogOutput.printAlways("Evaluating impact...");
				
		LogOutput.print("Axioms onto1: " + loader1.getOWLOntology().getAxiomCount());
		LogOutput.print("Axioms onto2: " + loader2.getOWLOntology().getAxiomCount());
		LogOutput.print("Mapping Axioms: " + mappings_owl_onto.getAxiomCount());
		
		
		
		sat_checker = new SatisfiabilityIntegration(
				loader1.getOWLOntology(), 
				loader2.getOWLOntology(),
				mappings_owl_onto,
				true,//Time_Out_Class
				false); //use factory
		
		
		hasUnSat=sat_checker.hasUnsatClasses();
		numUnsat=sat_checker.getNumUnsatClasses();
		
		//OWLManager.createOWLOntologyManager().saveOntology(mappings_owl_onto, new RDFXMLOntologyFormat(),
				//IRI.create("file:/usr/local/data/MappingsConferenceBenchmark/ontologies/mappings-cmt-confof.owl"));
		//		IRI.create("file:/usr/local/data/MappingsConferenceBenchmark/ontologies/mappings-edas-ekaw.owl"));
		System.out.println("\nNum unsat classes after integration: " + sat_checker.getNumUnsatClasses());
		//LogOutput.printAlways
	}
	
	
	
	/**
	 * This method will be used to build an OWLOntology object to evaluate the logical impact
	 * The ontology will not be stored (see @saveExtractedMappings())
	 * 
	 * @return
	 * @throws Exception
	 */
	public OWLOntology getOWLOntology4Mappings() throws Exception{
	
		int ident2;
		
		OWLAlignmentFormat owlformat = new OWLAlignmentFormat("");
		
		int dir_mapping;
		
		for (int ide1 : getClassMappings().keySet()){
			for (int ide2 : getClassMappings().get(ide1)){
				
				//LogOutput.print(getIRI4ConceptIdentifier(ide1));
				//LogOutput.print(getIRI4ConceptIdentifier(ide2));
				//LogOutput.print(getConfidence4ConceptMapping(ide1, ide2));
				//LogOutput.print("");
				
				dir_mapping = getDirClassMapping(ide1, ide2);
				
				if (dir_mapping!=Utilities.NoMap){
						
					//System.out.println(getIRI4ConceptIdentifier(ide1));
					//System.out.println(getIRI4ConceptIdentifier(ide2));
					//System.out.println(dir_mapping);
								
					//TODO No need to reverse ids. Done in OWLAlignmentFormat
					//if (dir_mapping!=Utilities.R2L){
						owlformat.addClassMapping2Output(
								getIRI4ConceptIdentifier(ide1),
								getIRI4ConceptIdentifier(ide2),
								dir_mapping,
								getConfidence4ConceptMapping(ide1, ide2)
								);
					/*}
					else{
						owlformat.addClassMapping2Output(
								getIRI4ConceptIdentifier(ide2),
								getIRI4ConceptIdentifier(ide1),								
								dir_mapping,
								getConfidence4ConceptMapping(ide1, ide2)
							);
					}*/
				}
			}
		}
		
		for (int ide1 : getDataPropMappings().keySet()){
			
			
			
			//System.out.println(getIRI4DataPropIdentifier(ide1));
			//System.out.println(getIRI4DataPropIdentifier(getDataPropMappings().get(ide1)));
			//System.out.println(getConfidence4DataPropConceptMapping(ide1, getDataPropMappings().get(ide1)));
			
			
			owlformat.addDataPropMapping2Output(
					getIRI4DataPropIdentifier(ide1),
					getIRI4DataPropIdentifier(getDataPropMappings().get(ide1)),
					Utilities.EQ,  
					getConfidence4DataPropMapping(ide1, getDataPropMappings().get(ide1))//1.0
				);
		}
		
		for (int ide1 : getObjectPropMappings().keySet()){
			
			//System.out.println(getIRI4ObjectPropIdentifier(ide1));
			//System.out.println(getIRI4ObjectPropIdentifier(getObjectPropMappings().get(ide1)));
			//System.out.println(getConfidence4ObjectPropConceptMapping(ide1, getObjectPropMappings().get(ide1)));
			//LogOutput.print("");
				
			owlformat.addObjPropMapping2Output(
					getIRI4ObjectPropIdentifier(ide1),
					getIRI4ObjectPropIdentifier(getObjectPropMappings().get(ide1)),
					Utilities.EQ, 
					getConfidence4ObjectPropMapping(ide1, getObjectPropMappings().get(ide1))//1.0
				);
		}
		

		if (Parameters.perform_instance_matching){
			
			for (int ide1 : getInstanceMappings().keySet()){
				for (int ide2 : getInstanceMappings().get(ide1)){
				
					owlformat.addInstanceMapping2Output(
							getIRI4InstanceIdentifier(ide1), 
							getIRI4InstanceIdentifier(ide2), 
							getConfidence4InstanceMapping(ide1, ide2)
						);
					
				}
			}
		}
		
		return owlformat.getOWLOntology();
		
	}
	
	
	
	private boolean areAnchorsdAmbiguous(){
		
		for (int ide : mapping_extractor.getLogMapMappings().keySet()){
			
			if (mapping_extractor.getLogMapMappings().get(ide).size()>1){
				LogOutput.print(ide + "  " + mapping_extractor.getLogMapMappings().get(ide));
				return true;
			}
			
		}
		
		return false;
		
		
	}
	
	
	
	
	private void InitLogMap() throws Exception{
		
		//Show print outs
		LogOutput.showOutpuLog(Parameters.print_output); //False for OAEI?
		LogOutput.showOutpuLogAlways(Parameters.print_output || Parameters.print_output_always);
		
		
		
		//Only from OAEI-LogMap
		//Parameters.readParameters();
		
		//We load both sets
		lexicalUtilities.loadStopWords();
		lexicalUtilities.loadStopWordsExtended();
		
		if (Parameters.use_umls_lexicon)
			lexicalUtilities.loadUMLSLexiconResources();
		
		lexicalUtilities.setStemmer(); //creates stemmer object (Paice by default)
		
		//Lib.debuginfo(LexicalUtilities.getStemming4Word("Prolactin") + " " + LexicalUtilities.getStemming4Word("brachii") + "\n");
		
		
		
		LogOutput.print("Time initializing lexical utilities (s): " + StatisticsTimeMappings.getRunningTime(init));
		StatisticsTimeMappings.addUpperbound_mappings_time(StatisticsTimeMappings.getRunningTime(init));
		
		
		//init = StatisticsTimeMappings.getCurrentTimeInMillis();
		//PrecomputeIndexCombination.preComputeIdentifierCombination();
		//
		//LogOutput.print("Time precomputing index combinations (s): " + StatisticsTimeMappings.getRunningTime(init));
		
	}
	
	
	
	private void OverlappingEstimation(String iri1_str, String iri2_str) throws Exception{
		
		LogOutput.print("OVERLAPPING");
		init = StatisticsTimeMappings.getCurrentTimeInMillis();
		
		//Overlapping to store and compare 
		//overlappingExtractor = new LexicalOverlappingExtractor(gs_mappings, logmap_mappings, iri1_str_out, iri2_str_out);
		
		//Overlapping to be used in the normal behaviour
		//No overlapping if size onto <10,000 entities (see parameters file)
		if (!Parameters.use_overlapping){
			overlappingExtractor = new NoOverlappingExtractor();
		}
		else{
			overlappingExtractor = new LexicalOverlappingExtractor(lexicalUtilities, true);
		}

		
		overlappingExtractor.createOverlapping(iri1_str, iri2_str);
		
		LogOutput.printAlways("Entities ontology 1: " + overlappingExtractor.getBaseOverlappedEntities1().size());
		LogOutput.printAlways("Entities ontology 2: " + overlappingExtractor.getBaseOverlappedEntities2().size());
		
		LogOutput.print("Time extracting overlapping (s): " + StatisticsTimeMappings.getRunningTime(init));
	}
	
	private void OverlappingEstimation(OWLOntology onto1, OWLOntology onto2) throws Exception{
		
		LogOutput.print("OVERLAPPING");
		init = StatisticsTimeMappings.getCurrentTimeInMillis();
		
		//Overlapping to store and compare 
		//overlappingExtractor = new LexicalOverlappingExtractor(gs_mappings, logmap_mappings, iri1_str_out, iri2_str_out);
		
		//Overlapping to be used in the normal behaviour
		//No overlapping if size onto <10,000 entities (see parameters file)
		if (!Parameters.use_overlapping){
			overlappingExtractor = new NoOverlappingExtractor();
		}
		else{
			overlappingExtractor = new LexicalOverlappingExtractor(lexicalUtilities, true);
		}

		
		overlappingExtractor.createOverlapping(onto1, onto2);
		
		LogOutput.print("Time extracting overlapping (s): " + StatisticsTimeMappings.getRunningTime(init));
	}
	
	
	private void IndexLexiconAndStructure() throws Exception{
		IndexLexiconAndStructure(new HashSet<MappingObjectStr>());
	}
	
	private void IndexLexiconAndStructure(Set<MappingObjectStr> input_mappings) throws Exception{
		
		//Create Index and new Ontology Index...
		index = new JointIndexManager();
		
		
		//Process ontologies: lexicon and taxonomy (class) and IFs
		onto_process1 = new OntologyProcessing(overlappingExtractor.getOverlappingOnto1(), index, lexicalUtilities);
		onto_process2 = new OntologyProcessing(overlappingExtractor.getOverlappingOnto2(), index, lexicalUtilities);
		
		
		//Extracts lexicon
		init = StatisticsTimeMappings.getCurrentTimeInMillis();
		onto_process1.precessLexicon();
		onto_process2.precessLexicon();
		
		LogOutput.print("Time extracting lexicon and IF (s): " + StatisticsTimeMappings.getRunningTime(init));
		
		//I guess can be deleted here
		lexicalUtilities.clearStructures();
		
		
		init = StatisticsTimeMappings.getCurrentTimeInMillis();
		//Init Mapping extractor: intersects IF and extract IF weak
		//mapping_extractor = new LexicalMappingExtractor(index, onto_process1, onto_process2);
		mapping_extractor = new CandidateMappingManager(index, onto_process1, onto_process2);
		
		//Statistics
		StatisticsManager.reInitValues();
		StatisticsManager.setMappingManager(mapping_extractor);
		
		
		//TODO Category mappings
		categoryMappingsLoader.loadMappings(Parameters.path_mappings_categories);
		mapping_extractor.setCategoryMappings(categoryMappingsLoader.getCategoryMappings());
		
		
		//Input mappings (e.g. composed mappings using MO given as input)
		mapping_extractor.processInputMappings(input_mappings);
		
		
		mapping_extractor.intersectInvertedFiles();
		
		LogOutput.print("Time intersecting IF and extracting IF weak (s): " + StatisticsTimeMappings.getRunningTime(init));
		//System.out.println("Time intersecting IF and extracting IF weak (s): " + StatisticsTimeMappings.getRunningTime(init));
		
		//Clear ontology stemmed labels 
		onto_process1.clearStemmedLabels();
		onto_process2.clearStemmedLabels();
		
		//Extracts Taxonomy
		//Also extracts A^B->C
		init = StatisticsTimeMappings.getCurrentTimeInMillis();
		onto_process1.setTaxonomicData();
		onto_process2.setTaxonomicData();
		
		LogOutput.print("Time extracting structural information (s): " + StatisticsTimeMappings.getRunningTime(init));
		
		
		//TODO Remove!!
		//if (!gs_mappings.equals("")){
		//	loadMappingsGS();
		//}
		
		
		
		//Keep only TBOX axioms to extract final module
		if (logmap_mappings_path.equals("")){ // no output files for overlappings
			if (!evaluate_impact){
				overlappingExtractor.clearModulesOverlapping();//Not necessary if we do no provide output
			}
		}
		else {
			overlappingExtractor.keepOnlyTBOXOverlapping(!evaluate_impact);
		}
		
		
		
		
		//We do not need the references to OWLEntities anymore
		onto_process1.clearOntologyRelatedInfo();
		onto_process2.clearOntologyRelatedInfo();

		/*
		loadMappingsGS(gs_mappings);
		printStatisticsGoldStandard();
		if (true)
		{
			LogOutput.print("finished!");
			return ;
		}
		*/
		
		
		//We first create weak anchors to be used for scopes
		init = StatisticsTimeMappings.getCurrentTimeInMillis();
		mapping_extractor.extractAllWeakMappings();
		
		LogOutput.print("Time creating all weak anchors (s): " + StatisticsTimeMappings.getRunningTime(init));
		
		
		//Extract subsets from all weak mappings to evaluate later
		//----------------------------------------------------------
		init = StatisticsTimeMappings.getCurrentTimeInMillis();
		mapping_extractor.extractCandidatesSubsetFromWeakMappings();
		
		LogOutput.print("Time creating candidate subset of weak anchors (s): " + StatisticsTimeMappings.getRunningTime(init));
		
		
		//Remove structures used for frequency extractor
		
		//Frequency structures
		onto_process1.clearFrequencyRelatedStructures();
		onto_process2.clearFrequencyRelatedStructures();
		index.clearSingleWordInvertedIndex();
		
		//Only used by frequency-like weak mappings
		index.clearStemmedAlternativeLabels4Classes();
		
		
	}
	
	
	private void createAndCleanAnchors() throws Exception{
		createAndCleanAnchors(false);
	}
	
	
	
	private void createAndCleanAnchors(boolean are_input_mapping_validated) throws Exception{
		
		LogOutput.printAlways("\nANCHOR DIAGNOSIS ");
		
		
		//TODO test for mouse 2 anatomy
		//Background knowledge: mappings composition
		//((CandidateMappingManager)mapping_extractor).createCandidatesFromBackgroundKnowledge();
		//getPrecisionAndRecallMappings();
		
		
		init = StatisticsTimeMappings.getCurrentTimeInMillis();
		mapping_extractor.createAnchors(are_input_mapping_validated);
		
		//Create different groups: "exact", ambiguity and no_scope (different sets...). We will add them later (almost done)
		
		
		LogOutput.printAlways("Time creating anchors (s): " + StatisticsTimeMappings.getRunningTime(init));
		
		
		
		
		//if (true){
		//	return ;
		//}
		
		//Tests
		//outputMappings(mapping_extractor.getAnchors(), logmap_mappings_path + "good.txt");
		
		
		
		
		countAnchors();
		mappings_assessment = new AnchorAssessment(index, mapping_extractor);
		
				
		if (Parameters.cleanD_G){
		
			//Only for statistical purposes or to extract global infor			
			if (Parameters.extractGlobal_D_G_Info){
				init = StatisticsTimeMappings.getCurrentTimeInMillis();
				mappings_assessment.CountSatisfiabilityOfIntegration_DandG(mapping_extractor.getLogMapMappings());
				
				LogOutput.printAlways("Time checking satisfiability D&G (s): " + StatisticsTimeMappings.getRunningTime(init));
			}
			
			
			init = StatisticsTimeMappings.getCurrentTimeInMillis();
			mappings_assessment.CheckSatisfiabilityOfIntegration_DandG(mapping_extractor.getLogMapMappings());
			
			LogOutput.printAlways("Time cleaning anchors D&G (s): " + StatisticsTimeMappings.getRunningTime(init));
		}
		
		//After repairing exact
		mapping_extractor.setExactAsFixed(true);
		mapping_extractor.saveAnchors(); //we save anchors in new structure so that we can retrieve them at the end of the process
		
		countAnchors();
		
		
		//TODO extract further disjointness based on weak anchors and mappings
		
		
		
		//INTERVAL LABELLING SCHEMA
		//--------------------------
		init = StatisticsTimeMappings.getCurrentTimeInMillis();
		
		//Index already have the necessary taxonomical information apart from the equiv mappings

		index.setIntervalLabellingIndex(mapping_extractor.getFixedMappings());
		
		index.clearAuxStructuresforLabellingSchema();
		
		
		LogOutput.printAlways("Time indexing hierarchy + anchors (ILS) (s): " + StatisticsTimeMappings.getRunningTime(init));
		
	}
	
	
	
	
	private void countAnchors(){
		
		int numMappings = 0;
		
		for (int ide1: mapping_extractor.getLogMapMappings().keySet()){
			for (int ide2: mapping_extractor.getLogMapMappings().get(ide1)){
			
				if (ide1<ide2)
					numMappings++;
				
			}
			
			
			
		}
		
		LogOutput.print("\nNum Anchors: " + numMappings + "\n");
		
		
	}
	
	
	
	private void createCandidateMappings() throws Exception{
		
		LogOutput.printAlways("\nCANDIDATE DIAGNOSIS 1");
		
		//After this method we will have 3 sets: Mappings2Review with DandG, Mappings to ask user, and discarded mappoings
		
		init = StatisticsTimeMappings.getCurrentTimeInMillis();
		mapping_extractor.createCandidates();
		
		
		//TODO
		//Delete Alt labels in class index
		//We won't extract more mappings
		//TODO Remove later on to extract lexical scores
		//index.clearAlternativeLabels4Classes();
		
		
		LogOutput.printAlways("Time creating candidates (s): " + StatisticsTimeMappings.getRunningTime(init));
		
		
		//Uncomment if no fixed anchors
		//We add candidates to anchors, nothing noew is fixed
		//mapping_extractor.setExactAsFixed(false);
		//mapping_extractor.moveMappingsToReview2AnchorList();
		
		
		//Clean with Dawling and Gallier mappings 2 review
		//-- D&G
		//countAnchors();
		//mappings_assessment = new AnchorAssessment(index, mapping_extractor);
		init = StatisticsTimeMappings.getCurrentTimeInMillis();
		if (Parameters.cleanD_G){
			
			
			//Only for statistical purposes or to extract global infor			
			if (Parameters.extractGlobal_D_G_Info){
				init = StatisticsTimeMappings.getCurrentTimeInMillis();
				mappings_assessment.CountSatisfiabilityOfIntegration_DandG(mapping_extractor.getMappings2Review());
				
				LogOutput.printAlways("Time checking satisfiability D&G (s): " + StatisticsTimeMappings.getRunningTime(init));
			}
			
