package query_processing.student;
import uk.ac.ic.doc.automed.*;
import uk.ac.ic.doc.automed.reps.*;
import uk.ac.ic.doc.automed.wrappers.*;

/**
 * This application provides an example for the LAV query processing using
 * inverse rules. This particular class wraps three Student databases which are
 * integrated using a public schema. The databases are described in the paper
 * 
 * <pre>
 *  P.J. McBrien and A. Poulovassilis. P2P query reformulation over Both-as-View
 *  data transformation rules. In Proc of DBISP2P 2006.
 * </pre>
 * 
 * The exact definition of the schemas of the three databases is given at end of
 * this file in SQL92 format.
 * <p>
 * Running Instructions:
 * <p>
 * Following files should be run in the given order:
 * <ol>
 * <li>StudentDatabaseWrapping.java
 * <li>StudentDatabaseIntegration.java
 * <li>StudentDatabaseQuerying.java
 * </ol>
 * 
 * @author <a href="mailto:sandeep@dcs.bbk.ac.uk">Sandeep Mittal</a>
 * @version 1.0
 * 
 */
public class StudentDatabaseIntegration {

    static Model sql92 = null;
    static Construct table = null;
    static Construct column = null;
    static Construct pk = null;
    static Construct fk = null;
    static SQLWrapperFactory wf;
    static String schemaChoice = null;

    public static void main(String[] args) {
        readArgs(args);
        try {
            System.out.println("AutoMed: LAV query example: "
                    + "Integration of Student Databases");

            //printExpData();
            if (Schema.exists("s1sp")) Schema.remove("s1sp");
            Schema s1 = Schema.getSchema("s1");
            transformsS1ToSP(s1, "s1sp");
            Schema s1sp = Schema.getSchema("s1sp");
            s1sp.listSchema();
            printPathway(s1, s1sp);

            if (Schema.exists("s2sp")) Schema.remove("s2sp");
            Schema s2 = Schema.getSchema("s2");
            transformsS2ToSP(s2, "s2sp");
            Schema s2sp = Schema.getSchema("s2sp");
            s2sp.listSchema();
            printPathway(s2, s2sp);

            if (Schema.exists("s3sp")) Schema.remove("s3sp");
            Schema s3 = Schema.getSchema("s3");
            transformsS3ToSP(s3, "s3sp");
            Schema s3sp = Schema.getSchema("s3sp");
            s3sp.listSchema();
            printPathway(s3, s3sp);

            integrateSchemas(s1sp, s2sp, "(++)");
            integrateSchemas(s1sp, s3sp, "(++)");
            integrateSchemas(s2sp, s3sp, "(++)");
            
        } catch (AutoMedException ame) {
            ame.printStackTrace();
        } catch (Throwable t) {
            System.err.println(t.toString());
            t.printStackTrace();
        }
    }

    public static void integrateSchemas(Schema s1, Schema s2, String iqlFunction) 
    throws AutoMedException {
        if (!iqlFunction.equals("choose") && !iqlFunction.equals("setUnion") && !iqlFunction.equals("(++)")
                && !iqlFunction.equals("intersect"))
            throw new AutoMedException("Incorrect IQL function used for id transformation: " + iqlFunction);

        System.out.print("Integration of " + s1.getName() + " and " + s2.getName());

        try {
            Transformation t = Transformation.createIdentTransformation(s1, s2, null, null);
            t.setProperty(Transformation.PROPERTY_IQL_FUNCTION, iqlFunction);
            System.out.println(" succeeded");
        } catch (SchemasNotIdenticalException e) {
            System.out.println(" failed");
            System.out.print("*** Schema " + e.getFromSchema().getName());
            System.out.println("has following SchemaObjects not matched");
            SchemaObject[] fromSo = e.getFromObjectsUnmatched();
            for (int i = 0; i < fromSo.length; i++)
                System.out.println(fromSo[i]);
            System.out.print("*** Schema " + e.getToSchema().getName());
            System.out.println("has following SchemaObjects not matched");
            SchemaObject[] toSo = e.getToObjectsUnmatched();
            for (int i = 0; i < toSo.length; i++)
                System.out.println(toSo[i]);
        }
    }

    private static void printPathway(Schema source, Schema target)
            throws IntegrityException, NotFoundException {
        banner("Shortest Pathway from Pathway class");
        Pathway path = Pathway.findShortestPathway(source, target);
        Transformation[] t = path.getTransformations();
        printTransformations(t);
    }

    private static void setConstructs(String source) throws IntegrityException,
            NotFoundException {
        wf = new SQLWrapperFactory();
        wf.setFeatures(Schema.getSchema(source).getAccessMethods()[0]
                .getAutoMedWrapperFactoryFeatures());
        sql92 = wf.getAutoMedModel();
        table = sql92.getConstruct(SQLWrapperFactory.AUTOMED_SQL_MODEL_TABLE);
        column = sql92.getConstruct(SQLWrapperFactory.AUTOMED_SQL_MODEL_COLUMN);
        if (wf.isFeatureInUse(SQLWrapperFactory.PRIMARY_KEY))
            pk = sql92
                    .getConstruct(SQLWrapperFactory.AUTOMED_SQL_MODEL_PRIMARY_KEY);
        if (wf.isFeatureInUse(SQLWrapperFactory.FOREIGN_KEY))
            fk = sql92
                    .getConstruct(SQLWrapperFactory.AUTOMED_SQL_MODEL_FOREIGN_KEY);
    }

    public static Schema transformsS1ToSP(Schema s1,
            String transformedSchemaName) throws NotFoundException,
            TypeMismatchException, IntegrityException {
        // The `current' schema as we transform s1 into sp
        Schema cs = s1;
        setConstructs(cs.getName() + "_src");

        // ------------------------------------------
        // Create table sp.course
        // ------------------------------------------

        // Extend table course
        cs = cs.applyExtendTransformation(table, new Object[] { "course" },
                "Range ([{c}|{s,c,t} <- <<studies>>]) Any", null);
        SchemaObject course = cs.getSchemaObject("<<course>>");

        // Extend column course:ccode
        // TODO: Why extend and not Add??

        SchemaObject studiesCcode = cs.getSchemaObject("<<studies,ccode>>");
        Object[] studiesCcodeScheme = studiesCcode.getSchemeDefinition();
        studiesCcodeScheme[0] = course;
        cs = cs.applyExtendTransformation(column, studiesCcodeScheme,
                "Range [{c,c}|{c}<-<<course>>] Any", null);

        // Extend column course, title
        SchemaObject studiesTitle = cs.getSchemaObject("<<studies,title>>");
        Object[] studiesTitleScheme = studiesTitle.getSchemeDefinition();
        studiesTitleScheme[0] = course;
        cs = cs.applyExtendTransformation(column, studiesTitleScheme,
                "Range [{c,ti}|{{s,c,t},ti}<-<<studies,title>>] Any", null);

        // Add Primary key ccode to course
        SchemaObject coCcode = cs.getSchemaObject("<<course,ccode>>");
        cs = cs.applyAddTransformation(pk, new Object[] { "course_pk", course,
                coCcode }, null, null);

        // Contract column studies:title
        cs = cs
                .applyContractTransformation(
                        studiesTitle,
                        "Range Void [{{s,c,t},ti}|{s,c,t}<-<<studies>>;{c,ti}<-<<course,title>>]",
                        null);

        // ------------------------------------------
        // Create table sp.student
        // ------------------------------------------

        // Extend table student
        cs = cs.applyExtendTransformation(table, new Object[] { "student" },
                "Range [{s}|{s,c,t}<-<<studies>>] Any", null);
        SchemaObject student = cs.getSchemaObject("<<student>>");

        // Add column student:sname
        SchemaObject studiesSname = cs.getSchemaObject("<<studies,sname>>");
        Object[] studiesSnameScheme = studiesSname.getSchemeDefinition();
        studiesSnameScheme[0] = student;
        cs = cs.applyAddTransformation(column, studiesSnameScheme,
                "[{s,s}|{s}<-<<student>>]", null);

        // Extend column student.dcode
        // FIXME
        cs = cs.applyExtendTransformation(column, new Object[] { student,
                "dcode", "notnull", "int4", "-1" }, "Range Void Any", null);

        // Add pk - student:sname
        SchemaObject studentSname = cs.getSchemaObject("<<student,sname>>");
        cs = cs.applyAddTransformation(pk, new Object[] { "student_pk",
                student, studentSname }, null, null);

        // ------------------------------------------
        // Create table sp.degree
        // ------------------------------------------

        // Extend table degree
        cs = cs.applyExtendTransformation(table, new Object[] { "degree" },
                "Range [{d}|{s,d}<-<<student,dcode>>] Any", null);
        SchemaObject degree = cs.getSchemaObject("<<degree>>");

        // Extend column degree:dcode
        // TODO: Why Add and not Extend??
        SchemaObject studentDcode = cs.getSchemaObject("<<student,dcode>>");
        Object[] studentDcodeScheme = studentDcode.getSchemeDefinition();
        studentDcodeScheme[0] = degree;
        cs = cs.applyAddTransformation(column, studentDcodeScheme,
                "[{d,d}|{d}<-<<degree>>]", null);

        // Extend column degree:dname
        SchemaObject studiesDname = cs.getSchemaObject("<<studies,dname>>");
        Object[] studiesDnameScheme = studiesDname.getSchemeDefinition();
        studiesDnameScheme[0] = degree;
        cs = cs
                .applyExtendTransformation(
                        column,
                        studiesDnameScheme,
                        "Range [{d,dn}|{s,d}<-<<student,dcode>>;{{s,c,t},dn}<-<<studies,dname>>] Any",
                        null);

        // Add pk to degree
        SchemaObject degreeDcode = cs.getSchemaObject("<<degree,dcode>>");
        cs = cs.applyAddTransformation(pk, new Object[] { "degree_pk", degree,
                degreeDcode }, null, null);

        // Contract column studies:dname
        // TODO: Looks wrong. The PK projection on <<studies,dname>> should be
        // {{s,c,t},dn}
        cs = cs
                .applyContractTransformation(
                        studiesDname,
                        "Range Void [{{s,c,t},dn}|{s,c,t}<-<<studies>>;{s,d}<-<<student,dcode>>;{d,dn}<-<<degree,dname>>]",
                        null);

        // ------------------------------------------
        // Create table sp.sit by renaming s1.studies
        // ------------------------------------------

        // Extend column cwmark
        SchemaObject studies = cs.getSchemaObject("<<studies>>");
        cs = cs.applyExtendTransformation(column, new Object[] { studies,
                "cwmark", "null", "int4", "-1" }, "Range Void Any", null);

        // rename pk studies_pk to sit_pk
        SchemaObject studiesPK = cs
                .getSchemaObject("<<studies_pk,studies,<<studies,sname>>,<<studies,ccode>>,<<studies,sem>>>>");
        Object[] sitPKScheme = studiesPK.getSchemeDefinition();
        sitPKScheme[0] = "sit_pk";
        cs = cs.applyRenameTransformation(studiesPK, sitPKScheme);

        // rename table studies to sit
        cs = cs.applyRenameTransformation(studies, new Object[] { "sit" });

        // That should form the pathways from S1 to SP.
        cs.setName(transformedSchemaName);
        return cs;
    }

    public static Schema transformsS2ToSP(Schema s2,
            String transformedSchemaName) throws NotFoundException,
            TypeMismatchException, IntegrityException {
        // The `current' schema as we transform s2 into sp
        Schema cs = s2;
        setConstructs(cs.getName() + "_src");

        // ------------------------------------------
        // Create table sp.course
        // ------------------------------------------

        // Extend table course
        cs = cs.applyExtendTransformation(table, new Object[] { "course" },
                "Range ([{c}|{s,c,t} <- <<teach>>]) Any", null);
        SchemaObject course = cs.getSchemaObject("<<course>>");

        // Extend column course.ccode
        // TODO: Why extend and not Add??
        SchemaObject teachCcode = cs.getSchemaObject("<<teach,ccode>>");
        Object[] teachCcodeScheme = teachCcode.getSchemeDefinition();
        teachCcodeScheme[0] = course;
        cs = cs.applyExtendTransformation(column, teachCcodeScheme,
                "Range [{c,c}|{c}<-<<course>>] Any", null);

        // Extend column course.title
        cs = cs.applyExtendTransformation(column, new Object[] { course,
                "title", "notnull", "varchar", "-1" }, "Range Void Any", null);

        // Add Primary key ccode to course
        SchemaObject coCcode = cs.getSchemaObject("<<course,ccode>>");
        cs = cs.applyAddTransformation(pk, new Object[] { "course_pk", course,
                coCcode }, null, null);

        // ------------------------------------------
        // Create table sp.student
        // ------------------------------------------

        // Extend table student
        cs = cs.applyExtendTransformation(table, new Object[] { "student" },
                "Range [{s}|{s,c,t}<-<<teach>>] Any", null);
        SchemaObject student = cs.getSchemaObject("<<student>>");

        // Add column student:sname
        SchemaObject teachSname = cs.getSchemaObject("<<teach,sname>>");
        Object[] teachSnameScheme = teachSname.getSchemeDefinition();
        teachSnameScheme[0] = student;
        cs = cs.applyAddTransformation(column, teachSnameScheme,
                "[{s,s}|{s}<-<<student>>]", null);

        // Extend column student.dcode
        cs = cs.applyExtendTransformation(column, new Object[] { student,
                "dcode", "notnull", "int4", "-1" }, "Range Void Any", null);

        // Add pk - student:sname
        SchemaObject studentSname = cs.getSchemaObject("<<student,sname>>");
        cs = cs.applyAddTransformation(pk, new Object[] { "student_pk",
                student, studentSname }, null, null);

        // ------------------------------------------
        // Create table sp.degree
        // ------------------------------------------

        // Extend table degree
        cs = cs.applyExtendTransformation(table, new Object[] { "degree" },
                "Range [{d}|{s,d}<-<<student,dcode>>] Any", null);
        SchemaObject degree = cs.getSchemaObject("<<degree>>");

        // Extend column degree:dcode
        // TODO: Why Add and not Extend??
        SchemaObject studentDcode = cs.getSchemaObject("<<student,dcode>>");
        Object[] studentDcodeScheme = studentDcode.getSchemeDefinition();
        studentDcodeScheme[0] = degree;
        cs = cs.applyAddTransformation(column, studentDcodeScheme,
                "[{d,d}|{d}<-<<degree>>]", null);

        // Extend column degree:dname
        cs = cs.applyExtendTransformation(column, new Object[] { degree,
                "dname", "notnull", "varchar", "-1" }, "Range Void Any", null);

        // Add pk to degree
        SchemaObject degreeDcode = cs.getSchemaObject("<<degree,dcode>>");
        cs = cs.applyAddTransformation(pk, new Object[] { "degree_pk", degree,
                degreeDcode }, null, null);

        // ------------------------------------------
        // Create table sp.sit by renaming s2.teach
        // ------------------------------------------

        // Extend column cwmark
        SchemaObject teach = cs.getSchemaObject("<<teach>>");
        cs = cs.applyExtendTransformation(column, new Object[] { teach,
                "cwmark", "null", "int4", "-1" }, "Range Void Any", null);

        // Contract column teach.tname
        SchemaObject teachTname = cs.getSchemaObject("<<teach,tname>>");
        cs = cs
                .applyContractTransformation(teachTname, "Range Void Any",
                        null);

        // rename pk studies_pk to sit_pk
        SchemaObject teachPK = cs
                .getSchemaObject("<<teach_pk,teach,<<teach,sname>>,<<teach,ccode>>,<<teach,sem>>>>");
        Object[] sitPKScheme = teachPK.getSchemeDefinition();
        
        sitPKScheme[0] = "sit_pk";
        cs = cs.applyRenameTransformation(teachPK, sitPKScheme);

        // rename table studies to sit
        cs = cs.applyRenameTransformation(teach, new Object[] { "sit" });

        // That should form the pathways from S1 to SP.
        cs.setName(transformedSchemaName);
        return cs;
    }

    public static Schema transformsS3ToSP(Schema s3,
            String transformedSchemaName) throws NotFoundException,
            TypeMismatchException, IntegrityException {
        // The `current' schema as we transform s3 into sp
        Schema cs = s3;
        setConstructs(cs.getName() + "_src");

        // ------------------------------------------
        // Create table sp.degree from s3.degree
        // ------------------------------------------

        // Contract column qual
        SchemaObject degreeQual = cs.getSchemaObject("<<degree,qual>>");
        cs = cs.applyContractTransformation(degreeQual, "Range Void Any", null);

        // ------------------------------------------
        // Create table sp.student from s3.ug
        // ------------------------------------------

        // Rename Primary key for ug
        SchemaObject ugPK = cs.getSchemaObject("<<ug_pk,ug,<<ug,sname>>>>");
        Object[] ugPKScheme = ugPK.getSchemeDefinition();
        ugPKScheme[0] = "student_pk";
        cs = cs.applyRenameTransformation(ugPK, ugPKScheme);

        // Drop foreign key for ug
        // -- We could keep it and add FKs to S1->SP and S2->SP transformations.
        // But for this example
        // I am omitting the FKs from the global schema for simplicity.
        SchemaObject ugDegFK = cs
                .getSchemaObject("<<ug_deg_fk,ug,<<ug,dcode>>,degree,<<degree,dcode>>>>");
        cs = cs.applyDeleteTransformation(ugDegFK, null, null);

        // Rename table ug to student
        SchemaObject ug = cs.getSchemaObject("<<ug>>");
        cs = cs.applyRenameTransformation(ug, new Object[] { "student" });

        // ------------------------------------------
        // Create table sp.sit from s3.reg
        // ------------------------------------------

        // Extend table sit
        cs = cs
                .applyExtendTransformation(
                        table,
                        new Object[] { "sit" },
                        "Range [{s,c,Const1 s c}|{s,c}<-<<reg>>;(Const1 s c)>='1994-1'] Any",
                        null);
        SchemaObject sit = cs.getSchemaObject("<<sit>>");

        // Extend column sit.sname
        SchemaObject regSname = cs.getSchemaObject("<<reg,sname>>");
        Object[] regSnameScheme = regSname.getSchemeDefinition();
        regSnameScheme[0] = sit;
        cs = cs.applyExtendTransformation(column, regSnameScheme,
                "Range [{{s,c,t},s}|{s,c,t}<-<<sit>>] Any", null);

        // Extend column sit.ccode
        SchemaObject regCcode = cs.getSchemaObject("<<reg,ccode>>");
        Object[] regCcodeScheme = regCcode.getSchemeDefinition();
        regCcodeScheme[0] = sit;
        cs = cs.applyExtendTransformation(column, regCcodeScheme,
                "Range [{{s,c,t},c}|{s,c,t}<-<<sit>>] Any", null);

        // Extend column sit.sem
        cs = cs.applyExtendTransformation(column, new Object[] { sit, "sem",
                "notnull", "bpchar", "-1" },
                "Range [{{s,c,t},t}|{s,c,t}<-<<sit>>] Any", null);

        // Add column sit.cwmark
        // TODO: Why ADD?
        SchemaObject regCwmark = cs.getSchemaObject("<<reg,cwmark>>");
        Object[] regCwmarkScheme = regCwmark.getSchemeDefinition();
        regCwmarkScheme[0] = sit;
        regCwmarkScheme[2] = "null";
        cs = cs.applyAddTransformation(column, regCwmarkScheme,
                "[{{s,c,t},cw}|{s,c,t}<-<<sit>>;{{s,c},cw}<-<<reg,cwmark>>]",
                null);

        // Extend column sit.mark
        cs = cs.applyExtendTransformation(column, new Object[] { sit, "mark",
                "notnull", "int4", "-1" }, "Range Void Any", null);

        // Add PK to sit
        SchemaObject sitSname = cs.getSchemaObject("<<sit,sname>>");
        SchemaObject sitCcode = cs.getSchemaObject("<<sit,ccode>>");
        SchemaObject sitSem = cs.getSchemaObject("<<sit,sem>>");
        cs = cs.applyAddTransformation(pk, new Object[] { "sit_pk", sit,
                sitSname, sitCcode, sitSem }, null, null);

        // Delete reg_pk
        SchemaObject regPK = cs
                .getSchemaObject("<<reg_pk,reg,<<reg,sname>>,<<reg,ccode>>>>");
        cs = cs.applyDeleteTransformation(regPK, null, null);

        // Delete reg_ug_fk
        SchemaObject regUgFK = cs
                .getSchemaObject("<<reg_ug_fk,reg,<<reg,sname>>,student,<<student,sname>>>>");
        cs = cs.applyDeleteTransformation(regUgFK, null, null);

        // Delete column reg.sname
        cs = cs.applyDeleteTransformation(regSname,
                "[{{s,c},s}|{s,c}<-<<reg>>]", null);

        // Delete column reg.ccode
        cs = cs.applyDeleteTransformation(regCcode,
                "[{{s,c},c}|{s,c}<-<<reg>>]", null);

        // Delete column reg.cwmark
        cs = cs.applyDeleteTransformation(regCwmark,
                "[{{s,c},cw}|{{s,c,t},cw}<-<<sit,cwmark>>]", null);

        // Contract column reg.tutor
        SchemaObject regTutor = cs.getSchemaObject("<<reg,tutor>>");
        cs = cs.applyContractTransformation(regTutor, "Range Void Any", null);

        // Contract table reg
        SchemaObject reg = cs.getSchemaObject("<<reg>>");
        cs = cs.applyContractTransformation(reg,
                "Range Void [{s,c}|{s,c,t}<-<<sit>>; t>='1994-1']", null);

        // ------------------------------------------
        // Create table sp.course from s3.reg
        // ------------------------------------------

        cs = cs.applyExtendTransformation(table, new Object[] { "course" },
                "Range [{c}|{s,c,t}<-<<sit>>] Any", null);
        SchemaObject course = cs.getSchemaObject("<<course>>");

        // Extend column course.ccode
        Object[] sitCcodeScheme = sitCcode.getSchemeDefinition();
        sitCcodeScheme[0] = course;
        cs = cs.applyExtendTransformation(column, sitCcodeScheme,
                "Range [{c,c}|{c}<-<<course>>] Any", null);

        // Extend column course.title
        cs = cs.applyExtendTransformation(column, new Object[] { course,
                "title", "notnull", "varchar", "-1" }, "Range Void Any", null);

        // Add PK to course
        SchemaObject coCcode = cs.getSchemaObject("<<course,ccode>>");
        cs = cs.applyAddTransformation(pk, new Object[] { "course_pk", course,
                coCcode }, null, null);

        // That should form the pathways from S1 to SP.
        cs.setName(transformedSchemaName);
        return cs;

    }

    static void printHelp() {
        System.out.println("Usage: StudentDatabaseIntegration [ options ]\n"
                + "  -debug <0-10>         set debug level\n"
                + "  -schema <schema name>\n");
    }

    public static void readArgs(String[] args) {
        int i = 0;
        try {
            while (i < args.length) {
                if (args[i].charAt(0) != '-') {
                    System.out.println("Error at " + args[i] + "\n");
                    printHelp();
                    System.exit(10);
                } else if (args[i].startsWith("-debug"))
                    STR.setDebugLevel(Integer.parseInt(args[++i]));
                else if (args[i].startsWith("-schema"))
                    schemaChoice = args[++i];
                else if (args[i].startsWith("-help"))
                    printHelp();
                ++i;
            }

            if (STR.atDebugLevel(5))
                System.out.println("Finished reading arguments, "
                        + "about to read database");

        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("You didn't supply an argument to the "
                    + args[i - 1] + " option!");
            printHelp();
            System.exit(10);
        }
    }

    public static void banner(String title) {
        int len = title.length();
        String stars = "**********************************************"
                + "*********************************";
        int slen = stars.length();

        System.out.println(stars);
        if (len > slen - 4)
            System.out.println(title);
        else
            System.out.println(stars.substring(0, (slen - len) / 2 - 1) + " "
                    + title + (len % 2 == 0 ? " " : "  ")
                    + stars.substring(0, (slen - len) / 2));
        System.out.println(stars);
    }

    private static void printExpData() throws Exception {

        Schema s1 = Schema.getSchema("s1");
        setConstructs(s1.getName() + "_src");
        // Schema ns = transformss1Tosp(s1);
        SchemaObject studies = s1.getSchemaObject("<<studies>>");
        Object[] studiessch = studies.getSchemeDefinition();
        printScheme(studiessch);
        Object[] stitle = s1.getSchemaObject("<<studies,title>>")
                .getSchemeDefinition();
        printScheme(stitle);
        Object[] ccode = s1.getSchemaObject("<<studies,ccode>>")
                .getSchemeDefinition();
        printScheme(ccode);

        SchemaObject[] spk = studies.getDependentSchemaObjects(pk);
        System.out.println(spk.length + " : " + spk[0].toString());
        printScheme(spk[0].getSchemeDefinition());
        System.out.println("----");

        System.out.println("Label: " + spk[0].getLabel());
        System.out.println("SchemeNamesString: "
                + spk[0].getSchemeNamesString());
        System.out.println("SchemeString: " + spk[0].getSchemeString());
        System.out.println("Value: " + spk[0].getValue());
        System.out.println("Ref Objects: ");
        printScheme(spk[0].getReferencedSchemaObjects());

        System.out.println("Dep Objects: ");
        printScheme(spk[0].getDependentSchemaObjects());

        Schema s3 = Schema.getSchema("s3");
        setConstructs(s3.getName() + "_src");
        SchemaObject reg = s3.getSchemaObject("<<reg>>");
        printScheme(reg.getDependentSchemaObjects(fk)[0].getSchemeDefinition());
    }

    private static void printScheme(Object[] s) {
        for (int i = 0; i < s.length; i++) {
            System.out.println(i + " " + s[i] + " " + s[i].getClass());
        }
    }

    private static void printTransformations(Transformation[] t) {
        for (int i = 0; i < t.length; i++) {
            System.out.println(i + " " + t[i].toString());
        }
    }

} // end StudentDatabaseIntegration

