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.wrappers.SQLWrapperFactory;

/*
 * An application to demonstrate how to setup models (i.e. modelling
 * languages such as ER, Relational, etc) using the
 * Automed API
 */

public class DefineModels {
  /*
   * Define an ER modelling language, with entities, attributes,
   * relationships and generalisations
   */
  public static void createERModel() 
    throws InconsistentException,
    AutoMedException, SQLException, IOException {
    // Zap any existing model called "er"
    if (Model.exists("templatesER")) {
      System.out.println("Removed old er modelling language");
      Model.getModel("templatesER").retract();
    }

    // COMMENT Should "add" match "remove"?
    Model er=Model.createModel("templatesER"); 

    // Create the four constructs this particular ER modelling language

    // ENTITY ...
    // Entities can stand by themselves; hence NODAL
    Construct entity=
      er.createConstruct("entity",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

    // addNodeNameScheme defaults to isKey=true, cardinality=1..1
    // (as construct's class is Nodal, cardinality must be 1..1)
    entity.addNodeNameScheme();

    /*
    entity.createConstructScheme(Scheme.TYPE_NAME, 
				 // Textual name
				 null, // and hence references nothing
				 true, // forms part of the key
				 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",
			 Construct.CLASS_LINK_NODAL,true);
    
    // addEdgeEdgeNameScheme & addReferenceScheme default to isKey=true
    // all default to cardinality 1..1 (EdgeName must be 1..1)
    attribute.addReferenceScheme(entity);
    attribute.addEdgeNameScheme();
    attribute.addConstraintScheme(false); // constraint's not key

    /*
    attribute.createConstructScheme(Scheme.TYPE_CONSTRUCT, entity,
				    true, Scheme.HDM_TYPE_P1, 1,1);
    attribute.createConstructScheme(Scheme.TYPE_NAME, null,
				    true, Scheme.HDM_TYPE_N1, 1,1);
    // constraint on attribute is one of "key", "null" or "notnull"
    attribute.createConstructScheme(Scheme.TYPE_NAME, null,
				    true, Scheme.HDM_TYPE_C, 1,1);
    */

    // Relationships link other existing objects, and hence are LINK
    Construct relationship=
      er.createConstruct("relationship",
			 Construct.CLASS_LINK,true);

    // we want an edge between two existing entities and we
    // want two cardinality constraints, one for each entity
    // We just want the edgeName and entity references to be key
    relationship.addEdgeNameScheme();
    relationship.addReferenceScheme(entity, 2, 2);
    relationship.addConstraintScheme(2, 2, false);

    /*
    relationship.createConstructScheme(Scheme.TYPE_NAME, null,
				       true, 
				       Scheme.HDM_TYPE_N1,1,1);
    relationship.createConstructScheme(Scheme.TYPE_CONSTRUCT,
				       entity, true, 
				       Scheme.HDM_TYPE_P1,
				       2,2);
    relationship.createConstructScheme(Scheme.TYPE_NAME, null,
				       false, 
				       Scheme.HDM_TYPE_C,
				       2,2);
    */

    // Generalisations are constraints on the values of entities, and
    // have not associated values, hence CONSTRAINT
    Construct generalisation=
      er.createConstruct("generalisation",
			 Construct.CLASS_CONSTRAINT,
			 true);
    
    // need labels here as we need to name the generalization and type
    // but there is no corresponding HDM edge or node
    // Note the cardinality of the sub entities ReferenceScheme, as lower>
    // bigger this means lower..n i.e. 2..n in this case
    generalisation.addLabelScheme();
    generalisation.addLabelScheme(false);
    generalisation.addReferenceScheme(entity);
    generalisation.addReferenceScheme(entity, 2, 0, false);
  
    /*
    generalisation.createConstructScheme(Scheme.TYPE_NAME, null,
					 true, 
					 Scheme.HDM_TYPE_C,1,1);
    generalisation.createConstructScheme(Scheme.TYPE_NAME, null,
					 false, 
					 Scheme.HDM_TYPE_C,1,1);
    generalisation.createConstructScheme(Scheme.TYPE_CONSTRUCT,
					 entity, true, 
					 Scheme.HDM_TYPE_C,1,1);
    generalisation.createConstructScheme(Scheme.TYPE_CONSTRUCT,
					 entity, false, 
					 Scheme.HDM_TYPE_C,2,0);
    */
    System.out.println("Created ER Model: "+er.getName());
  }

  /*
   * Define an relational modelling language, using nodes, edges and
   * constraints
   */
  public static void createRelationalModel() 
    throws InconsistentException,
    AutoMedException, SQLException, IOException {

	SQLWrapperFactory wf = new SQLWrapperFactory();
	wf.setFeatures(SQLWrapperFactory.PRIMARY_KEY);
	Model rel = wf.getAutoMedModel();

    System.out.println("Created Relational Model : "+rel.getName());
  }

  public static void main(String[] args) {
    try {
      System.out.println("AutoMed Repository: Define Models");
      createERModel();
      createRelationalModel();
    }
    catch (InconsistentException aie) {
      aie.printStackTrace();
    }
    catch (SQLException se) { 
      se.printStackTrace();
    }
    catch (IOException ie) {
      ie.printStackTrace();
    }
    catch (AutoMedException ame) {
      ame.printStackTrace();
    }      
  }
}

























