package basic;

import java.sql.*;
import java.io.*;
import uk.ac.ic.doc.automed.*;
import uk.ac.ic.doc.automed.reps.*;
import uk.ac.ic.doc.automed.util.Debugger;
import uk.ac.ic.doc.automed.util.LogOutputHandler;
import uk.ac.ic.doc.automed.util.Logger;

/**
 * An application to demonstrate how to create schemas in existing models
 */
public class DefineSchemas {

    public static Schema createERS1(String name)
            throws NotFoundException, TypeMismatchException, IntegrityException {
        Schema s = Schema.createSchema(name);
        Model er = Model.getModel("er");

        Construct ent = er.getConstruct("entity");
        Construct att = er.getConstruct("attribute");
        Construct rel = er.getConstruct("relationship");

        // Now build the schema
        SchemaObject staff = s.createSchemaObject(ent, new Object[]{"staff"});
        s.createSchemaObject(att, new Object[]{staff, "id", "key"});
        s.createSchemaObject(att, new Object[]{staff, "name", "notnull"});
        s.createSchemaObject(att, new Object[]{staff, "sex", "notnull"});
        SchemaObject dept = s.createSchemaObject(ent, new Object[]{"dept"});
        s.createSchemaObject(att, new Object[]{dept, "dname", "key"});
        s.createSchemaObject(rel,
                new Object[]{"worksin", staff, dept, "1:1;1:N"});
        System.out.println("Created schema " + name + " succesfully");

        return s;
    }

    public static Schema createERS2(String name)
            throws NotFoundException, TypeMismatchException, IntegrityException {
        Schema s = Schema.createSchema(name);
        Model er = Model.getModel("er");

        Construct ent = er.getConstruct("entity");
        Construct att = er.getConstruct("attribute");
        Construct gen = er.getConstruct("generalisation");

        // Now build the schema
        SchemaObject person = s.createSchemaObject(ent, new Object[]{"person"});
        s.createSchemaObject(att, new Object[]{person, "pid", "key"});
        s.createSchemaObject(att, new Object[]{person, "name", "notnull"});
        s.createSchemaObject(att, new Object[]{person, "dname", "notnull"});
        SchemaObject male = s.createSchemaObject(ent, new Object[]{"male"});
        SchemaObject female = s.createSchemaObject(ent, new Object[]{"female"});
        s.createSchemaObject(gen, new Object[]{"sex", "total", person, male, female});
        System.out.println("Created schema " + name + " succesfully");

        return s;
    }

    public static Schema createERS3(String name)
            throws NotFoundException, TypeMismatchException, IntegrityException {
        Schema s = Schema.createSchema(name);
        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");

        // Now build the schema
        SchemaObject person = s.createSchemaObject(ent, new Object[]{"person"});
        s.createSchemaObject(att, new Object[]{person, "id", "key"});
        SchemaObject male = s.createSchemaObject(ent, new Object[]{"male"});
        SchemaObject female = s.createSchemaObject(ent, new Object[]{"female"});
        s.createSchemaObject(gen, new Object[]{"sex", "total", person, male, female});
        SchemaObject dept = s.createSchemaObject(ent, new Object[]{"dept"});
        s.createSchemaObject(att, new Object[]{dept, "dname", "key"});
        s.createSchemaObject(rel, new Object[]{"worksin", person, dept, "1:1;1:N"});
        SchemaObject degree = s.createSchemaObject(ent, new Object[]{"degree"});
        s.createSchemaObject(att, new Object[]{degree, "code", "key"});
        s.createSchemaObject(att, new Object[]{degree, "title", "notnull"});
        s.createSchemaObject(rel, new Object[]{"runby", degree, dept, "1:1;1:N"});
        System.out.println("Created schema " + name + " succesfully");

        return s;
    }

    public static Schema createERS6(String name)
            throws NotFoundException, TypeMismatchException, IntegrityException {
        Schema s = Schema.createSchema(name);
        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");

        // Now build the schema
        SchemaObject person = s.createSchemaObject(ent, new Object[]{"person"});
        s.createSchemaObject(att, new Object[]{person, "id", "key"});
        SchemaObject male = s.createSchemaObject(ent, new Object[]{"male"});
        SchemaObject female = s.createSchemaObject(ent, new Object[]{"female"});
        s.createSchemaObject(gen, new Object[]{"sex", "total", person, male, female});
        SchemaObject dept = s.createSchemaObject(ent, new Object[]{"dept"});
        s.createSchemaObject(att, new Object[]{dept, "dname", "key"});
        s.createSchemaObject(rel, new Object[]{"worksin", person, dept, "1:1;1:N"});
        SchemaObject degree = s.createSchemaObject(ent, new Object[]{"degree"});
        s.createSchemaObject(att, new Object[]{degree, "code", "key"});
        s.createSchemaObject(att, new Object[]{degree, "title", "notnull"});
        s.createSchemaObject(rel, new Object[]{"runby", degree, dept, "1:1;1:N"});
        SchemaObject course = s.createSchemaObject(ent, new Object[]{"course"});
        s.createSchemaObject(att, new Object[]{course, "code", "key"});
        s.createSchemaObject(att, new Object[]{course, "title", "notnull"});
        s.createSchemaObject(rel, new Object[]{"sits", person, course, "0:N;0:N"});
        SchemaObject lecturer = s.createSchemaObject(ent, new Object[]{"lecturer"});
        s.createSchemaObject(att, new Object[]{lecturer, "staff_no", "key"});
        s.createSchemaObject(att, new Object[]{lecturer, "name", "notnull"});
        s.createSchemaObject(att, new Object[]{lecturer, "office", "null"});
        s.createSchemaObject(rel, new Object[]{"teaches",
            lecturer, course, "0:N;0:1"
        });

        System.out.println("Created schema " + name + " succesfully");

        return s;
    }

    public static Schema createEERS6(String name)
            throws NotFoundException, TypeMismatchException, IntegrityException {
        Schema s = Schema.createSchema(name);
        Model eer = Model.getModel("eer");
        Construct ent = eer.getConstruct("entity");
        Construct att = eer.getConstruct("attribute");
        Construct rel = eer.getConstruct("relationship");
        Construct gen = eer.getConstruct("generalisation");

        // Now build the schema
        SchemaObject person = s.createSchemaObject(ent, new Object[]{"person"});
        s.createSchemaObject(att, new Object[]{person, "id", "key"});
        SchemaObject male = s.createSchemaObject(ent, new Object[]{"male"});
        SchemaObject female = s.createSchemaObject(ent, new Object[]{"female"});
        s.createSchemaObject(gen, new Object[]{"sex", "total", person, male, female});
        SchemaObject dept = s.createSchemaObject(ent, new Object[]{"dept"});
        s.createSchemaObject(att, new Object[]{dept, "dname", "key"});
        s.createSchemaObject(rel, new Object[]{"worksin", person, dept, "1:1;1:N"});
        SchemaObject degree = s.createSchemaObject(ent, new Object[]{"degree"});
        s.createSchemaObject(att, new Object[]{degree, "code", "key"});
        s.createSchemaObject(att, new Object[]{degree, "title", "notnull"});
        s.createSchemaObject(rel, new Object[]{"runby", degree, dept, "1:1;1:N"});
        SchemaObject course = s.createSchemaObject(ent, new Object[]{"course"});
        s.createSchemaObject(att, new Object[]{course, "code", "key"});
        s.createSchemaObject(att, new Object[]{course, "title", "notnull"});
        SchemaObject sits =
                s.createSchemaObject(rel, new Object[]{"sits", person, course, "0:N;0:N"});
        s.createSchemaObject(att, new Object[]{sits, "year", "notnull"});
        s.createSchemaObject(att, new Object[]{sits, "result", "null"});
        SchemaObject lecturer = s.createSchemaObject(ent, new Object[]{"lecturer"});
        s.createSchemaObject(att, new Object[]{lecturer, "staff_no", "key"});
        s.createSchemaObject(att, new Object[]{lecturer, "name", "notnull"});
        s.createSchemaObject(att, new Object[]{lecturer, "office", "null"});
        s.createSchemaObject(rel, new Object[]{"teaches",
            lecturer, course, "0:N;0:1"
        });

        System.out.println("Created schema " + name + " succesfully");

        return s;
    }

    public static Schema createRelationalS1(String name)
            throws NotFoundException, TypeMismatchException, IntegrityException {
        Schema s = Schema.createSchema(name);
        Model rel = Model.getModel("rel");

        Construct table = rel.getConstruct("table");
        Construct field = rel.getConstruct("field");
        Construct pk = rel.getConstruct("primary_key");
        Construct fk = rel.getConstruct("foreign_key");

        // Now build the schema
        SchemaObject person = s.createSchemaObject(table, new Object[]{"person"});
        SchemaObject id = s.createSchemaObject(field, new Object[]{person, "id", "1"});
        SchemaObject persondept = s.createSchemaObject(field, new Object[]{person, "dept", "2"});
        s.createSchemaObject(field, new Object[]{person, "name", "3"});
        s.createSchemaObject(field, new Object[]{person, "sex", "4"});
        s.createSchemaObject(pk, new Object[]{"person_pk", person, id});
        SchemaObject dept = s.createSchemaObject(table, new Object[]{"dept"});
        SchemaObject dname =
                s.createSchemaObject(field, new Object[]{dept, "dname", "1"});
        s.createSchemaObject(pk, new Object[]{"dept_pk", dept, dname});
        s.createSchemaObject(fk, new Object[]{"persondept_fk", person, persondept, dept, dname});
        System.out.println("Created schema " + name + " succesfully");

        return s;
    }

    public static Schema createRelationalS2(String name)
            throws NotFoundException, TypeMismatchException, IntegrityException {
        Schema s = Schema.createSchema(name, true);
        Model rel = Model.getModel("rel");

        Construct table = rel.getConstruct("table");
        Construct field = rel.getConstruct("field");
        Construct pk = rel.getConstruct("primary_key");
        Construct fk = rel.getConstruct("foreign_key");

        // Now build the schema
        SchemaObject person = s.createSchemaObject(table, new Object[]{"person"});
        SchemaObject id = s.createSchemaObject(field, new Object[]{person, "id", "1"});
        s.createSchemaObject(field, new Object[]{person, "name", "2"});
        s.createSchemaObject(field, new Object[]{person, "dname", "3"});
        s.createSchemaObject(pk, new Object[]{"person_pk", person, id});
        SchemaObject male = s.createSchemaObject(table, new Object[]{"male"});
        SchemaObject mid = s.createSchemaObject(field, new Object[]{male, "id", "1"});
        s.createSchemaObject(pk, new Object[]{"male_pk", male, mid});
        s.createSchemaObject(fk, new Object[]{"male_fk", male, mid, person, id});
        SchemaObject female = s.createSchemaObject(table, new Object[]{"female"});
        SchemaObject fid = s.createSchemaObject(field, new Object[]{female, "id", "1"});
        s.createSchemaObject(pk, new Object[]{"female_pk", female, fid});
        s.createSchemaObject(fk, new Object[]{"female_fk", female, fid, person, id});
        System.out.println("Created schema " + name + " succesfully");

        return s;
    }

    public static void main(String[] args) {
        try {
            System.out.println("AutoMed Repository: Creating Schemas 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.retract("eer_s6");
            Schema es6 = createEERS6("eer_s6");
            es6.listSchema();

            Schema.retract("er_s1");
            Schema s1 = createERS1("er_s1");
            s1.listSchema();

            Schema.retract("er_s2");
            Schema s2 = createERS2("er_s2");
            s2.listSchema();

            Schema.retract("er_s3");
            Schema s3 = createERS3("er_s3");
            s3.listSchema();

            Schema.retract("er_s6");
            Schema s6 = createERS6("er_s6");
            s6.listSchema();

            Schema.retract("rel_s1");
            Schema rels1 = createRelationalS1("rel_s1");
            rels1.listSchema();

            Schema.retract("rel_s2");
            Schema rels2 = createRelationalS2("rel_s2");
            rels2.listSchema();

            DSR.shutdown();
        } catch (AutoMedException ame) {
            ame.printStackTrace();
        }
    }
}

