
import uk.ac.ic.doc.automed.reps.*;
import uk.ac.ic.doc.automed.matching.*;
import uk.ac.ic.doc.automed.matching.modules.*;
import uk.ac.ic.doc.automed.matching.relationships.*;

/**
 * An application to demostrate how to perform the schema matching process on XML schemas
 */

public class XMLSchemaMatching{


	public static void main(String[] args){
		try{
			System.out.println("Schema matching on XML schemas: bank1, bank2, bank3");
			Schema bank1 = Schema.getSchema("bank1");
			Schema bank2 = Schema.getSchema("bank2");
			Schema bank3 = Schema.getSchema("bank3");

			SchemaObject[] bank1SOS = new SchemaObject[]{
											bank1.getSchemaObject("<<number$1,text>>"),
											bank1.getSchemaObject("<<cname$1,text>>")};
			SchemaObject[] bank2SOS = new SchemaObject[]{
											bank2.getSchemaObject("<<sitecode$1,text>>"),
											bank2.getSchemaObject("<<number$1,text>>"),
											bank2.getSchemaObject("<<cname$1,text>>")};
		

			System.out.println("Comparing NestedLists of bank1 and bank2 (instances of elements are tuples)");
			SchemaElement[] bank1XMLNestLists = SchemaElement.getSchemaElements(bank1, bank1SOS, Construct.CLASS_LINK, false);
			SchemaElement[] bank2XMLNestLists = SchemaElement.getSchemaElements(bank2, bank2SOS, Construct.CLASS_LINK, false);
			SchemaElementPairRelationship[] relsBank12 = getNonAtomicNestListRelationships(1.25,0.85,0.3,0.15, bank1XMLNestLists, bank2XMLNestLists);
			System.out.println("The discovered relationships (between non-atomic link objects) are:");
			for(int i=0; i<relsBank12.length; i++)
				System.out.println(relsBank12[i]);

			
			
			System.out.println("Comparing NestedLists of bank1 and bank2 atomically (i.e. their text field)...");
			SchemaElement[] bank1XMLNestListsAtomic = SchemaElement.getSchemaElements(bank1, bank1SOS, Construct.CLASS_LINK, true);
			SchemaElement[] bank2XMLNestListsAtomic = SchemaElement.getSchemaElements(bank2, bank2SOS, Construct.CLASS_LINK, true);
			SchemaElementPairRelationship[] relsBank12atomic = getAtomicNestListRelationships(1.25,0.85,0.3,0.15, bank1XMLNestListsAtomic, bank2XMLNestListsAtomic);
			System.out.println("The discovered relationships (between atomic link objects) are:");
			for(int i=0; i<relsBank12atomic.length; i++)
				System.out.println(relsBank12atomic[i]);
		
		

			System.out.println("Comparing XMLElements of bank2 and bank3...");
			SchemaElement[] bank2XMLElements = SchemaElement.getSchemaElements(bank1, Construct.CLASS_NODAL, false);
			SchemaElement[] bank3XMLElements = SchemaElement.getSchemaElements(bank3, Construct.CLASS_NODAL, false);
			SchemaElementPairRelationship[] relsBank23 = getXMLElementRelationships(1.25,0.85,0.3,0.15, bank2XMLElements, bank3XMLElements);
			System.out.println("The discovered relationships (between non-atomic nodal objects) are:");
			for(int i=0; i<relsBank23.length; i++)
				System.out.println(relsBank23[i]);
		}
		catch(Exception e){
			e.printStackTrace();
		}
	}


	private static SchemaElementPairRelationship[] getXMLElementRelationships(double mainThreshold, double eqThreshold, double overThreshold, double disThreshold, SchemaElement[] elements1, SchemaElement[] elements2) 
			throws UninstantiatedException, RelationshipConflictException, Exception{

		AbstractModule names=null, numOfInstances=null, existence=null, precision=null;	
		names = new ElementNameModule(elements1, elements2);
		numOfInstances = new NumberInstancesModule(elements1, elements2);
		existence = new CheckExistenceModule(elements1, elements2);
		precision = new PrecisionModule(elements1, elements2);

		Filter filter = new Filter(elements1, elements2);
		filter.addModule(numOfInstances);
		filter.addModule(precision);
		filter.addModule(existence);
		filter.addModule(names);
		SimilarSchemaElementPair[] allpairs = filter.getAllPairs();

		BidirectionalMap map = new BidirectionalMap(eqThreshold, overThreshold, disThreshold); 
		DegreeCombinator combinator = new DegreeCombinator(allpairs);
		combinator.setNumberInstancesModule(numOfInstances);
		combinator.setExistenceModule(existence);
		combinator.setPrecisionModule(precision);
		SchemaElementPairRelationship[] rels = combinator.getRelationships(map);

		return rels;
	}
	
	private static SchemaElementPairRelationship[] getAtomicNestListRelationships(double mainThreshold, double eqThreshold, double overThreshold, double disThreshold, SchemaElement[] nestLists1, SchemaElement[] nestLists2) 
			throws UninstantiatedException, RelationshipConflictException, Exception{

		if(nestLists1.length==0 || nestLists2.length==0)
			return new SchemaElementPairRelationship[0];

			
		AbstractModule datatype=null, statistics=null, names=null, numOfInstances=null, existence=null, naivebayes=null, precision=null;	
		SimilarSchemaElementPair datatypePairs[], statisticsPairs[], namesPairs[], numinstancesPairs[], existencePairs[], naivebayesPairs[], precisionPairs[];  

		datatype = new DataTypeModule(nestLists1, nestLists2);
		datatypePairs = datatype.getBidirectionalDegrees();

		statistics = new StatisticsModule(nestLists1, nestLists2);
		statisticsPairs = statistics.getBidirectionalDegrees();

		names = new ElementNameModule(nestLists1, nestLists2);
		namesPairs = names.getBidirectionalDegrees();

		numOfInstances = new NumberInstancesModule(nestLists1, nestLists2);
		numinstancesPairs = numOfInstances.getBidirectionalDegrees();

		existence = new CheckExistenceModule(nestLists1, nestLists2);
		existencePairs = existence.getBidirectionalDegrees();

		precision = new PrecisionModule(nestLists1, nestLists2);
		precisionPairs = precision.getBidirectionalDegrees();

		naivebayes = new NaiveBayesModule(nestLists1, nestLists2);
		naivebayesPairs = naivebayes.getBidirectionalDegrees();

	
		Filter filter = new Filter(nestLists1, nestLists2);
		filter.addModule(datatype);
		filter.addModule(statistics);
		filter.addModule(naivebayes);
		filter.addModule(precision);
		filter.addModule(names);
		filter.addModule(existence);
		SimilarSchemaElementPair[] filtered = filter.getCompatibles(mainThreshold);
		
		Aggregator aggregator = new Aggregator(filtered);
		aggregator.addNonAuxiliaryModule(datatype);
		aggregator.addNonAuxiliaryModule(statistics);
		aggregator.addNonAuxiliaryModule(precision);
		aggregator.addNonAuxiliaryModule(existence);
		aggregator.addNonAuxiliaryModule(numOfInstances);
		aggregator.addAuxiliaryModule(names);
		SimilarSchemaElementPair[] aggregated = aggregator.getPairs();
		
		BidirectionalMap map = new BidirectionalMap(eqThreshold, overThreshold, disThreshold); 
		DegreeCombinator combinator = new DegreeCombinator(aggregated);
		combinator.setNumberInstancesModule(numOfInstances);
		combinator.setExistenceModule(existence);
		combinator.setPrecisionModule(precision);
		SchemaElementPairRelationship[] rels = combinator.getRelationships(map);

		return rels;
	}

	
	private static SchemaElementPairRelationship[] getNonAtomicNestListRelationships(double mainThreshold, double eqThreshold, double overThreshold, double disThreshold, SchemaElement[] nestLists1, SchemaElement[] nestLists2) 
			throws UninstantiatedException, RelationshipConflictException, Exception{

		if(nestLists1.length==0 || nestLists2.length==0)
			return new SchemaElementPairRelationship[0];


		AbstractModule names=null, numOfInstances=null, existence=null, precision=null;	

		names = new ElementNameModule(nestLists1, nestLists2);
		numOfInstances = new NumberInstancesModule(nestLists1, nestLists2);
		existence = new CheckExistenceModule(nestLists1, nestLists2);
		precision = new PrecisionModule(nestLists1, nestLists2);
		
		Filter filter = new Filter(nestLists1, nestLists2);
		filter.addModule(precision);
		filter.addModule(names);
		filter.addModule(existence);
		filter.addModule(numOfInstances);
		SimilarSchemaElementPair[] allpairs = filter.getAllPairs();
		
		BidirectionalMap map = new BidirectionalMap(eqThreshold, overThreshold, disThreshold); 
		DegreeCombinator combinator = new DegreeCombinator(allpairs);
		combinator.setNumberInstancesModule(numOfInstances);
		combinator.setExistenceModule(existence);
		combinator.setPrecisionModule(precision);
		SchemaElementPairRelationship[] rels = combinator.getRelationships(map);

		return rels;
	}

}
