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

/*
 * An application to demonstrate how various aspects of the AutoMed
 * repository may be used --- and not useful for much else!
 * The application shows how to create models (such as an ER modelling
 * language), how to create schemas in the language (such as an ER model
 * containing entities "person" and "dept" and relationship "works_in",
 * and how to create transformation pathways between those models
 */

public class AutoMedExamples {
  // A new method that could go in Model?
  public static void forceRemove(Model m) {
    try {
      Construct c[]=m.getConstructs();
      int no_c=c.length;
      for (int i=0;i<no_c;i++) {
	//Construct.removeConstruct(c[i]); // COMMENT Does not exist!!!
      }
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }

  public static void reinitialiseMDRfaulty() {
    try {
      String param[]=new String[]{
	"", 
	ModelDefinitionsRepository.getMDR_DataSourceName()};
      System.out.println("First "+param[1]);
      DataSourceRepository.doDropdbCommand(param);
      // COMMENT Param string changed to null
      System.out.println("Second "+param[1]);
      DataSourceRepository.doCreatedbCommand(param);
      System.out.println("MDR Recreated");
    }
    catch (DataSourceRepositoryException dse) {
      dse.printStackTrace();
    }      
    catch (SQLException se) { // COMMENT Why this?
      se.printStackTrace();
    }
    catch (IOException ioe) { // COMMENT Why this?
      ioe.printStackTrace();
    }
  }
    
  public static void reinitialiseMDR() {
    try {
      System.out.println("Dropping MDR");
      DataSourceRepository.doDropdbCommand(new String[]{
	"", 
	ModelDefinitionsRepository.getMDR_DataSourceName()});
      DataSourceRepository.doCreatedbCommand(new String[]{
	"", 
	ModelDefinitionsRepository.getMDR_DataSourceName()});
      
      // you should always do this after altering the MDR not throug the
      // reps API if you are going to then use the MDR through the reps API
      Model.reloadModels();
      System.out.println("MDR Reinitialized");
    }
    catch (DataSourceRepositoryException dse) {
      dse.printStackTrace();
    }      
    catch (SQLException se) { // COMMENT Why this?
      se.printStackTrace();
    }
    catch (IOException se) { // COMMENT Why this?
      se.printStackTrace();
    }
  }
    
  public static void reinitialiseSTR() {
    try {	    
      Schema.getSchema("s1");
      System.out.println("Dropping STR");
      DataSourceRepository.doDropdbCommand(new String[]{
	"", 
	SchemaTransformationRepository.getSTR_DataSourceName()
      });
      DataSourceRepository.doCreatedbCommand(new String[]{
	"", 
	SchemaTransformationRepository.getSTR_DataSourceName()
      });

      // you should always do this after altering the STR not through the
      // reps API if you are going to then use the STR through the reps API
      Schema.clearSchemas();
      System.out.println("STR Reinitialized");
    }
    catch (DataSourceRepositoryException dse) {
      dse.printStackTrace();
    }      
    catch (AutoMedException ae) {
      ae.printStackTrace();
    }
    catch (SQLException se) { // COMMENT Why this?
      se.printStackTrace();
    }
    catch (IOException se) { // COMMENT Why this?
      se.printStackTrace();
    }
  }

  public static void createERModel() {
    // Zap any existing model called "er"
    /*
    try {
      Model er=Model.getModel("er");
      if (er!=null)
	forceRemove(er);
      System.out.println("Removed old er modelling language");
    }
    catch (AutoRepException are) {
      //are.printStackTrace();
    }
    */

    System.out.println("Building er modelling language");
    try {
      // COMMENT Should "add" match "remove"?
      Model er=Model.createModel("er"); 

      // Create the four constructs this particular ER modelling language

      // ENTITY ...
      // Entities can stand by themselves; hence NODAL
      Construct entity=
	er.createConstruct("entity",Constants.CONSTRUCT_CLASS_NODAL,true);
      // The scheme of an entity contains just the entity name,
      // in the form <<ent_name>> where we use ent_name as name of the
      // node
      entity.createConstructScheme(Constants.SCHEME_TYPE_NAME, 
				   // Textual name
				   null, // and hence references nothing
				   true, // forms part of the key
				   Constants.SCHEME_HDM_TYPE_N1, 
				   // the first HDM node
				   1,1 // exactly one of these
				   );

      // ATTRIBUTE ...
      // Attributes have values not present in other constructs, but
      // must be associated to other objects; hence LINK_NODAL
      Construct attribute=
	er.createConstruct("attribute",
			   Constants.CONSTRUCT_CLASS_LINK_NODAL,true);
      attribute.createConstructScheme(Constants.SCHEME_TYPE_CONSTRUCT, 
				      entity,
				      true, Constants.SCHEME_HDM_TYPE_P1,
				      1,1);
      attribute.createConstructScheme(Constants.SCHEME_TYPE_NAME, null,
				      true, Constants.SCHEME_HDM_TYPE_N1, 
				      1,1);

      // Relationships link other existing objects, and hence are LINK
      Construct relationship=
	er.createConstruct("relationship",
			   Constants.CONSTRUCT_CLASS_LINK,true);
      relationship.createConstructScheme(Constants.SCHEME_TYPE_NAME, null,
					 true, 
					 Constants.SCHEME_HDM_TYPE_N1,1,1);
      relationship.createConstructScheme(Constants.SCHEME_TYPE_CONSTRUCT,
					 entity, true, 
					 Constants.SCHEME_HDM_TYPE_P1,
					 1,1);
      relationship.createConstructScheme(Constants.SCHEME_TYPE_CONSTRUCT,
					 entity, true, 
					 Constants.SCHEME_HDM_TYPE_P2,
					 1,1);
      relationship.createConstructScheme(Constants.SCHEME_TYPE_NAME, null,
					 true, 
					 Constants.SCHEME_HDM_TYPE_C,
					 1,1);
      relationship.createConstructScheme(Constants.SCHEME_TYPE_NAME, null,
					 true, 
					 Constants.SCHEME_HDM_TYPE_C, 
					 1,1);

      // Generalisations are constraints on the values of entities, and
      // have not associated values, hence CONSTRAINT
      Construct generalisation=
	er.createConstruct("generalisation",
			   Constants.CONSTRUCT_CLASS_CONSTRAINT,true);
      generalisation.createConstructScheme(Constants.SCHEME_TYPE_NAME, null,
					   true, 
					   Constants.SCHEME_HDM_TYPE_C,1,1);
      generalisation.createConstructScheme(Constants.SCHEME_TYPE_NAME, null,
					   true, 
					   Constants.SCHEME_HDM_TYPE_C,1,1);
      generalisation.createConstructScheme(Constants.SCHEME_TYPE_CONSTRUCT,
					   entity, true, 
					   Constants.SCHEME_HDM_TYPE_C,1,1);
      generalisation.createConstructScheme(Constants.SCHEME_TYPE_CONSTRUCT,
					   entity, true, 
					   Constants.SCHEME_HDM_TYPE_C,1,1);
      generalisation.createConstructScheme(Constants.SCHEME_TYPE_CONSTRUCT,
					   entity, true, 
					   Constants.SCHEME_HDM_TYPE_C,1,0);
      System.out.println("MDR Created");
    }
    catch (IntegrityException ie) {
      ie.printStackTrace();
    }
    catch (DataSourceRepositoryException dse) {
      dse.printStackTrace();
    }
    catch (ModelDefinitionsRepositoryException mde) {
      mde.printStackTrace();
    }
    //catch (AutoRepException are) {
    //  are.printStackTrace();
    //}
    catch (SQLException se) { // COMMENT Why this?
      se.printStackTrace();
    }
    catch (IOException se) { // COMMENT Why this?
      se.printStackTrace();
    }
  }

  public static void createERs1() {
    try {
      System.out.println("Building schema s1");
      Schema s1=Schema.createSchema("s1", false);
      Model er=Model.getModel("er");
      Construct mc[]=er.getConstructs(); // COMMENT Blows Up
      Construct ent=er.getConstruct("entity");
      Construct rel=er.getConstruct("relationship");
      Construct att=er.getConstruct("attribute");

      /*
      for (int i=0;i<mc.length;i++) {
	if (mc[i].getName().equals("entity")) 
	  ent=mc[i];
	else if (mc[i].getName().equals("attribute")) 
	  att=mc[i];
	else if (mc[i].getName().equals("relationship")) 
	  rel=mc[i];
      }
      */

      // Now build the schema
      SchemaObject person=s1.createSchemaObject(ent,new Object[]{"person"});
      s1.createSchemaObject(att, new Object[] {person, "id"});
      s1.createSchemaObject(att, new Object[] {person, "name"});
      s1.createSchemaObject(att, new Object[] {person, "sex"});
      SchemaObject dept=s1.createSchemaObject(ent, new Object[] {"dept"});
      s1.createSchemaObject(att, new Object[] {dept, "dname"});
      s1.createSchemaObject(rel,
			    new Object[]{"worksin",person,dept,
					   "1:1","1:N"});
      System.out.println("Created schema s1 succesfully");
    }
    catch (AutoMedException ame) {
      ame.printStackTrace();
    }
 }

  public static void main(String[] args) {
    boolean recreateMDR = true;
    boolean recreateSTR = true;
    boolean runStatic = false;
    boolean displayMDR = false;
    boolean fullMDR = false;
    boolean displaySTR = false;
    for (int i=0; i<args.length; i++) {
      if (args[i].equals("-cmdr"))
	recreateMDR=false;
      else if (args[i].equals("-cstr"))
	recreateSTR=false;
      else if (args[i].equals("-static"))
	runStatic=true;
      else if (args[i].equals("-dmdr"))
	displayMDR=true;
      else if (args[i].equals("-Dmdr"))
	fullMDR=true;
      else if (args[i].equals("-dstr"))
	displaySTR=true;
      else {
	System.out.println("-cmdr   - don't recreate the MDR\n" +
			   "-cstr   - don't recreate the STR\n" +
			   "-dmdr   - display MDR contents\n" +
			   "-Dmdr   - display long MDR contents\n" +
			   "-dstr   - display STR contents\n" +
			   "-static - run in static context");
	System.exit(10);
      }
    }
    if (runStatic)
      test(recreateMDR, recreateSTR, displayMDR, fullMDR, displaySTR);
    else
      new AutoMedExamples().test(recreateMDR, recreateSTR,
				 displayMDR, fullMDR, displaySTR);
  }

  private static void printMDR(boolean full) {
    try {
      System.out.println(Model.getModel("er").getModelDescription(full));
    }
    catch (Exception e) {
      e.printStackTrace(System.out);
    }
  }

  private static void printSTR() {
    try {
      System.out.println(Schema.getSchema("s1").getAllSchemeNamesString());
    }
    catch (Exception e) {
      e.printStackTrace(System.out);
    }
  }

  private static void test(boolean recreateMDR, boolean recreateSTR,
			   boolean displayMDR, boolean fullMDR,
			   boolean displaySTR) {
    System.out.println("AutoMed Repository Demo Application");
    if (recreateMDR) {
      reinitialiseMDR();
      createERModel();
    }
    if (displayMDR | fullMDR)
      printMDR(fullMDR);
    if (recreateSTR) {
      reinitialiseSTR();
      createERs1();
    }
    if (displaySTR)
      printSTR();
  }
}

