package uk.ac.ox.krr.logmap2.indexing;

import java.io.FileNotFoundException;
import java.util.ArrayList;


import java.util.HashSet;


import java.util.Calendar;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;

//import org.apache.commons.lang3.StringUtils;


import org.semanticweb.owlapi.model.*;
import org.semanticweb.owlapi.model.parameters.Imports;
import org.semanticweb.owlapi.reasoner.Node;
import org.semanticweb.owlapi.reasoner.NodeSet;
import org.semanticweb.owlapi.reasoner.OWLReasoner;
import org.semanticweb.owlapi.reasoner.impl.OWLClassNodeSet;
import org.semanticweb.owlapi.search.EntitySearcher;
import org.semanticweb.owlapi.search.Searcher;

import com.google.common.collect.Multimap;

import uk.ac.ox.krr.logmap2.Parameters;
import uk.ac.ox.krr.logmap2.indexing.entities.ClassIndex;
import uk.ac.ox.krr.logmap2.io.LogOutput;
import uk.ac.ox.krr.logmap2.lexicon.LexicalUtilities;
import uk.ac.ox.krr.logmap2.lexicon.NormalizeDate;
import uk.ac.ox.krr.logmap2.lexicon.NormalizeNumbers;
import uk.ac.ox.krr.logmap2.multilingual.TranslatorManager;
import uk.ac.ox.krr.logmap2.oaei.OAEI2015InstanceProcessing;
import uk.ac.ox.krr.logmap2.owlapi.SynchronizedOWLManager;
import uk.ac.ox.krr.logmap2.reasoning.ELKAccess;
import uk.ac.ox.krr.logmap2.reasoning.HermiTAccess;
import uk.ac.ox.krr.logmap2.reasoning.StructuralReasonerExtended;
import uk.ac.ox.krr.logmap2.reasoning.profiles.CheckOWL2Profile;
import uk.ac.ox.krr.logmap2.utilities.Lib;
import uk.ac.ox.krr.logmap2.utilities.PrecomputeIndexCombination;
import uk.ac.ox.krr.logmap2.utilities.Utilities;

/**
 * This class will extract the lexicon and structure of the given ontology
 * 
 *
 * @author Ernesto Jimenez-Ruiz
 * Created: Sep 12, 2011
 *
 */
public class OntologyProcessing {
	
	long init, fin;
	
	private OWLOntology onto;
	
	private IndexManager index;
	
	/*Exact match entries*/
	//protected Map<String, Integer> extact_occurrence_entries = new HashMap<String, Integer>();

	
	/**Exact match inverted file*/
	protected Map<Set<String>, Set<Integer>> invertedFileExact = new HashMap<Set<String>, Set<Integer>>();
	
	/**Exact match inverted file for data properties*/
	protected Map<Set<String>, Integer> invertedFileExactDataProp = new HashMap<Set<String>, Integer>();
	
	/**Exact match inverted file for object properties*/
	protected Map<Set<String>, Integer> invertedFileExactObjProp = new HashMap<Set<String>, Integer>();
	
	protected Map<Set<String>, Set<Integer>> invertedFileIndividuals = new HashMap<Set<String>, Set<Integer>>();
	//Only one word IF weak
	protected Map<String, Set<Integer>> invertedFileWeakIndividuals = new HashMap<String, Set<Integer>>();
	
	
	//Will contain a lexicon of the role assertions in indiv
	protected Map<String, Set<Integer>> invertedFileRoleassertions = new HashMap<String, Set<Integer>>();
	
	
	protected Map<Set<String>, Set<Integer>> invertedFileWeakLabelsStemming = new HashMap<Set<String>, Set<Integer>>();
	
	protected Map<Set<String>, Set<Integer>> invertedFileWeakLabels = new HashMap<Set<String>, Set<Integer>>();
	//protected Map<Set<String>, Set<Integer>> invertedFileWeakLabelsL2 = new HashMap<Set<String>, Set<Integer>>();
	//protected Map<Set<String>, Set<Integer>> invertedFileWeakLabelsL3 = new HashMap<Set<String>, Set<Integer>>();
	
	
	
	/**To index class names: necessary when loading GS and repairing mappings*/
	protected Map<String, Integer> className2Identifier = new HashMap<String, Integer>();
	
	/**To index data prop names: necessary when loading GS and repairing mappings*/
	protected Map<String, Integer> dataPropName2Identifier = new HashMap<String, Integer>();
	
	/**To index object prop names: necessary when loading GS and repairing mappings*/
	protected Map<String, Integer> objectPropName2Identifier = new HashMap<String, Integer>();
	
	/**To index instance names: necessary when loading GS and repairing mappings*/
	protected Map<String, Integer> individualName2Identifier = new HashMap<String, Integer>();
	
	
	/**USed when extracting taxonomy*/
	private Map<OWLClass, Integer> class2identifier = new HashMap<OWLClass, Integer>();
	private Map<String, Integer> classIri2identifier = new HashMap<String, Integer>();
	
	//For lexicon extraction. Indiv are related one to the other
	private Map<OWLNamedIndividual, Integer> inidividual2identifier = new HashMap<OWLNamedIndividual, Integer>();
	
	private Map<Integer, OWLClass> identifier2class = new HashMap<Integer, OWLClass>();
	
	//In this set we should include those classes we should not map
	//e.g. classes that are equivalent to Top (see cocus ontology)
	private Set<Integer> dangerousClasses = new HashSet<Integer>();
	
	
	private Set<String> alternative_labels_tmp = new HashSet<String>();
	
	
	//private HashMap<Integer, Set<Integer>> identifier2directkids= new HashMap<Integer, Set<Integer>>();	
	//private Map<Integer, Set<Integer>> identifier2directparents= new HashMap<Integer, Set<Integer>>();
	
	/**This set will be used to propagate equivalences (entities store equivalents)*/
	//TODO this set will need to be enriched with anchors... or at leats considered after indexing
	//In index
	//private Set<Integer> representativeNodes = new HashSet<Integer>();
	
	/* Importnat for a ordered assessment Now in index*/
	//protected Set<Integer> RootIdentifiers = new HashSet<Integer>();
	
	
	/*A^B->C axioms Now in Index*/
	//private Map<Set<Integer>, Integer> generalHornAxioms= new HashMap<Set<Integer>, Integer>();
	
	
	
	/** We use this structure to create weak labels*/
	//private Map<Integer, List<String>> identifier2stemmedlabel = new HashMap<Integer, List<String>>();
	//We also consider alternative labels
	private Map<Integer, Set<List<String>>> identifier2stemmedlabels = new HashMap<Integer, Set<List<String>>>();
	//Must be kept outside index to be removed after use and to attached to onto (i.e ontoprocessing object)
	
	/**
	 * Meaningful roots 
	 * @deprecated
	 */
	protected Set<Integer> MeaningfulRootIdentifiers = new HashSet<Integer>();
	/**Real roots 
	 * @deprecated
	 */
	protected Set<Integer> TaxRootIdentifiers = new HashSet<Integer>(); //The real ones
	
	
	//IRI labels annotations 
	private String rdf_label_uri = "http://www.w3.org/2000/01/rdf-schema#label";
	public static String deprecated_uri = "http://www.w3.org/2002/07/owl#deprecated";
	
	
	protected Set<OWLClass> obsolete_classes = new HashSet<OWLClass>();
	
	
	
	private String iri_onto = "http://krono.act.uji.es/ontology.owl";
	
	public String getOntoIRI() {return iri_onto; }
	
	private int id_onto;
	
	
	int num_syn=0;
	int toohigh_synset_cases=0;	
	
	
		
	private OWLReasoner reasoner;
	private int reasonerIdentifier;
	
	
	//TODO Ernesto: to avoid using all labels for weak mappings
	boolean use_all_labels_for_weak_mappings=false;
	
	
	private LexicalUtilities lexicalUtilities;
	
	private PrecomputeIndexCombination precomputeIndexCombination = new PrecomputeIndexCombination();
	
	private ExtractStringFromAnnotationAssertionAxiom annotationExtractor = new ExtractStringFromAnnotationAssertionAxiom();
	
	public ExtractAcceptedLabelsFromRoleAssertions roleAssertionLabelsExtractor = new ExtractAcceptedLabelsFromRoleAssertions();
	
	private ExtractCategoriesForIndividual categoryExtractor = new ExtractCategoriesForIndividual();
	
	
	//For multilingual module
	//private Translator translator = TranslatorManager.getCurrentTranslatorObject();
	private TranslatorManager translator = new TranslatorManager(Parameters.translator_id); //use all available translators
	
	
	
	/**
	 * 
	 * @param onto
	 * @param index
	 * @param lexicalUtilities
	 */
	public OntologyProcessing(OWLOntology onto, IndexManager index, LexicalUtilities lexicalUtilities){
		
		this.onto=onto;
		this.index=index;
		
		this.lexicalUtilities=lexicalUtilities;
		
		
		//We precompute indexes
		 //precomputeIndexCombination.clearCombinations(); //Old calls
		 precomputeIndexCombination.preComputeIdentifierCombination();
		
		
		//The preclassification with condor has no ontology id
		if (onto.getOntologyID().getOntologyIRI()!=null && onto.getOntologyID().getOntologyIRI().isPresent()){
			iri_onto=onto.getOntologyID().getOntologyIRI().get().toString();
		}
		//System.out.println(onto.getOntologyID());
		
		this.id_onto = this.index.addNewOntologyEntry(iri_onto);
		
		
		
	}
	
	public void clearOntologyRelatedInfo(){
		//TODO After extracting tax
		onto=null;
		class2identifier.clear();
		clearReasoner();
	}
	
	public Map<OWLClass, Integer> getClass2Identifier(){
		return class2identifier;
	}
	
	
	public int getIdentifier4ConceptIRI(String iri){
		if (classIri2identifier.containsKey(iri))
			return classIri2identifier.get(iri);
		else
			return -1;
	}
	
	
	public void clearInvertedFilesExact(){
		invertedFileExact.clear();
		//invertedFileExactDataProp.clear();
		//invertedFileExactObjProp.clear();	
	}
	
	public void clearInvertedFileStemming(){
	
		invertedFileWeakLabelsStemming.clear();
	}
	
	public void clearInvertedFileWeak(){
		
		invertedFileWeakLabels.clear();		

	}


	public void clearInvertedFilesStemmingAndWeak(){
	
		invertedFileWeakLabels.clear();		
		invertedFileWeakLabelsStemming.clear();
	}
	
	public void clearStemmedLabels(){
		//identifier2stemmedlabel.clear();
		identifier2stemmedlabels.clear();
	}
	
	public void clearInvertedFiles4properties(){
		invertedFileExactDataProp.clear();
		invertedFileExactObjProp.clear();
	}
	
	public void clearInvertedFiles4Individuals(){
		invertedFileIndividuals.clear();
		invertedFileWeakIndividuals.clear();
		invertedFileRoleassertions.clear();
	}
	
	
	

	
	
	
	
	
	/**
	 * @deprecated
	 * 
	 */
	private void clearTaxonomy(){
		//TODO after indexing or the global id2kids has been created 
		//identifier2directkids.clear();
		//identifier2directparents.clear();
		//representativeNodes.clear();
		//generalHornAxioms.clear();
	}
	
	
	public void clearReasoner(){
		//TODO after extracting tax!
		reasoner.dispose();
		reasoner=null;
	}
	
	
	
	public void precessLexicon() {
		precessLexicon(true);
	}
	
	/**
	 * We create a class identifier for each class, we also create inverted files
	 * 
	 */
	public void precessLexicon(boolean extractLabels) {
		
		
		init=Calendar.getInstance().getTimeInMillis();
		
		
		
		//LogOutput.print(onto.getClassesInSignature().size());
		
		//CLASSES				
		LogOutput.print("\nCLASSES: " + onto.getClassesInSignature(Imports.INCLUDED).size());
		
		//TODO
		//We need to add something
		//Was already fixed in a different place?
		//if (onto.getClassesInSignature(true).size()==0){
		//	OWLClass cls = SynchronizedOWLManager.createOWLDataFactory().getOWLClass(IRI.create("http://logmap.cs.ox.ac.uk/ontologies#TopClass"));
		//	precessLexiconClasses(cls, extractLabels);			
		//}
		//else {
		
		//TODO For the OAEI campaign we do not translate bigger ontologies
		//We have a limit in our google translate account
		if (onto.getClassesInSignature(Imports.INCLUDED).size()>300){
			Parameters.allow_multilingual=false;
		}
		
		
		//TODO Identify language and load local dictionary if any
		//Useful for the multifarm task where we need to translate each ontology servarl times.
		//Thus we translate for the first occurrence and we keep (locally) the translation for the next cases.
		//We assume that each ontology is in only one language 
		String lang="";
		if (Parameters.allow_multilingual){
			lang = identifyLanguageOfOntologyLabels();
			
			//System.out.println("LANGUAGE: " + lang);
			
			if (!lang.equals("") && !lang.equals(Parameters.target_lang)){
				//load dictionary 
				try {
					translator.loadDictionary(lang);
				} catch (FileNotFoundException e) {
					// TODO Auto-generated catch block
					LogOutput.printError("Dictionary file for '" + lang + "' not found.");// + e.getLocalizedMessage());
					//e.printStackTrace();
				}	
			}
				
			
		}
			
		
		 
		
		for (OWLClass cls : onto.getClassesInSignature(Imports.INCLUDED)){ //we also add imports
			
						
			if (!cls.isTopEntity() && !cls.isBottomEntity()){// && !ns_ent.equals(oboinowl)){
				
				processLexiconClasses(cls, extractLabels);
				
			}
				
		}//end For classes
		
		
		//DETECT HIGH REDUNDANCY ON EXACT IF
		//Added August 30, 2018
		if (Parameters.avoid_redundant_labels){
			Set<Integer> redundant_ids = new HashSet<Integer>();
			for (Set<String> entry : invertedFileExact.keySet()){
				if (invertedFileExact.get(entry).size()>Parameters.max_redundancy_labels){
					//Keep only entries for which only 1 alternative label exists
					for (int ident: invertedFileExact.get(entry)){
						if (index.getAlternativeLabels4ConceptIndex(ident).size()>1){//has lower case
							redundant_ids.add(ident);
						}
					}
					invertedFileExact.get(entry).removeAll(redundant_ids);
					redundant_ids.clear();
				}
			}
		}
		
		//System.out.println("NUM RDF LABEL: "+num_labels);
		
		
		//}//end If size classes
						
		
		//DATA PROPERTIES
		processLexiconDataProperties(extractLabels);
			
		
		
		//OBJECT PROPERTIES
		processLexiconObjectProperties(extractLabels);
		
		
		
		//INDIVIDUALS
		if (Parameters.perform_instance_matching){
			processNamedIndividuals(extractLabels);
			
			//DETECT HIGH REDUNDANCY ON EXACT IF
			//Added August 30
			
			if (Parameters.avoid_redundant_labels){
				Set<Integer> redundant_ids = new HashSet<Integer>();
				for (Set<String> entry : invertedFileIndividuals.keySet()){
					if (invertedFileIndividuals.get(entry).size()>Parameters.max_redundancy_labels){
						
						//if (entry.contains("sonates")){
						//	System.out.println("Redundancey: " + entry + "  " + invertedFileIndividuals.get(entry).size());
						//}
						
						//Keep only entries for which only 1 alternative label exists
						for (int ident: invertedFileIndividuals.get(entry)){
							
							//if (entry.contains("sonates")){
							//	System.out.println("\t" + ident + "  " + index.getAlternativeLabels4IndividualIndex(ident).size() + "  " + index.getAlternativeLabels4IndividualIndex(ident) + "  " + index.getIRIStr4IndividualIndex(ident));
							//}
							
							if (index.getAlternativeLabels4IndividualIndex(ident).size()>1){
								redundant_ids.add(ident);
							}
						}
						invertedFileIndividuals.get(entry).removeAll(redundant_ids);
						redundant_ids.clear();
					}
				}
			}
			
		}
		
		
		//Store local dictionary: es-en.txt
		//Add note that the dictionary is automatically extracted.
		if (Parameters.allow_multilingual){
			
			if (!lang.equals("") && !lang.equals(Parameters.target_lang)){
				
				//TODO we also store new translations if not in local or local is not allowed
				//store dictionary 
				translator.storeDictionary(lang);
				//}
				
				//TODO REMOVE if not testing!!!
				/*if (Parameters.is_test_mode_multilingual){
					WriteFile writer = new WriteFile(
							"/home/ernesto/Documents/OAEI_OM_2015/EVAL_2015/error_multilingual/total_characters_reduced.txt", true);
					//System.out.println("Num translated characters: " + translator.getNumberOfTranslatedCharacters());
					//System.out.println("Num calls to google: " + translator.getNumberOfGoogleTranslateCalls());
					writer.writeLine(String.valueOf(translator.getNumberOfTranslatedCharacters()));
					writer.closeBuffer();
				}*/
				
			}
			
		}
		
		
		
		
		
		
		LogOutput.print("Number of classes/labels: " + index.getSizeIndexClasses()); //Ojo it is a total
		LogOutput.print("\tNumber of labels + syn: " + num_syn);
		LogOutput.print("\tCases with huge combination of synonyms: " + toohigh_synset_cases);
		LogOutput.print("\tNumber of entries inverted file (exact): " + invertedFileExact.size());
		
		LogOutput.print("Number of dProp: " + index.getSizeDataProperties()); //Ojo it is a total
		LogOutput.print("\tNumber of dProp inverted file: " + invertedFileExactDataProp.size());
		
		LogOutput.print("Number of oProp: " + index.getSizeObjectProperties()); //Ojo it is a total
		LogOutput.print("\tNumber of oProp inverted file: " + invertedFileExactObjProp.size());
		
		LogOutput.print("Number of Indiv: " + index.getSizeIndexIndividuals()); //Ojo it is a total
		LogOutput.print("\tNumber of Indiv inverted file: " + invertedFileIndividuals.size());
		LogOutput.print("\tNumber of Indiv weak inverted file: " + invertedFileWeakIndividuals.size());
		LogOutput.print("\tNumber of Indiv Role assertions inverted file: " + invertedFileRoleassertions.size());
		
		
		
		
		/*int exactIFAmb=0;
		for (Set<String> setstr : invertedFileExact.keySet()){
			//LogOutput.print(setstr);
			if (invertedFileExact.get(setstr).size()>1)
				exactIFAmb++;
		}
		LogOutput.print("Ambiguity IF exact: " + exactIFAmb);*/
		
		
		//Labels are already indexed so we can safely remove annotations form onto
		//managerOnto.applyChanges(listchanges);
		
		
		/*for (int i=1900; i<2000; i++){
			if (identifier2ClassIndex.get(i).getAlternativeLabels().size()>1){
				LogOutput.print(i);
				LogOutput.print("\t"+identifier2ClassIndex.get(i).getLabel());
				LogOutput.print("\t"+identifier2ClassIndex.get(i).getEntityName());
				LogOutput.print("\t"+identifier2ClassIndex.get(i).getAlternativeLabels());
			}
		}*/
		
		
		fin = Calendar.getInstance().getTimeInMillis();
		LogOutput.print("Time setting labels and inverted files (s): " + (float)((double)fin-(double)init)/1000.0);
			
		
		

	}
	
	
	
	private String identifyLanguageOfOntologyLabels(){
		
		//We check a subset of classes
		int num_tests=0;
		
		String lang="";
		
		for (OWLClass cls : onto.getClassesInSignature(Imports.INCLUDED)){ //we also add imports
			if (!cls.isTopEntity() && !cls.isBottomEntity()){
				
				for (OWLAnnotationAssertionAxiom clsAnnAx : EntitySearcher.getAnnotationAssertionAxioms(cls, onto)){
					
					lang = annotationExtractor.getAnntotationLanguage(clsAnnAx);
					
					if (lang!=null && !lang.equals("")){
						
						//To fix misuses of ISO codes
						if (lang.equals("cn"))
							return "zh";
						if (lang.equals("cz"))
							return "cs";
											
						return lang;
					}
				
				}	
				num_tests++;
				if (num_tests>100) //to put a limit!
					return lang;
			}
		}
		
		return lang;
	}
	
	
	
	
	private Set<String> translateLabel(OWLAnnotationAssertionAxiom entityAnnAx, String label){
		
		Set<String> translation_labels = new HashSet<String>();
		
		//We only translate if lang is provided in a direct label
		String lang = annotationExtractor.getAnntotationLanguage(entityAnnAx);
			
		if (!lang.equals(Parameters.target_lang) && !lang.equals("")){
				
			//Call the translation module
			label = translator.getTranslation(label, lang);
			//LogOutput.printAlways(label + ":  " + translation);
			
			
			//For translated labels (case with many translations)
			//Label is: trans1|trans2|...|transx
			if (label.indexOf("|")>=0){
				String[] elements = label.split("\\|");
				for (String e : elements){
					translation_labels.add(e);
				}
				return translation_labels;
			}
				
		}
		
		translation_labels.add(label); //Original label or single translation
				
		return translation_labels;
	}
	
	
	
	
	private void processLexiconClasses(OWLClass cls, boolean extractLabels) {
		
		int ident;
		
		String ns_ent;
		String name;
		
		
		
		//TODO Added on Sept 7, 2018
		//Avoid deprecated cases. Possibly extend the ways a class is declared as deprecated
		if (isDeprecatedClass(cls)){
			//System.out.println("Filtering deprecated cls: " + cls.getIRI());
			return;
		}
		
		
		ns_ent=Utilities.getNameSpaceFromURI(cls.getIRI().toString());
		
		
		ident = index.addNewClassEntry();
		
		index.setOntologyId4Class(ident, id_onto);
		
		name = Utilities.getEntityLabelFromURI(cls.getIRI().toString());
				
		//if (name.equals("Mouse_Coccyx"))
		//	LogOutput.print("Here");
		
		index.setClassName(ident, name);
		
		//We store ns only if it is different to the ontology ns
		if (!ns_ent.equals("") && !ns_ent.equals(iri_onto)){
			index.setClassNamespace(ident, ns_ent);
		}
		
		
		/*LogOutput.print("\nENT:");
		LogOutput.print(iri_onto);
		LogOutput.print(cls.getIRI().toString());
		LogOutput.print(identifier2ClassIndex.get(ident).getNamespace());
		LogOutput.print(identifier2ClassIndex.get(ident).getEntityName());*/
		
		
		//We may need this structure for the taxonomy extraction...
		class2identifier.put(cls, ident);
		identifier2class.put(ident, cls);
		className2Identifier.put(name, ident);
		
		// Alessandro 21 April 2014
		//Useful for composed mappinsg as well
		classIri2identifier.put(cls.getIRI().toString(), ident);
		
						
		//Extract labels and alternative labels and create IFs
		if (extractLabels)
			createEntryInLexicalInvertedFiles4ClassLabels(cls, ident);
		
		//if (ident>30)
		//	break;
		
		
	}
	
	
	private void processLexiconDataProperties() {
		processLexiconDataProperties(true);
	}
	
	
	private void processLexiconDataProperties(boolean extractLabels) {
		
		
		List<String> cleanWords;
		String label;
		
		int ident;
		
		String ns_ent;
		String name;
		
		//DATA PROPERTIES
		for (OWLDataProperty dProp : onto.getDataPropertiesInSignature(Imports.INCLUDED)){ //also imports
			
			ns_ent=Utilities.getNameSpaceFromURI(dProp.getIRI().toString());
			
					
			ident = index.addNewDataPropertyEntry();	
			
			index.setOntologyId4DataProp(ident, id_onto);
				
			name = Utilities.getEntityLabelFromURI(dProp.getIRI().toString());
				
			index.setDataPropName(ident, name);
			
			dataPropName2Identifier.put(name, ident);
			
				
			//LogOutput.print(name);
				
			//We store ns only if it is different to the ontology ns
			if (!ns_ent.equals("") && !ns_ent.equals(iri_onto)){
				index.setDataPropNamespace(ident, ns_ent);
			}
				
			
			//Extract labels and alternative labels and create IFs
			cleanWords = processLabel(name);
			if (cleanWords.size()>0){
				if (extractLabels){
					invertedFileExactDataProp.put(new HashSet<String>(cleanWords), ident);
				}
			}
			
			label="";
			for (String word : cleanWords){
				label=label + word;				
			}			
			//label without spaces
			index.setDataPropLabel(ident, label);
			index.addAlternativeDataPropertyLabel(ident, label);
			cleanWords.clear();
			
			
			//Create alternative labels
			//--------------------------------
			List<String> cleanWordsAlternative = createAlternativeLabel(name);
			if (cleanWordsAlternative.size()>0){
				
				//Note that we do not add alternative label to inverted file
				//Inverted file only contains exact entries from main labels
			
				label=""; //label without spaces
				for (String word : cleanWordsAlternative){
					label=label + word;				
				}
				index.addAlternativeDataPropertyLabel(ident, label);
			}
			cleanWordsAlternative.clear();
			
			//----------------------------
			//Use rdf:label and others as alternative labels
			//----------------------------
			//TODO: labels might be in an annotation
			
			
			
			for (OWLAnnotationAssertionAxiom dPropAnnAx : EntitySearcher.getAnnotationAssertionAxioms(dProp, onto)){
				
				//String label_value = annotationExtractor.getAnntotationString(dPropAnnAx);
				
				LogOutput.print(name);
				
				
				//TODO Perform translation if necessary
				for (String label_value : annotationExtractor.getAnntotationString(dPropAnnAx, onto, index.getFactory())){
					
					if (Parameters.allow_multilingual){			
						alternative_labels_tmp.addAll(translateLabel(dPropAnnAx, label_value));
					}
					else{									
						alternative_labels_tmp.add(label_value);
					}
				
				}
				
				
				//Cleaning and Indexing
				for (String label_value : alternative_labels_tmp){
					
					
					LogOutput.print("\t  " + label_value);
					
					cleanWords = processLabel(label_value);
					
					if (cleanWords.size()>0){
						label=""; //label without spaces
						for (String word : cleanWords){
							
							if (label.length()==0)
								label= word;
							else{
								label+= "_" + word;
							}
								
						}
						index.addAlternativeDataPropertyLabel(ident, label);
											
					}
				}
				alternative_labels_tmp.clear();
			}
			
			
			
			//LogOutput.print(name);
			
			//Process domain
			//--------------------------------
			for (OWLClassExpression clsexp : EntitySearcher.getDomains(dProp, onto)){
				if (!clsexp.isAnonymous()){
					if (class2identifier.containsKey(clsexp.asOWLClass())){
						index.addDomainClass4DataProperty(ident, class2identifier.get(clsexp.asOWLClass()));
					}
				}
				else if (clsexp.getClassExpressionType()==ClassExpressionType.OBJECT_UNION_OF){									
					for (OWLClassExpression clsexpunion : clsexp.asDisjunctSet()){
						if (!clsexpunion.isAnonymous()){
							if (class2identifier.containsKey(clsexpunion.asOWLClass())){
								index.addDomainClass4DataProperty(ident, class2identifier.get(clsexpunion.asOWLClass()));
							}
						}
					}
				}
			}
			
			String range_type;
			
			//Process data ranges
			//--------------------------------
			for (OWLDataRange type : EntitySearcher.getRanges(dProp, onto)){
				if (type.isDatatype()){
					//LogOutput.print(type.asOWLDatatype() + " " + type.asOWLDatatype().getIRI() + " " + type.asOWLDatatype().isBuiltIn() +"  " +
					//		Utilities.getEntityLabelFromURI(type.asOWLDatatype().getIRI().toString()));
					
					try{
						if (type.asOWLDatatype().isBuiltIn()){
							range_type = type.asOWLDatatype().getBuiltInDatatype().getShortForm();
						}
						else{//we extract name from iri
							//range_type =  Utilities.getEntityLabelFromURI(Utilities.getEntityLabelFromURI(type.asOWLDatatype().getIRI().toString()));
							range_type =  Utilities.getEntityLabelFromURI(type.asOWLDatatype().getIRI().toString());
						}
					}
					catch (Exception e){ //In some cases the datatype is not built in an rises an error
						//range_type =  Utilities.getEntityLabelFromURI(Utilities.getEntityLabelFromURI(type.asOWLDatatype().getIRI().toString()));
						range_type =  Utilities.getEntityLabelFromURI(type.asOWLDatatype().getIRI().toString());
					}
					index.addRangeType4DataProperty(ident, range_type);
				}
				
			}
			
			
			//LogOutput.print("\tDOMAINS: " + identifier2DataPropIndex.get(ident).getDomainClassIndexes());
			//LogOutput.print("\tRANGES: " + identifier2DataPropIndex.get(ident).getRangeTypes());
			
							
			ident++;			
			
		}
		
		
	}
	
	private void processLexiconObjectProperties(){
		processLexiconObjectProperties(true);
	}
	
	private void processLexiconObjectProperties(boolean extractLabels){
		
		List<String> cleanWords;
		String label;
		
		int ident;
		
		String ns_ent;
		String name;
		
		
		//OBJECT PROPERTIES
		for (OWLObjectProperty oProp : onto.getObjectPropertiesInSignature(Imports.INCLUDED)){//also imports
			
			ns_ent=Utilities.getNameSpaceFromURI(oProp.getIRI().toString());
						
				
			
			ident = index.addNewObjectPropertyEntry();
			
			index.setOntologyId4ObjectProp(ident, id_onto);
				
			name = Utilities.getEntityLabelFromURI(oProp.getIRI().toString());
				
			index.setObjectPropName(ident, name);
			
			objectPropName2Identifier.put(name, ident);
			
			
			//identifier2ObjPropIndex.get(ident).setLabel(name);
			
			//LogOutput.print(name);
				
				
			//We store ns only if it is different to the ontology ns
			if (!ns_ent.equals("") && !ns_ent.equals(iri_onto)){
				index.setObjectPropNamespace(ident, ns_ent);
			}
				
			//Extract labels and alternative labels and create IFs
			cleanWords = processLabel(name);
			if (cleanWords.size()>0){
				if (extractLabels){
					invertedFileExactObjProp.put(new HashSet<String>(cleanWords), ident);
				}
			}
			
			label=""; //label without spaces
			for (String word : cleanWords){
				label=label + word;				
			}
			index.setObjectPropLabel(ident, label);
			index.addAlternativeObjectPropertyLabel(ident, label);
			cleanWords.clear();
			
			
			
			//Create alternative labels
			//--------------------------------
			List<String> cleanWordsAlternative = createAlternativeLabel(name);
			if (cleanWordsAlternative.size()>0){
				
				//Note that we do not add alternative label to inverted file
				//Inverted file only contains exact entries from main labels
			
				label=""; //label without spaces
				for (String word : cleanWordsAlternative){
					label=label + word;				
				}
				index.addAlternativeObjectPropertyLabel(ident, label);
			}
			cleanWordsAlternative.clear();
			
			
			
			//----------------------------
			//Use rdf:label and others as alternative labels
			//----------------------------
			//TODO: labels might be in an annotation
			for (OWLAnnotationAssertionAxiom oPropAnnAx : EntitySearcher.getAnnotationAssertionAxioms(oProp, onto)){
				
				//String label_value = annotationExtractor.getAnntotationString(oPropAnnAx);
				
				LogOutput.print(name);
				
				
				//TODO Perform translation if necessary
				for (String label_value : annotationExtractor.getAnntotationString(oPropAnnAx, onto, index.getFactory())){
					
					if (Parameters.allow_multilingual){			
						alternative_labels_tmp.addAll(translateLabel(oPropAnnAx, label_value));
					}
					else{									
						alternative_labels_tmp.add(label_value);
					}
				
				}
				
				
				//Cleaning and indexing
				for (String label_value : alternative_labels_tmp){
					
									
					LogOutput.print("\t  " + label_value);
					
					cleanWords = processLabel(label_value);
					
					if (cleanWords.size()>0){
						label=""; //label without spaces
						for (String word : cleanWords){
							
							if (label.length()==0)
								label= word;
							else{
								label+= "_" + word;
							}
								
						}
						//System.out.println(ident + "  " + label);
						index.addAlternativeObjectPropertyLabel(ident, label);
											
					}
				}
				alternative_labels_tmp.clear();
			}
			
			
			

			//Process Inverse properties and extend labels
			//--------------------------------------------
			String inverse_name;
			List<String> cleanWordsInverse;
			for (OWLObjectPropertyExpression propexp : EntitySearcher.getInverses(oProp, onto)){
				if (!propexp.isAnonymous()){
					inverse_name = Utilities.getEntityLabelFromURI(
							propexp.asOWLObjectProperty().getIRI().toString());
					
					//Reuse name of inverse property to create an alternative label for the property
					cleanWordsInverse = processInverseLabel(inverse_name);
					
					if (cleanWordsInverse.size()>0){
						
						//Note that we do not add alternative label to inverted file
						//Inverted file only contains exact entries from main labels
						
					
						label=""; //label without spaces
						for (String word : cleanWordsInverse){
							label=label + word;				
						}
						index.addAlternativeObjectPropertyLabel(ident, label);
					}
					cleanWordsInverse.clear();
				}
			}
			
			
			//Process domains
			//--------------------------------------------
			for (OWLClassExpression clsexp : EntitySearcher.getDomains(oProp, onto)){
				
				if (!clsexp.isAnonymous()){
					if (class2identifier.containsKey(clsexp.asOWLClass())){
						index.addDomainClass4ObjectProperty(ident, class2identifier.get(clsexp.asOWLClass()));
					}
				}
				else if (clsexp.getClassExpressionType()==ClassExpressionType.OBJECT_UNION_OF){									
					for (OWLClassExpression clsexpunion : clsexp.asDisjunctSet()){
						if (!clsexpunion.isAnonymous()){
							if (class2identifier.containsKey(clsexpunion.asOWLClass())){
								index.addDomainClass4ObjectProperty(ident, class2identifier.get(clsexpunion.asOWLClass()));
							}
						}
					}
				}
			
			}
			
			
			//Process ranges
			//--------------------------------------------
			for (OWLClassExpression clsexp : EntitySearcher.getRanges(oProp, onto)){
				if (!clsexp.isAnonymous()){
					if (class2identifier.containsKey(clsexp.asOWLClass())){
						index.addRangeClass4ObjectProperty(ident, class2identifier.get(clsexp.asOWLClass()));
					}
				}
				else if (clsexp.getClassExpressionType()==ClassExpressionType.OBJECT_UNION_OF){									
					for (OWLClassExpression clsexpunion : clsexp.asDisjunctSet()){
						if (!clsexpunion.isAnonymous()){
							if (class2identifier.containsKey(clsexpunion.asOWLClass())){
								index.addRangeClass4ObjectProperty(ident, class2identifier.get(clsexpunion.asOWLClass()));
							}
						}
					}
				}
			}
			
			//LogOutput.print(name);
			//LogOutput.print("\tDOMAINS: " + identifier2ObjPropIndex.get(ident).getDomainClassIndexes());
			//LogOutput.print("\tRANGES: " + identifier2ObjPropIndex.get(ident).getRangeClassIndexes());
							
			ident++;	//Is it necessary?	
			
		}
		
	}
	
	
	private void processNamedIndividuals(){
		processNamedIndividuals(true);
	}
	
	private void processNamedIndividuals(boolean extractLabels){
		
		Set<String> cleanWords = new HashSet<String>();
		List<String> cleanWordsList;
		
		String label;
		
		int ident;
		
