package basic;

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
 */
import uk.ac.ic.doc.automed.util.Debugger;
import uk.ac.ic.doc.automed.util.LogOutputHandler;
import uk.ac.ic.doc.automed.util.Logger;

public class DefineTransformations {
    public static Schema transforms1Tos4(Schema s1)
    throws NotFoundException,TypeMismatchException,IntegrityException {
        
        Model er=Model.getModel("er");
        Construct ent=er.getConstruct("entity");
        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,'F'} <- <<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,'F'} | {x} <- <<female>>]",
                "distinct [{x} | {y,x} <- <<person,sex>>] = "+
                "['M','F']");
    }
    
    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,dname>>]",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 att=er.getConstruct("attribute");
        
        // 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 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"},
                "[{x} | {x,'M'} <- <<person,sex>>]",
                null);
        Schema s1b=s1a.applyAddTransformation(node,
                new Object[] {"female"},
                "[{x} | {x,'F'} <- <<person,sex>>]",
                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,
                "[{x,'m'} | {x} <- <<male>>]++"+
                "[{x,'f'} | {x} <- <<female>>]",
                null);
        return s1e.applyDeleteTransformation(sex,
                "['m','f']",
                null);
    }
    
    public static void main(String[] args) {
        try {
            System.out.println("AutoMed Repository: Transformation and "+
                    "Integration Demo");
            
            String cfgFile = System.getProperty("-c");
            String debug = System.getProperty("-d");
            System.out.println("AutoMed Repository Reinitialisation");

            if (debug != null) {
                Debugger.setSectionDebugLevel(new String[]{"-d", debug});
            } else {
                Debugger.setSectionDebugLevel(args);
            }

            Logger.setOutputHandler(new LogOutputHandler(LogOutputHandler.CONSOLE));

            if (cfgFile != null) {
                DSRConfiguration.setDefaultConfigFileName(cfgFile);
            } else {
                DSRConfiguration.setDefaultConfigFileName(args);
            }
            
            Schema s1=Schema.getSchema("er_s1");
            Schema s2=Schema.getSchema("er_s2");
            Schema s3=Schema.getSchema("er_s3");
            
            if (AutoMedInANutshell.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 (AutoMedInANutshell.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("================================================");
            }
            
            AutoMedInANutshell.integrateSchemas(s4a,s4b);
            AutoMedInANutshell.integrateSchemas(s4b,s4c);
            
            DSR.shutdown();
            
            System.exit(0);
            
        } catch (AutoMedException ame) {
            ame.printStackTrace();
        }
    }
}
