
/**
 * The HdmStoreApiDemo class demonstrates the use of the HDM store through 
 * its API (rather than through the IQL wrapper or command file reader)
 * 
 * @author Dean Williams
 * (<a href="mailto:dean@dcs.bbk.ac.uk"><i>dean@dcs.bbk.ac.uk</i></a>)
 */

import java.io.IOException;
import java.sql.SQLException;

import uk.ac.bbk.dcs.automed.hdmstore.Debug;
import uk.ac.bbk.dcs.automed.hdmstore.Edge;
import uk.ac.bbk.dcs.automed.hdmstore.HdmStore;
import uk.ac.ic.doc.automed.reps.AccessMethod;
import uk.ac.ic.doc.automed.reps.Construct;
import uk.ac.ic.doc.automed.reps.Model;
import uk.ac.ic.doc.automed.reps.Protocol;
import uk.ac.ic.doc.automed.reps.Schema;
import uk.ac.ic.doc.automed.reps.SchemaObject;

public class DemoHdmStoreApi
{

	/** 
	 * Builds the standard Automed {@link Model} to represent HDM 
	 */
	public void buildModel()
		throws Exception, Exception, SQLException, IOException
	{

		System.out.println("Building hdm model");

		// Zap any existing model called "hdm"
		if (Model.exists("hdm"))
		{
			System.out.println("About to remove old hdm modelling language");
			Model.getModel("hdm").retract();
			System.out.println("Removed old hdm modelling language");
		}

		Model hdm = Model.createModel("hdm");

		// Create the three constructs of the HDM modelling language

		// NODE ... by definition NODAL
		Construct node =
			hdm.createConstruct("node", Construct.CLASS_NODAL, true);

		node.addNodeNameScheme();

		// EDGE ... by definition a LINK
		Construct edge =
			hdm.createConstruct("edge", Construct.CLASS_LINK, true);
		Construct nodeOrEdge =
			hdm.createConstruct(
				"nodeOrEdge",
				Construct.CLASS_ALTERNATION,
				false);
		nodeOrEdge.addReferenceScheme(node);
		nodeOrEdge.addReferenceScheme(edge);

		edge.addEdgeNameScheme();
		edge.addReferenceScheme(nodeOrEdge, 2, 0);
		// 2..0 (lower>upper) => 2..n

		// CONSTRAINT ... by definition a CONSTRAINT
		Construct constraint =
			hdm.createConstruct("constraint", Construct.CLASS_CONSTRAINT, true);
		constraint.addConstraintScheme(1, 1, true);

		System.out.println("Created hdm Model");

		System.out.println(hdm.getModelDescription());

	}




	/** 
	 * Builds an example {@link Schema} for a college personnel department 
	 */
	public void buildPersonnelSchema()
		throws Exception, Exception, SQLException, IOException
	{

		String schemaName = "personnel";

		System.out.println("Building " + schemaName + " schema");

		// retract schema if it already exists
		if (Schema.exists(schemaName))
		{
			System.out.println("Retracted old schema");
			Schema.retract(schemaName);
		}

		Schema s = Schema.createSchema(schemaName, false);
		Model hdm = Model.getModel("hdm");

		Construct node = hdm.getConstruct("node");
		Construct edge = hdm.getConstruct("edge");
		Construct cons = hdm.getConstruct("constraint");

		// Now build the schema
		SchemaObject person =
			s.createSchemaObject(node, new Object[] { "person" });
		SchemaObject project =
			s.createSchemaObject(node, new Object[] { "project" });
		SchemaObject room = s.createSchemaObject(node, new Object[] { "room" });
		SchemaObject houseNumber =
			s.createSchemaObject(node, new Object[] { "houseNumber" });
		SchemaObject road = s.createSchemaObject(node, new Object[] { "road" });
		SchemaObject town = s.createSchemaObject(node, new Object[] { "town" });
		SchemaObject postCode =
			s.createSchemaObject(node, new Object[] { "postCode" });

		SchemaObject worksIn =
			s.createSchemaObject(
				edge,
				new Object[] { "worksIn", person, project });
		SchemaObject worksIn2 =
			s.createSchemaObject(
				edge,
				new Object[] { "worksIn", person, room });
		SchemaObject address =
			s.createSchemaObject(
				edge,
				new Object[] { "address", houseNumber, road, town, postCode });
		SchemaObject livesAt =
			s.createSchemaObject(
				edge,
				new Object[] { "livesAt", person, address });

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

		s.listSchema();

		// ensure the HDM protocol exists in the repository
		System.out.println("Doing the Access Method Stuff");
		if (Protocol.exists("hdm"))
		{
			Protocol.remove("hdm");
		}
		Protocol protocol = Protocol.createProtocol("hdm");
		
		// add the access method for the schema
		s.removeAccessMethods();
		AccessMethod am =
			AccessMethod.createAccessMethod(
				s,
				"jdbc:postgresql:localhost:hdmstore",
				protocol,
				"org.postgresql.Driver",
				"pjm");
	}




	/** 
	 * Populate the example {@link Schema} using the HDM store API 
	 */
	public void populatePersonnelSchema()
		throws Exception, Exception, SQLException, IOException
	{
		Edge edge;
		Debug debug = new Debug(Debug.ERROR);
		boolean result;

		System.out.println("about to create HDMStore:");

		// datastore

		HdmStore hdmStore = new HdmStore(debug);
		
		// drop & recreate the database store tables
		hdmStore.createDBtables();
		
		// create a (logical) hdm store 
		hdmStore.createHdmStore("personnel", "bbkdata");
		hdmStore.use("bbkdata");

		// add nodes

		hdmStore.addNode("person", "dean");
		hdmStore.addNode("person", "hao");
		hdmStore.addNode("person", "mat");
		hdmStore.addNode("person", "edgar");
		hdmStore.addNode("person", "tony");
		hdmStore.addNode("person", "liz");
		hdmStore.addNode("room", "NG26");
		hdmStore.addNode("room", "B34E");
		hdmStore.addNode("project", "automed");
		hdmStore.addNode("project", "tristarp");
		hdmStore.addNode("houseNumber", "64");
		hdmStore.addNode("road", "Northdown Street");
		hdmStore.addNode("town", "London");
		hdmStore.addNode("postCode", "N1 9BS");
		hdmStore.addNode("houseNumber", "10");
		hdmStore.addNode("road", "Downing Street");
		hdmStore.addNode("postCode", "W1 CND");
		hdmStore.listNodes();

		// add edges

		edge =
			new Edge(
				"<<worksIn,person,project>>",
				new String[] { "dean", "tristarp" });
		hdmStore.addEdge(edge);

		edge =
			new Edge(
				"<<worksIn,person,project>>",
				new String[] { "mat", "tristarp" });
		hdmStore.addEdge(edge);

		edge =
			new Edge(
				"<<worksIn,person,project>>",
				new String[] { "hao", "automed" });
		hdmStore.addEdge(edge);

		edge =
			new Edge(
				"<<worksIn,person,project>>",
				new String[] { "edgar", "automed" });
		hdmStore.addEdge(edge);

		edge =
			new Edge(
				"<<worksIn,person,project>>",
				new String[] { "dean", "automed" });
		hdmStore.addEdge(edge);

		edge =
			new Edge("<<worksIn,person,room>>", new String[] { "mat", "B34E" });
		hdmStore.addEdge(edge);

		edge =
			new Edge(
				"<<worksIn,person,room>>",
				new String[] { "dean", "B34E" });
		hdmStore.addEdge(edge);

		edge =
			new Edge("<<worksIn,person,room>>", new String[] { "hao", "NG26" });
		hdmStore.addEdge(edge);

		edge =
			new Edge(
				"<<worksIn,person,room>>",
				new String[] { "edgar", "NG26" });
		hdmStore.addEdge(edge);

		edge =
			new Edge(
				"<<address,houseNumber,road,town,postCode>>",
				new String[] { "64", "Northdown Street", "London", "N1 9BS" });
		hdmStore.addEdge(edge);

		edge =
			new Edge(
				"<<livesAt,person,<<address,houseNumber,road,town,postCode>>>>",
				new String[] { "dean", "[64,Northdown Street,London,N1 9BS]" });
		hdmStore.addEdge(edge);

		edge =
			new Edge(
				"<<address,houseNumber,road,town,postCode>>",
				new String[] { "10", "Downing Street", "London", "W1 CND" });
		hdmStore.addEdge(edge);

		edge =
			new Edge(
				"<<livesAt,person,<<address,houseNumber,road,town,postCode>>>>",
				new String[] { "tony", "[10,Downing Street,London,W1 CND]" });
		hdmStore.addEdge(edge);
		
		System.out.println("about to test node deletes:\n\n");
		
		result = hdmStore.deleteNode("animal","bear");
		System.out.println("result of trying to delete node <<animal>> [bear] (node type not in the schema) was :" + result + "\n\n");
			
		result = hdmStore.deleteNode("person","bill");
		System.out.println("result of trying to delete node <<person>> [bill] (not in the db) was :" + result + "\n\n");
		
		result = hdmStore.deleteNode("person","dean");
		System.out.println("result of trying to delete node <<person>> [dean] (in the db, but in an edge) was :" + result + "\n\n");
		
		result = hdmStore.deleteNode("person","liz");
		System.out.println("result of trying to delete node <<person>> [liz] (in the db, not in any edge) was :" + result + "\n\n");
		
		result = hdmStore.deleteNode("person","liz");
		System.out.println("result of trying to delete node <<person>> [liz] (already deleted!) was :" + result + "\n\n");
					
		System.out.println("\n\n\nabout to test edge deletes:\n\n");
		
		result = hdmStore.deleteEdge("<<worksIn,person,postcode>>","[dean,N1 9BS]");
		System.out.println("result of trying to delete edge "
			+ "\n\t<<worksIn,person,postcode>>"
			+ "\n\t[dean,N1 9BS]"
			+ "\n\t(edge type not in the schema) was :"
			+ result + "\n\n");
		
		result = hdmStore.deleteEdge("<<worksIn,person,room>>","[hao,B34E]");
		System.out.println("result of trying to delete edge "
			+ "\n\t<<worksIn,person,room>>"
			+ "\n\t[hao,B34E]"
			+ "\n\t(edge not in the db) was :"
			+ result + "\n\n");
		
		result = hdmStore.deleteEdge("<<address,houseNumber,road,town,postCode>>",
							"[64,Northdown Street,London,N1 9BS]");
		System.out.println("result of trying to delete edge "
			+ "\n\t<<address,houseNumber,road,town,postCode>>"
			+ "\n\t[64,Northdown Street,London,N1 9BS]" 
			+ "\n\t(edge part of another edge) was :"
			+ result + "\n\n");
			
		result = hdmStore.deleteEdge("<<worksIn,person,project>>",
							"[mat,tristarp]");
		System.out.println("result of trying to delete edge "
			+ "\n\t<<worksIn,person,project>>"
			+ "\n\t[mat,tristarp]"
			+ "\n\t(should be OK) was \t:"
			+ result + "\n\n");			
			
			
		result = hdmStore.deleteEdge("<<livesAt,person,<<address,houseNumber,road,town,postCode>>>>",
							"[tony,[10,Downing Street,London,W1 CND]]");
		System.out.println("result of trying to delete edge "
			+ "\n\t<<livesAt,person,<<address,houseNumber,road,town,postCode>>>>"
			+ "\n\t[tony,[10,Downing Street,London,W1 CND]]"
			+ "\n\t(should be OK) was :"
			+ result + "\n\n");
			
		result = hdmStore.deleteEdge("<<livesAt,person,<<address,houseNumber,road,town,postCode>>>>",
									"[tony,[10,Downing Street,London,W1 CND]]");
		System.out.println("result of trying to delete edge "
			+ "\n\t<<livesAt,person,<<address,houseNumber,road,town,postCode>>>>"
			+ "\n\t[tony,[10,Downing Street,London,W1 CND]]"
			+ "\n\t(already deleted!) was :"
			+ result + "\n\n");
	
	}



	/** 
	 *  Demonstrate the use of the HDM store API 
	 */
	public static void main(String args[])
		throws Exception, Exception, SQLException, IOException
	{

		DemoHdmStoreApi demo = new DemoHdmStoreApi();

		demo.buildModel();
		demo.buildPersonnelSchema();
		demo.populatePersonnelSchema();
	}

}
