/*******************************************************************************
 * Copyright 2012 by the Department of Computer Science (University of Oxford)
 * 
 *    This file is part of LogMap.
 * 
 *    LogMap is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Lesser General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 * 
 *    LogMap is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Lesser General Public License for more details.
 * 
 *    You should have received a copy of the GNU Lesser General Public License
 *    along with LogMap.  If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/
package uk.ac.ox.krr.logmap2.mappings;

import java.util.ArrayList;

import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import uk.ac.ox.krr.logmap2.Parameters;
import uk.ac.ox.krr.logmap2.indexing.IndexManager;
import uk.ac.ox.krr.logmap2.io.LogOutput;
import uk.ac.ox.krr.logmap2.io.OutPutFilesManager;
import uk.ac.ox.krr.logmap2.interactive.objects.MappingObjectInteractivity;
import uk.ac.ox.krr.logmap2.mappings.objects.MappingObjectStr;
import uk.ac.ox.krr.logmap2.utilities.Utilities;


/**
 * This class defines the basic methods to provide the anchors between two ontologies
 * Mappings have been used to index mappings and their direction then the entry ide_a:{id_b, id_bb} will 
 * represent the mappings ide_a->ide_b and ide_a->ide_bb (with the exception of structures representing equivalence mappings.) 
 * 
 * 
 * @author ernesto
 *
 */
public abstract class MappingManager {
	
	long init, fin;

	protected IndexManager index;
	
	/**Necessary for statistic purposes*/
	protected Map<Integer, Set<Integer>> GSMappings1N = new HashMap<Integer, Set<Integer>>();
	
	/**Anchor mappings. They represent "safe" mappings, high lexical similarity and with scope.
	 * They will be used as reference to asses/clean other candidates. We store mappings and implicitly the dir.*/
	protected Map<Integer, Set<Integer>> anchorMappings1N = new HashMap<Integer, Set<Integer>>();
	
	
	/** LogMap Mappings: they grow from anchors to the final set of output mappings **/
	protected Map<Integer, Set<Integer>> logmapMappings1N = new HashMap<Integer, Set<Integer>>();
	
	/** Mappings from IF exact which must be assessed; or "repechaged" from 2ask (logmap or user)*/
	protected Map<Integer, Set<Integer>> mappings2Review = new HashMap<Integer, Set<Integer>>();
	
	
	
	/**We store mappings and implicitely the dir. MAPPINGS TO BE ASKED TO LOGMAP AMBIGUITY HEURISTICS*/
	protected Map<Integer, Set<Integer>> candidateMappings2askLogMap1N = new HashMap<Integer, Set<Integer>>();
	
	
	/**We store mappings equiv mappings*/
	protected Map<Integer, Set<Integer>> candidateMappings2askUser1N = new HashMap<Integer, Set<Integer>>();
	
	
	/**List of mappings objects. Mappings to ask to the user*/	
	//protected List<MappingObjectInteractivity> listMappings2askUser1N = new ArrayList<MappingObjectInteractivity>();
	protected Set<MappingObjectInteractivity> listMappings2askUser1N = new HashSet<MappingObjectInteractivity>();
	

	/**Split mappings with Dawling and Gallier**/
	protected Map<Integer, Set<Integer>> weakenedDandG_Mappings1N = new HashMap<Integer, Set<Integer>>();
	
	/** Discarded mappings by LogMap*/
	protected Map<Integer, Set<Integer>> discardedMappings1N = new HashMap<Integer, Set<Integer>>();
	
	/** Hard Discarded mappings by LogMap, should not be retrieved*/
	protected Map<Integer, Set<Integer>> hardDiscardedMappings1N = new HashMap<Integer, Set<Integer>>();
	
	/** Mappings selected by user (only interactive process)*/
	protected Map<Integer, Set<Integer>> interactiveProcessMappings1N = new HashMap<Integer, Set<Integer>>();
	
	/**Mappings that cause an error with D&G or are in conflict with exact mappings wrt interval labelling schema*/
	protected Map<Integer, Set<Integer>> conflictiveMappings1N = new HashMap<Integer, Set<Integer>>();
	
	/**Only mappings that cause an error with D&G**/
	protected Map<Integer, Set<Integer>> conflictiveMappings1N_D_G = new HashMap<Integer, Set<Integer>>();
	
	
	/**Subset of weak mappings to be considered as candidates**/
	protected Map<Integer, Set<Integer>> weakCandidateMappings1N = new HashMap<Integer, Set<Integer>>();
	
	
	/**All possible mappings. Will be used for scope purposes*/ 
	protected Map<Integer, Set<Integer>> allWeakMappings1N = new HashMap<Integer, Set<Integer>>();
	
	
	protected Map<Integer, Integer> dataPropertyMappings = new HashMap<Integer, Integer>();
	protected Map<Integer, Integer> objPropertyMappings = new HashMap<Integer, Integer>();
	
	protected Map<Integer, Double> dataPropertyMappings2confidence = new HashMap<Integer, Double>();
	protected Map<Integer, Double> objPropertyMappings2confidence = new HashMap<Integer, Double>();
	
	private Map<Integer, Map<Integer,Double>> anchor2scopeAll = new HashMap<Integer, Map<Integer,Double>>();
	private Map<Integer, Map<Integer,Double>> anchor2scopeAnchors = new HashMap<Integer, Map<Integer,Double>>();
	private Map<Integer, Map<Integer,Double>> anchor2isub = new HashMap<Integer, Map<Integer,Double>>();
	private Map<Integer, Map<Integer,Double>> anchor2isub_avg = new HashMap<Integer, Map<Integer,Double>>();
	private Map<Integer, Map<Integer,Double>> anchor2sim_weak = new HashMap<Integer, Map<Integer,Double>>();
	private Map<Integer, Set<Integer>> anchor2addedByUser = new HashMap<Integer, Set<Integer>>();
	

	protected Map<Integer, Set<Integer>> instanceMappings1N = new HashMap<Integer, Set<Integer>>();
	protected Map<Integer, Set<Integer>> instanceMappings1N_inverted = new HashMap<Integer, Set<Integer>>(); //only for queries and statistic purposes
	protected Map<Integer, Map<Integer,Double>> instanceMappings2isub = new HashMap<Integer, Map<Integer,Double>>();
	protected Map<Integer, Map<Integer,Double>> instanceMappings2compfactor = new HashMap<Integer, Map<Integer,Double>>();
	protected Map<Integer, Map<Integer,Double>> instanceMappings2scope = new HashMap<Integer, Map<Integer,Double>>();
	
	protected Map<Integer, Set<Integer>> instanceMappings1N_not_allowed_output = new HashMap<Integer, Set<Integer>>();
	
	protected Map<Integer, Set<Integer>> instanceMappings1N_ambiguity  = new HashMap<Integer, Set<Integer>>();
	
	
	//0: ok, 1: disc1, 2: disc2, 3: incompatible
	protected Map<Integer, Map<Integer,Integer>> instanceMappings2outputtype = new HashMap<Integer, Map<Integer,Integer>>();
	
	
	/**For statictics purposes*/
	protected Set<MappingObjectStr> discarded_candidates = new HashSet<MappingObjectStr>();
	
	/** For P&R purposes*/
	protected Set<MappingObjectStr> mappings_candidates_Str = new HashSet<MappingObjectStr>();
	protected Set<MappingObjectStr> mappings_GS_Str = new HashSet<MappingObjectStr>();
	
	
	/** Category mappings (relevant for instance matching) **/
	protected Map<String, Set<String>> category_mappings = new HashMap<String, Set<String>>();
	
	
	double weightIsub=0.5;
	double weightIsub_avg=0.0;//not used
	double weightScope=0.3;
	double weightScopeAnchors=0.2;
	
	I_Sub isub = new I_Sub();
	
	
	private boolean areExactFixed=false;
	
	private boolean filterWithHeuristicsInteractivity = true;
	
	
	//Statistical purposes (DISCARDED)
	//Type 0
	protected int goodAmb4=0;
	protected int badAmb4=0;
	//Type 1
	protected int goodDangEquiv=0;
	protected int badDangEquiv=0;
	//Type 2
	protected int goodAmbigExact=0;
	protected int badAmbigExact=0;
	//Type 3
	protected int goodConfidence=0;
	protected int badConfidence=0;
	
	
	
	
	
	
	
	protected void isHardMappingInGS(int ide1, int ide2, int type){
		if (isMappingInGoldStandard(ide1, ide2)){
			switch(type){
				case 0: 
					goodAmb4++;
					break;
				case 1:
					goodDangEquiv++;
					break;
				case 2:
					goodAmbigExact++;
					break;
				case 3:
					goodConfidence++;
					break;
			}
		}
		else {
			switch(type){
				case 0: 
					badAmb4++;
					break;
				case 1:
					badDangEquiv++;
					break;
				case 2:
					badAmbigExact++;
					break;
				case 3:
					badConfidence++;
					break;
			}
		}
	}
	
	
	public void printHarDiscardedStatistics(){
		
		LogOutput.print("Good Amb 4: " + goodAmb4);
		LogOutput.print("Bad Amb 4: " + badAmb4);
		
		LogOutput.print("Good DangEqui: " + goodDangEquiv);
		LogOutput.print("Bad DangEqui: " + badDangEquiv);
		
		LogOutput.print("Good AmbigExact: " + goodAmbigExact);
		LogOutput.print("Bad AmbigExact: " + badAmbigExact);
		
		LogOutput.print("Good Confidence: " + goodConfidence);
		LogOutput.print("Bad Confidence: " + badConfidence);
		
	}
	
	
	/**
	 * If no interactivity, mappings are filtered using automatic heuristics, 
	 * if this flag is set to true. Otherwise, former mappings 2 ask user are 
	 * added automatically
	 * @return the filterWithHeuristicsInteractivity
	 */
	public boolean isFilterWithHeuristicsSecondLevelMappings() {
		return filterWithHeuristicsInteractivity;
	}


	/**
	 * If no interactivity, mappings are filtered using automatic heuristics, 
	 * if this flag is set to true. Otherwise, former mappings 2 ask user are 
	 * added automatically
	 * @param filterWithHeuristicsInteractivity the filterWithHeuristicsInteractivity to set
	 */
	public void setFilterWithHeuristicsSecondLevelMappings(
			boolean filterWithHeuristicsInteractivity) {
		this.filterWithHeuristicsInteractivity = filterWithHeuristicsInteractivity;
	}


	//Not necessary for every extractor
	public void intersectInvertedFiles(){
		
	}
	
	
	public abstract void processInputMappings(Set<MappingObjectStr> mappings);
	
	/*public void clearIntersectedInvertedFilesExact(){
	}
	
	public void clearIntersectedInvertedFilesStemmingAndWeak(){
	}
	
	public void clearIntersectedInvertedFiles4Properties(){
		
	}*/
	
	public void assesWeakenedMappingsDandG2(boolean removeAfterwards, boolean add2Anchors){
		//weakenedDandG_Mappings1N
	}
	
	public void assessMappings2AskUser(){
		
	}
	
	
	
	public abstract void createAnchors();
	
	public abstract void createCandidates();	
	
	
	public abstract void createDataPropertyAnchors();
	
	public abstract void createObjectPropertyAnchors();
	
	public abstract void createInstanceAnchors();
	
	public abstract void extractAllWeakMappings();
	
	public abstract void extractCandidatesSubsetFromWeakMappings();
	
	
	
	public int getEntityAmbiguity_LogMapMappings(int ide){
		// Side 
		int amb=0;
		
		if (getLogMapMappings().containsKey(ide)){
			amb += getLogMapMappings().get(ide).size();
		}
		
		if (getToAskLogMapMappings().containsKey(ide)){
			amb += getToAskLogMapMappings().get(ide).size();
		}
		
		return amb;
			
	}
	
	public int getEntityAmbiguity_UserMappings(int ide){
		// Side 
		int amb=0;
		
		if (getLogMapMappings().containsKey(ide)){
			amb += getLogMapMappings().get(ide).size();
		}
		
		if (getToAskUserMappings().containsKey(ide)){
			amb += getToAskUserMappings().get(ide).size();
		}
		
		return amb;
			
	}
	
	
	
	/*public Set<Integer> getMappedEntitiesOnto1(){
		return mapped_entities_onto1;
	}
	
	public Set<Integer> getMappedEntitiesOnto2(){
		return mapped_entities_onto2;
	}*/
	
	
	public boolean isEntityAlreadyMapped(int index){
		return logmapMappings1N.containsKey(index); //If the entry was deleted if should be then in discarded entries!!!
	}
	
	
	
	public boolean isEntityInCandidates2AskUser(int index){
		return candidateMappings2askUser1N.containsKey(index); 
	}
	
	public boolean isEntityInCandidates2AskLogMap(int index){
		return candidateMappings2askLogMap1N.containsKey(index); 
	}
	
	/**
	 * This method must only be used when only exact mappings are considered since treats the maps as 1 to 1  
	 * @param index
	 * @return
	 */
	public int getTargetEntity4Index(int index){
		if (logmapMappings1N.containsKey(index)){
			for (int ide2 : logmapMappings1N.get(index))
				return ide2;
		}
			
		return -1;//in case there is no entity
	}
	
	
	public Set<Integer> getTargetEntities4Index(int index){
		if (logmapMappings1N.containsKey(index)){
			return logmapMappings1N.get(index);
		}
			
		return Collections.emptySet();
	}
	

	public void removeSubMappingFromStructure(int ide1, int ide2){ //only one direction
		if (logmapMappings1N.containsKey(ide1)){
			logmapMappings1N.get(ide1).remove(ide2);
			if (logmapMappings1N.get(ide1).size()==0){
				logmapMappings1N.remove(ide1);
			}
		}
	}
	
	
	public void removeSubMappingFromMappings2Review(int ide1, int ide2){ //only one direction
		if (mappings2Review.containsKey(ide1)){
			mappings2Review.get(ide1).remove(ide2);
			if (mappings2Review.get(ide1).size()==0){
				mappings2Review.remove(ide1);
			}
		}
		
	}
	
	
	
	public void removeSubMappingFromConflictive_D_G(int ide1, int ide2){ //only one direction
		if (conflictiveMappings1N_D_G.containsKey(ide1)){
			conflictiveMappings1N_D_G.get(ide1).remove(ide2);
			if (conflictiveMappings1N_D_G.get(ide1).size()==0){
				conflictiveMappings1N_D_G.remove(ide1);
			}
		}
		
	}
	
	
	
	
	
	
	
	public void removeSubMappingFromWeakenedDandGMappings(int ide1, int ide2){ //only one direction
		if (weakenedDandG_Mappings1N.containsKey(ide1)){
			weakenedDandG_Mappings1N.get(ide1).remove(ide2);
			if (weakenedDandG_Mappings1N.get(ide1).size()==0){
				weakenedDandG_Mappings1N.remove(ide1);
			}
		}
	}
	
	
	public void removeSubMappingFromDiscarded(int ide1, int ide2){ //only one direction
		if (discardedMappings1N.containsKey(ide1)){
			discardedMappings1N.get(ide1).remove(ide2);
			if (discardedMappings1N.get(ide1).size()==0){
				discardedMappings1N.remove(ide1);
			}
		}
	}
	
	/**
	 * Removes mappings and adds it to ambiguosmappimgs
	 * @param ide1
	 * @param ide2
	 */
	protected void removeAmbiguousFullMappingFromStructure(int ide1, int ide2, double min_average_isub){
		
		removeSubMappingFromStructure(ide1, ide2);
		removeSubMappingFromStructure(ide2, ide1);
		
		if (extractISUBAverage4Mapping(ide1, ide2) < min_average_isub){
			addEquivMapping2DiscardedAnchors(ide1, ide2);
		}
		else{
			addMapping2ListOfAnchors2AskLogMap(ide1, ide2);
		}
	}
	
	
	/**
	 * Removes mappings and adds it to mappings2review
	 * @param ide1
	 * @param ide2
	 */
	protected void moveMapping2ReviewList(int ide1, int ide2){
		
		removeSubMappingFromStructure(ide1, ide2);
		removeSubMappingFromStructure(ide2, ide1);
		
		//OJO!!
		//addEquivMapping2Mappings2Review(ide2, ide1);
		addSubMapping2Mappings2Review(ide1, ide2);//only one side
	
	}
	
	
	/*
	public boolean isEntityAlreadyMappedOnto2(int index){
		return mapped_entities_onto2.contains(index);
	}*/
	
	
	
	public void saveAnchors() {
		anchorMappings1N.putAll(logmapMappings1N);
	}
	
	
	
	public void setExactAsFixed(boolean set){
		areExactFixed=set;
	}
	
	public Map<Integer, Set<Integer>> getFixedMappings(){
		if (areExactFixed)
			return logmapMappings1N;
		else
			return Collections.EMPTY_MAP;
	}
	
	
	/**
	 * Highly precise mappings
	 * @return
	 */
	public Map<Integer, Set<Integer>> getAnchors(){
		return anchorMappings1N;
	}
	
	
	public Map<Integer, Set<Integer>> getLogMapMappings(){
		return logmapMappings1N;
	}
	
	
	public int getDirMapping(int ide1, int ide2){
		
		if (isId1SmallerThanId2(ide1, ide2)){
			
			if (isMappingAlreadyInList(ide2, ide1)){
				return Utilities.EQ;
			}
			else {
				return Utilities.L2R;
			}
		}
		else {
			
			if (isMappingAlreadyInList(ide2, ide1)){
				return Utilities.NoMap; //Already considered
			}
			else {
				return Utilities.R2L;
			}
		}
	}
	
	
	public Map<Integer, Set<Integer>> getMappings2Review(){
		return mappings2Review;
	}
	
	
	public Map<Integer, Set<Integer>> getToAskUserMappings(){
		return candidateMappings2askUser1N;
	}
	
	
	
	//public List<MappingObjectInteractivity> getListOfMappingsToAskUser(){
	public Set<MappingObjectInteractivity> getListOfMappingsToAskUser(){
		return listMappings2askUser1N;
	}
	
	
	//Assumes it is equiv and class ampping
	public void addMappingObject2AskUserList(int index1, int index2){
		//listMappings2askUser1N.add(new MappingObjectInteractivity(index1, index2, ambiguity));
		listMappings2askUser1N.add(new MappingObjectInteractivity(
				index1, index2, Utilities.EQ, extractScopeAll4Mapping(index1, index2), extractISUB4Mapping(index1, index2)));
		
		
	}
	
	
	public void addMappingObject2AskUserList(int index1, int index2, int dirMapping, int type){
		//listMappings2askUser1N.add(new MappingObjectInteractivity(index1, index2, ambiguity));
		listMappings2askUser1N.add(new MappingObjectInteractivity(
				index1, index2, dirMapping, type, extractScopeAll4Mapping(index1, index2), extractISUB4Mapping(index1, index2)));
	}
	
	
	
	public Map<Integer, Set<Integer>> getToAskLogMapMappings(){
		return candidateMappings2askLogMap1N;
	}
	
	
	
	
	
	public Map<Integer, Set<Integer>> getWeakAnchors(){
		return allWeakMappings1N;
	}
	
	public Map<Integer, Set<Integer>> getWeakCandidateAnchors(){
		return weakCandidateMappings1N;
	}
	
	
	public void clearWeakCandidateAnchors(){
		weakCandidateMappings1N.clear();
	}
	
	
	
	public Map<Integer, Integer> getDataPropertyAnchors(){
		return dataPropertyMappings;
	}
	
	public Map<Integer, Integer> getObjectPropertyAnchors(){
		return objPropertyMappings;
	}
	
	
	public Map<Integer, Set<Integer>> getInstanceMappings(){
		return instanceMappings1N;
	}
	
	/**
	 * Only for statistics
	 */
	public Map<Integer, Map<Integer,Integer>> getInstanceMappings4OutputType(){
		return instanceMappings2outputtype;
	}
	
	
	
	public void addDataPropertyAnchor(int ide1, int ide2){
		dataPropertyMappings.put(ide1, ide2);
	}
	
	
	public void addObjectPropertyAnchor(int ide1, int ide2){
		objPropertyMappings.put(ide1, ide2);
	}
	
	public void addDataPropertyAnchorConfidence(int ide1, double conf){
		dataPropertyMappings2confidence.put(ide1, conf);
	}
	
	
	public void addObjectPropertyAnchorConfidence(int ide1, double conf){
		objPropertyMappings2confidence.put(ide1, conf);
	}
	
	
	public void addInstanceAnchorConfidence(int ide1, int ide2, double conf){
		addIsub4Indivual(ide1, ide2, conf);
		addIsub4Indivual(ide2, ide1, conf);
	}
	
	
	
	
	
	
	
	
	public Map<Integer, Set<Integer>> getInstanceMappings_inverted(){
		return instanceMappings1N_inverted;
	}
	
	
	public int getSizeOfInstanceMappings(){
		int num=0;
		for (int ide1 : instanceMappings1N.keySet()){
			//for (int ide2 : instanceMappings1N.get(ide1)){	
			//	num++;
			//}
			num+=instanceMappings1N.get(ide1).size();
			
			/*if (instanceMappings1N.get(ide1).size()>1){
				//Ambiguity
				LogOutput.print("AMBIGUITY: " + index.getAlternativeLabels4IndividualIndex(ide1).toString());
				for (int ide2 : instanceMappings1N.get(ide1)){
					LogOutput.print("\t" +index.getAlternativeLabels4IndividualIndex(ide2).toString());
				}
				
			}*/
		}
		return num;
	}
	
	
	public boolean isIndividualAlreadyMapped(int ide){
		
		return instanceMappings1N.containsKey(ide) || instanceMappings1N_inverted.containsKey(ide) || instanceMappings1N_not_allowed_output.containsKey(ide) || instanceMappings1N_ambiguity.containsKey(ide);
		
	}
	
	
	
	public double getConfidence4DataPropertyAnchor(int ident1, int ident2){
		//return dataPropertyMappings2confidence.get(ident1); //currently mappings are only one 2 one
		if (dataPropertyMappings2confidence.containsKey(ident1)){
			return dataPropertyMappings2confidence.get(ident1); //currently mappings are only one 2 one
		}
		return 0.80;
	}
	
	public double getConfidence4ObjectPropertyAnchor(int ident1, int ident2){
		//return objPropertyMappings2confidence.get(ident1); //currently mappings are only one 2 one
		if (objPropertyMappings2confidence.containsKey(ident1)){
			return objPropertyMappings2confidence.get(ident1); //currently mappings are only one 2 one
		}
		return 0.80;
	}
	
	/**
	 * Returns ISUb confidence
	 * @param ident1
	 * @param ident2
	 * @return
	 */
	public double getConfidence4InstanceMapping(int ident1, int ident2){
		if (instanceMappings2isub.containsKey(ident1) && instanceMappings2isub.get(ident1).containsKey(ident2)){
			return instanceMappings2isub.get(ident1).get(ident2);
		}
		return 0.70; //we return something just in case
	}
	
	public double getISUB4InstanceMapping(int ident1, int ident2){
		if (instanceMappings2isub.containsKey(ident1) && instanceMappings2isub.get(ident1).containsKey(ident2)){
			return instanceMappings2isub.get(ident1).get(ident2);
		}
		return 0.70;
	}
	
	public double getCompFactor4InstanceMapping(int ident1, int ident2){
		if (instanceMappings2compfactor.containsKey(ident1) && instanceMappings2compfactor.get(ident1).containsKey(ident2)){
			return instanceMappings2compfactor.get(ident1).get(ident2);
		}
		return 0.50;
	}
	
	public double getScope4InstanceMapping(int ident1, int ident2){
		if (instanceMappings2scope.containsKey(ident1) && instanceMappings2scope.get(ident1).containsKey(ident2)){
			return instanceMappings2scope.get(ident1).get(ident2);
		}
		return 0.50;
	}
	
	
	public double getOutputType4InstanceMapping(int ident1, int ident2){
		if (instanceMappings2outputtype.containsKey(ident1) && instanceMappings2outputtype.get(ident1).containsKey(ident2)){
			return instanceMappings2outputtype.get(ident1).get(ident2);
		}
		return 0;
	}
	
	
	/*public List<MappingObjectIdentifiers> getAnchorObjects(){
		return identifier2anchor;
	}*/
	
	
	public Set<MappingObjectStr> getStringLogMapMappings(){
		return mappings_candidates_Str;
	}
	
	public Set<MappingObjectStr> getStringGoldStandardAnchors(){
		return mappings_GS_Str;
	}
	
	
	public Map<Integer, Set<Integer>> getDiscardedMappings(){
		return discardedMappings1N;
	}
	
	public Map<Integer, Set<Integer>> getHardDiscardedMappings(){
		return hardDiscardedMappings1N;
	}
	
	public Map<Integer, Set<Integer>> getMappingsInteractiveProcess(){
		return interactiveProcessMappings1N;
	}
	
	
	
	public Map<Integer, Set<Integer>> getConflictiveMappings(){
		return conflictiveMappings1N;
	}
	
	public Map<Integer, Set<Integer>> getWeakenedDandGMappings(){
		return weakenedDandG_Mappings1N;
	}
	
	public Set<MappingObjectStr> getDiscardedMappingsStr(){
		return discarded_candidates;
	}
	
	
	/**
	 * We add each direcction individually
	 * @param index1
	 * @param index2
	 */
	public void addSubMapping2ListOfAnchors(int index1, int index2){
		
		//mapped_entities_onto1.add(index1);
		//mapped_entities_onto2.add(index2);
		
		//Deprecated: We can implicitely store the dir in map!!
		//We need this structure to store the direction (type) of the mappings
		//MappingObjectIdentifiers mapping = new MappingObjectIdentifiers(index1, index2);
		//if (!identifier2anchor.contains(mapping)){
		//	identifier2anchor.add(mapping);
		//}
		
		if (!logmapMappings1N.containsKey(index1)){
			logmapMappings1N.put(index1, new HashSet<Integer>());
		}
		logmapMappings1N.get(index1).add(index2);
		
	}
	
	
	
	public void addInstanceMapping(int index1, int index2){
		addInstanceMapping(index1, index2, false);
	}
	
	
	
	/**
	 * Check if the instance is an allowed type
	 * @param types
	 * @param allowed_types
	 * @return
	 */
	private boolean hasAllowedType(Set<Integer> types){
		
		//No restrictions or empty set of allowed types
		if (!Parameters.isRestrictInstanceTypesActive() || index.getAllowedInstanceTypes().isEmpty())
			return true;
		
		
		for (int itype : types){
			//is class type listed as allowed
			if (index.getAllowedInstanceTypes().contains(itype))
				return true;
			
			for (int atype : index.getAllowedInstanceTypes()){
				//Is class type as subclass of allowed types 
				if (index.isSubClassOf(itype, atype))
						return true;
			}
		}
		
		return false;
		
	}
	
	/**
	 * We deal instance mappings as one side mappings. We only consider SameAs. 
	 * If during cleaning they are deleted then we do not consider mapping
	 * @param index1
	 * @param index2
	 */
	public void addInstanceMapping(int index1, int index2, boolean ambiguity){
			
		
		//If type is not allowed in the output
		//Old code
		//if (!index.getIdentifier2IndividualIndexMap().get(index1).showInOutput() ||
		//	!index.getIdentifier2IndividualIndexMap().get(index2).showInOutput()){
		//New code: August 28, 2017
		if (!hasAllowedType(index.getIdentifier2IndividualIndexMap().get(index1).getClassTypes()) ||
			!hasAllowedType(index.getIdentifier2IndividualIndexMap().get(index2).getClassTypes())){			
			
			if (!instanceMappings1N_not_allowed_output.containsKey(index1)){
				instanceMappings1N_not_allowed_output.put(index1, new HashSet<Integer>());
			}
			instanceMappings1N_not_allowed_output.get(index1).add(index2);
			
			
			return;
			
		}
		
		
		//We add to different structure for future revision
		if (ambiguity){
			
			if (!instanceMappings1N_ambiguity.containsKey(index1)){
				instanceMappings1N_ambiguity.put(index1, new HashSet<Integer>());
			}
			instanceMappings1N_ambiguity.get(index1).add(index2);
			
			
			return;
			
		}
		
		
		
		if (!instanceMappings1N.containsKey(index1)){
			instanceMappings1N.put(index1, new HashSet<Integer>());
		}
		instanceMappings1N.get(index1).add(index2);
		
		
		
		//Only for queries
		if (!instanceMappings1N_inverted.containsKey(index2)){
			instanceMappings1N_inverted.put(index2, new HashSet<Integer>());
		}
		instanceMappings1N_inverted.get(index2).add(index1);
		
	}
	
	
	
	/**
	 * By user in interactivity
	 * @param index1
	 * @param index2
	 * @param add2conflictive
	 */
	public void removeInstanceMappings(int index1, int index2){
		
		if (instanceMappings1N.containsKey(index1)){
			instanceMappings1N.get(index1).remove(index2);
			if (instanceMappings1N.get(index1).size()==0){
				instanceMappings1N.remove(index1);
			}
		}
	}
	
	
	
	public void addSubMapping2Mappings2Review(int index1, int index2){
		
		if (!mappings2Review.containsKey(index1)){
			mappings2Review.put(index1, new HashSet<Integer>());
		}
		mappings2Review.get(index1).add(index2);
	}
	
	
	public void moveMappingsToReview2AnchorList(){
		
		for (int ide1 : mappings2Review.keySet()){
			for (int ide2 : mappings2Review.get(ide1)){
				
				addSubMapping2ListOfAnchors(ide1, ide2);
				
			}
			
		}
		
	}
	
	
	
	
	
	
	
	
	/**
	 * We add equivalence mappings
	 * @param index1
	 * @param index2
	 */
	public void addMapping2ListOfAnchors2AskLogMap(int index1, int index2){
		
		if (!candidateMappings2askLogMap1N.containsKey(index1)){
			candidateMappings2askLogMap1N.put(index1, new HashSet<Integer>());
		}
		candidateMappings2askLogMap1N.get(index1).add(index2);
		
		
		//Add both sides for statistical purposes
		if (!candidateMappings2askLogMap1N.containsKey(index2)){
			candidateMappings2askLogMap1N.put(index2, new HashSet<Integer>());
		}
		candidateMappings2askLogMap1N.get(index2).add(index1);
		
	}
	
	
	
	/**
	 * We add equivalence mappings
	 * @param index1
	 * @param index2
	 */
	public void addEquivMapping2ListOfAnchors2AskUser(int index1, int index2){
		
		if (!candidateMappings2askUser1N.containsKey(index1)){
			candidateMappings2askUser1N.put(index1, new HashSet<Integer>());
		}
		candidateMappings2askUser1N.get(index1).add(index2);
		
		//Add both sides for statistical purposes
		if (!candidateMappings2askUser1N.containsKey(index2)){
			candidateMappings2askUser1N.put(index2, new HashSet<Integer>());
		}
		candidateMappings2askUser1N.get(index2).add(index1);
			
	}
	
	

	
	
	/**
	 * By user in interactivity
	 * @param index1
	 * @param index2
	 * @param add2conflictive
	 */
	public void removeEquivMappingFromListOfAnchors2AskUser(int index1, int index2){
		
		if (candidateMappings2askUser1N.containsKey(index1)){
			candidateMappings2askUser1N.get(index1).remove(index2);
			if (candidateMappings2askUser1N.get(index1).size()==0){
				candidateMappings2askUser1N.remove(index1);
			}
		}
	}
	
	
	
	/**
	 * By user in interactivity
	 * @param index1
	 * @param index2
	 * @param add2conflictive
	 */
	public void removeEquivMappingFromListOfAnchors2AskUser(int index1, int index2, boolean add2conflictive){
		
		if (candidateMappings2askUser1N.containsKey(index1)){
			candidateMappings2askUser1N.get(index1).remove(index2);
			if (candidateMappings2askUser1N.get(index1).size()==0){
				candidateMappings2askUser1N.remove(index1);
			}
		}
		
		if (add2conflictive){
			addSubMapping2ConflictiveAnchors(index1, index2);
			addSubMapping2ConflictiveAnchors(index2, index1);
		}
		else{
			addEquivMapping2DiscardedAnchors(index1, index2);
			addEquivMapping2DiscardedAnchors(index2, index1);
		}
		
	}
	
	
	
	
	/**
	 * We add equiv mappings
	 * @param index1
	 * @param index2
	 */
	
	int num_discarded=0;
	public void addEquivMapping2DiscardedAnchors(int index1, int index2){
		
		if (!discardedMappings1N.containsKey(index1)){
			discardedMappings1N.put(index1, new HashSet<Integer>());
		}
		if (!discardedMappings1N.get(index1).contains(index2)){
			num_discarded++;
			discardedMappings1N.get(index1).add(index2);
		}
		
		//Temporary: Add both sides
		/*if (!discardedMappings1N.containsKey(index2)){
			discardedMappings1N.put(index2, new HashSet<Integer>());
		}
		discardedMappings1N.get(index2).add(index1);
		*/
		
	}
	
	public int getNumDiscardedMappings(){
		return num_discarded;
	}
	
	
	
	/**
	 * We add equiv mappings
	 * @param index1
	 * @param index2
	 */
	public void addEquivMapping2HardDiscardedAnchors(int index1, int index2){
		
		//To save space and time
		if (!hardDiscardedMappings1N.containsKey(index1)){
			hardDiscardedMappings1N.put(index1, new HashSet<Integer>());
		}
		hardDiscardedMappings1N.get(index1).add(index2);
	}
	
	
	
	public void addEquivMapping2InteractiveMappings(int index1, int index2){
		
		if (!interactiveProcessMappings1N.containsKey(index1)){
			interactiveProcessMappings1N.put(index1, new HashSet<Integer>());
		}
		interactiveProcessMappings1N.get(index1).add(index2);
		
		
	}
	
	
	
	
	
	/**
	 * We add each mapping direcction individually
	 * Direction are discarded in pre-conflict detection and in D&G
	 * @param index1
	 * @param index2
	 */
	public void addSubMapping2ConflictiveAnchors(int index1, int index2){
		
		addSubMapping2ConflictiveAnchors(index1, index2, false);
	
	}
	
	public void addSubMapping2ConflictiveAnchors(int index1, int index2, boolean fromDG){
		
		if (!conflictiveMappings1N.containsKey(index1)){
			conflictiveMappings1N.put(index1, new HashSet<Integer>());
		}
		conflictiveMappings1N.get(index1).add(index2);
		
		
		if (fromDG){
			//We add mapping only conflictive in D&G
			//This may help us to retrieve them back in some cases
			if (!conflictiveMappings1N_D_G.containsKey(index1)){
				conflictiveMappings1N_D_G.put(index1, new HashSet<Integer>());
			}
			conflictiveMappings1N_D_G.get(index1).add(index2);
		}
	}
	
	public Map<Integer, Set<Integer>> getConflictiveMappings_D_G(){
		return conflictiveMappings1N_D_G;
	}
		
	
	
	/**
	 * We add each mapping direcction individually
	 * @param index1
	 * @param index2
	 */
	public void addSubMapping2WeakenedDandGAnchors(int index1, int index2){
		
		if (!weakenedDandG_Mappings1N.containsKey(index1)){
			weakenedDandG_Mappings1N.put(index1, new HashSet<Integer>());
		}
		weakenedDandG_Mappings1N.get(index1).add(index2);
		
		
	}
	
	
	
	public void addMapping2GoldStandardAnchors(int index1, int index2){
		
		if (!GSMappings1N.containsKey(index1)){
			GSMappings1N.put(index1, new HashSet<Integer>());
		}
		GSMappings1N.get(index1).add(index2);
		
		
	}
	
	public Map<Integer, Set<Integer>> getGoldStandardMappings()
	{
		return GSMappings1N;
	}
	
	
	public boolean isMappingInGoldStandard(int index1, int index2){  //it is important the order of the question!
		if (GSMappings1N.containsKey(index1)){
			if (GSMappings1N.get(index1).contains(index2)){
				return true;
			}
		}
		return false;
	}
	
	
	public boolean isMappingAlreadyInList(int index1, int index2){
		
		if (logmapMappings1N.containsKey(index1)){
			if (logmapMappings1N.get(index1).contains(index2)){
				return true;
			}
		}
		return false;
		
	}
	
	
	
	
	public boolean isMappingInList2Review(int index1, int index2){
		
		if (mappings2Review.containsKey(index1)){
			if (mappings2Review.get(index1).contains(index2)){
				return true;
			}
		}
		return false;
		
	}
	
	public boolean isMappingInAnchors2AskLogMap(int index1, int index2){
		
		if (candidateMappings2askLogMap1N.containsKey(index1)){
			if (candidateMappings2askLogMap1N.get(index1).contains(index2)){
				return true;
			}
		}
		return false;
		
	}
	
	

	public boolean isMappingInAnchors2AskUser(int index1, int index2){
		
		if (candidateMappings2askUser1N.containsKey(index1)){
			if (candidateMappings2askUser1N.get(index1).contains(index2)){
				return true;
			}
		}
		return false;
		
	}
	
	
	
	
