import java.sql.*;
import java.io.*;
import uk.ac.ic.doc.automed.*;
import uk.ac.ic.doc.automed.reps.*;

import java.util.*;

/*
 * An application to demonstrate how various aspects of the AutoMed
 * repository may be used to link schemas together 
 * via transformation pathways
 */

public class DefineTransformations {
  public static Schema transforms1Tos4(Schema s1) 
    throws NotFoundException,TypeMismatchException,IntegrityException {

    Model er=Model.getModel("er");
    Construct ent=er.getConstruct("entity");
    Construct att=er.getConstruct("attribute");
    Construct rel=er.getConstruct("relationship");
    Construct gen=er.getConstruct("generalisation");

    // Check that we have the objects that we want to transform
    SchemaObject staff=s1.getSchemaObject("<<staff>>");
    Schema s1a=s1.applyRenameTransformation(staff,new Object[]{"person"});

    SchemaObject newnames=
      Transformation.getTransformation(s1,s1a).getSchemaObject(s1a);
    SchemaObject person=(SchemaObject)newnames.getSchemeDefinition()[0];
    SchemaObject personsex=s1a.getSchemaObject("<<person,sex>>");

    Schema s1b=s1a.applyAddTransformation(ent,new Object[]{"male"},
    "[ {x} | {x,'M'} <- <<person,sex>>]",null);
    Schema s1c=s1b.applyAddTransformation(ent,new Object[]{"female"},
    "[ {x} | {x,'Y'} <- <<person,sex>>]",null);

    SchemaObject male= 
      Transformation.getTransformation(s1a,s1b).getSchemaObject(s1b);
    SchemaObject female=
      Transformation.getTransformation(s1b,s1c).getSchemaObject(s1c);
    // No query should be given here, since generalisations are constraint
    // objects, and thus have no extent
    Schema s1d=
      s1c.applyAddTransformation
      (gen,new Object[]{"sex","total",person,male,female},null,null);
    return s1d.
      applyDeleteTransformation(personsex,
				"[ {x,'M'} | {x} <- <<male>>] ++"+
				"[ {x,'Y'} | {x} <- <<female>>]",
				"distinct [{x} | {y,x} <- <<person,sex>>] = "+
				"['M','Y']");
}

public static Schema transforms2Tos4(Schema s2) 
  throws NotFoundException,TypeMismatchException,IntegrityException {
  Model er=Model.getModel("er");
  Construct ent=er.getConstruct("entity");
  Construct att=er.getConstruct("attribute");
  Construct rel=er.getConstruct("relationship");

    // Check that we have the objects that we want to transform
    SchemaObject person=s2.getSchemaObject("<<person>>");
    SchemaObject persondname=
      s2.getSchemaObject("<<person,dname>>");

    Transformation t2_1=
      Transformation.createAddTransformation(s2,ent,
	new Object[] {"dept"},"[{x} | {y,x} <- <<person,dept>>]",null);
    Schema s2a=t2_1.getOtherSchema(s2);
    SchemaObject dept=t2_1.getSchemaObject(s2a);

    Transformation t2_2=
      Transformation.createAddTransformation(s2a,att,
	new Object[] {dept,"dname","key"},"[ {x,x} | {x} <- <<dept>>]",null);
    Schema s2b=t2_2.getOtherSchema(s2a);
    Transformation t2_3=
      Transformation.createAddTransformation(s2b,rel,
	new Object[] {"worksin",person,dept,"1:1","1:N"},"<<person,dname>>",null);
    Schema s2c=t2_3.getOtherSchema(s2b);
    Transformation t2_4=
      Transformation.createDeleteTransformation(s2c,persondname,
	"<<worksin,person,dept>>",null);
    Schema s2d=t2_4.getOtherSchema(s2c);
    SchemaObject personpid=s2d.getSchemaObject("<<person,pid,key>>");
    return s2d.applyRenameTransformation(personpid,
					 new Object[]{person,"id","key"});
  }

  public static Schema transforms3Tos4(Schema s3) 
    throws NotFoundException,TypeMismatchException,IntegrityException {
    Model er=Model.getModel("er");
    Construct ent=er.getConstruct("entity");
    Construct att=er.getConstruct("attribute");
    Construct rel=er.getConstruct("relationship");
    Construct gen=er.getConstruct("generalisation");

    // Check that we have the objects that we want to transform
    SchemaObject person=s3.getSchemaObject("<<person>>");
    SchemaObject degree=s3.getSchemaObject("<<degree>>");
    SchemaObject degreecode=s3.getSchemaObject("<<degree,code>>");
    SchemaObject degreetitle=
      s3.getSchemaObject("<<degree,title>>");
    SchemaObject runby=
      s3.getSchemaObject("<<runby,degree,dept>>");

    // Alternative style of creating transformations, having the same
    // result as using the Schema based methods, except you have returned
    // the transformation created rather than the schema created
    Transformation t3_1=
      Transformation.createContractTransformation(s3,degreetitle,null,null);
    Schema s3a=t3_1.getOtherSchema(s3);
    Transformation t3_2=
      Transformation.createContractTransformation(s3a,degreecode,null,null);
    Schema s3b=t3_2.getOtherSchema(s3a);
    Transformation t3_3=
      Transformation.createContractTransformation(s3b,runby,null,null);
    Schema s3c=t3_3.getOtherSchema(s3b);
    Transformation t3_4=
      Transformation.createContractTransformation(s3c,degree,null,null);
    Schema s3d=t3_4.getOtherSchema(s3c);
    Transformation t3_5=
      Transformation.createExtendTransformation(s3d,att,
						new Object[]{person,
							     "name",
							     "notnull"},
						null,null);
    return t3_5.getOtherSchema(s3d);
  }

  public static Schema transforms1Tos4HDM(Schema s1) 
    throws NotFoundException,TypeMismatchException,IntegrityException {
    Model hdm=Model.getModel("hdm");
    Construct node=hdm.getConstruct("node");
    Construct edge=hdm.getConstruct("edge");
    Construct cons=hdm.getConstruct("constraint");

    // Check that we have the objects that we want to transform
    SchemaObject sex=s1.getSchemaObject("<<sex>>");
    SchemaObject personsex=s1.getSchemaObject("<<_,person,sex>>");

    Schema s1a=s1.applyAddTransformation(node,
					 new Object[] {"male"},
					 "male(X):-person-sex(X,male)",
					 null);
    Schema s1b=s1a.applyAddTransformation(node,
					  new Object[] {"female"},
					  "female(X):-person-sex(X,female)",
					  null);
    Schema s1c=
      s1b.applyAddTransformation(cons,
				 new Object[]{"subset(<<male>>,<<person>>)"},
				 null,
				 null);
    Schema s1d=
      s1c.applyAddTransformation(cons,
				 new Object[]{"subset(<<female>>,<<person>>)"},
				 null,
				 null);
    Schema s1e=
      s1d.applyDeleteTransformation(personsex,
				    "person-sex(X,Y) :- male(X),Y=m;"+
				    "female(X),Y=f",
				    null);
    return s1e.applyDeleteTransformation(sex,
				    "sex(X) :- X=m;X=f",
				    null);
  }

  public static void main(String[] args) {
    try {
      System.out.println("AutoMed Repository: Transformation and "+
			 "Integration Demo");

      // level 5 prints all the old debug information, 0 makes it silent
      STR.setDebugLevel(0);

      Schema s1=Schema.getSchema("er_s1");
      Schema s2=Schema.getSchema("er_s2");
      Schema s3=Schema.getSchema("er_s3");

      if (AutoMedUtils.debug>0) {
	System.out.println("================================================");
	System.out.println(s1.getName());
	System.out.println(s1.getAllSchemeNamesString(true, -1, -1));    
	System.out.println("------------------------------------------------");
	System.out.println(s2.getName());
	System.out.println(s2.getAllSchemeNamesString(true, -1, -1));    
	System.out.println("------------------------------------------------");
	System.out.println(s3.getName());
	System.out.println(s3.getAllSchemeNamesString(true, -1, -1));    
	System.out.println("================================================");
      }

      Schema s4a=transforms1Tos4(s1);
      s4a.listSchema();
      Schema s4b=transforms2Tos4(s2); 
      s4b.listSchema();
      Schema s4c=transforms3Tos4(s3);
      s4c.listSchema();

      if (AutoMedUtils.debug>0) {
	System.out.println("================================================");
	System.out.println(s4a.getName());
	System.out.println(s4a.getAllSchemeNamesString(true, -1, -1));    
	System.out.println("------------------------------------------------");
	System.out.println(s4b.getName());
	System.out.println(s4b.getAllSchemeNamesString(true, -1, -1));    
	System.out.println("------------------------------------------------");
	System.out.println(s4c.getName());
	System.out.println(s4c.getAllSchemeNamesString(true, -1, -1));    
	System.out.println("================================================");
      }

      AutoMedUtils.integrateSchemas(s4a,s4b);
      AutoMedUtils.integrateSchemas(s4b,s4c); 
    }
    catch (AutoMedException ame) {
      ame.printStackTrace();
    }
  }
}
