package query_processing.student;
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.*;

/**
 * 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.
 * 
 * @author <a href="mailto:sandeep@dcs.bbk.ac.uk">Sandeep Mittal</a>
 */
public class StudentDatabaseWrapping {
	static String username = "postgres";
	static String password = "manager";
	static String driver = "org.postgresql.Driver";
	static String urlbase = "jdbc:postgresql://localhost/";

	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: "
					+ "Wrapping of Student Databases");

			// Wrap using SQL Wrapper 
			wf = new SQLWrapperFactory();
			// Set the wrapper factory features
			wf.setFeatures(SQLWrapperFactory.PRIMARY_KEY);
			wf.setFeatures(SQLWrapperFactory.FOREIGN_KEY);
			wf.setFeatures(SQLWrapperFactory.DATA_TYPE);
			wf.setFeatures(SQLWrapperFactory.DATA_SIZE);
			wf.setFeatures(SQLWrapperFactory.NULL_CONSTRAINT);

			if (schemaChoice == null || "s1".equals(schemaChoice))
				wrapSchema(username, password, driver, urlbase,
						wf, "S1", "s1");
			if (schemaChoice == null || "s2".equals(schemaChoice))
				wrapSchema(username, password, driver, urlbase,
						wf, "S2", "s2");
			if (schemaChoice == null || "s3".equals(schemaChoice))
				wrapSchema(username, password, driver, urlbase,
						wf, "S3", "s3");

		} catch (SQLException se) {
			se.printStackTrace();
		} catch (IOException ie) {
			ie.printStackTrace();
		} catch (AutoMedException ame) {
			ame.printStackTrace();
		} catch (Throwable t) {
			System.err.println(t.toString());
			t.printStackTrace();
		}
	}

	public static Schema wrapSchema(
			String username, String password,
			String driver, String urlbase, 
			SQLWrapperFactory wf, String db,
			String name) throws Exception {
		
		// If schema exists, retract those from the repository.
		// AutoMed oriented schema
		if (Schema.exists(name))
			Schema.getSchema(name).retract();
        // Datasource oriented schema
		String sourceName = name + "_src";
		if (Schema.exists(sourceName))
			Schema.getSchema(sourceName).retract();

		// Get the Source oriented schema
		AutoMedWrapper sw = AutoMedWrapper.selectNewAutoMedWrapper(username,
				password, null, driver, urlbase + db, sourceName, wf);
		Schema sourceSchema = sw.getSchema();
		banner(sourceSchema.getName());
		sourceSchema.listSchema();

		// Generate an AutoMed oriented schema
		Schema s = sw.newAutoMedSchema(name);
		banner(s.getName());
		s.listSchema();

		return s;
	}

	static void printHelp() {
		System.out.println("Usage: StudentDatabaseWrapping [ options ]\n"
				+ "  -debug <0-10>         set debug level\n"
				+ "  -url <dbURL>          URL where DB located\n"
				+ "  -driver <jdbcDriverClass>\n" + "  -user <user>\n"
				+ "  -schema <schema name>\n" + "  -password <password>\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("-url"))
					urlbase = args[++i];
				else if (args[i].startsWith("-help"))
					printHelp();
				else if (args[i].startsWith("-driver"))
					driver = args[++i];
				else if (args[i].startsWith("-user"))
					username = args[++i];
				else if (args[i].startsWith("-schema"))
					schemaChoice = args[++i];
				else if (args[i].startsWith("-password"))
					password = args[++i];
				++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);
	}	
} // end StudentDatabaseWrapping


//--------------------------------------------------------------------------
//-- LAV Query processing example
//-- Students marks database
//-- Three extensional schemas - S1, S2 and S3
//-- One global/public schema - SP
//-- 
//-- Data constraints
//-- - each student studies for one degree
//-- - tutors introduced from 1994 onwards
//-- - cwmark only once per course for each student
//-- - student may repeatedly sit exam for a course over any number of 
//--    semesters
//-- - each student studies only one degree
//-- - each degree identified by dcode, has title dname, and has an 
//--   associated qualification
//--
//-- Author: Sandeep Mittal (sandeep@dcs.bbk.ac.uk)
//-- Last Modified : 24 August 2006
//--------------------------------------------------------------------------
//
//-- 
//-- Public Schema - SP
//-- degree (dcode, dname) pk dcode
//-- student (sname, dcode) pk sname
//-- course (ccode, title) pk ccode
//-- sit (sname, ccode, sem, mark, cwmark?) pk (sname, ccode, sem)
//-- 
//
//--------------------------------------------------------------------------
//-- datasource1 - S1
//--------------------------------------------------------------------------
//
//create table studies
//( sname  varchar(50) not null
//, ccode  integer not null check (ccode >= 500)
//, sem    char(6) not null
//, mark   integer not null
//, title  varchar(50) not null
//, dname  varchar(50) not null
//, constraint studies_pk primary key (sname, ccode, sem)
//);
//
//
//--------------------------------------------------------------------------
//-- datasource2 - S2
//--------------------------------------------------------------------------
//
//create table teach
//( sname varchar(50) not null 
//, ccode integer not null check (ccode < 500)
//, sem   char(6) not null
//, mark  integer not null
//, tname varchar(50)
//, constraint teach_pk primary key (sname, ccode, sem)
//);
//
//
//--------------------------------------------------------------------------
//-- datasource3 - S3
//--------------------------------------------------------------------------
//
//create table degree
//( dcode integer not null
//, dname varchar(50) not null
//, qual  varchar(50) not null
//, constraint degree_pk primary key (dcode)
//);
//
//
//create table ug
//( sname varchar(50) not null
//, dcode integer not null
//, constraint ug_pk primary key (sname)
//, constraint ug_deg_fk foreign key (dcode) references degree (dcode)
//);
//
//
//create table reg
//( sname varchar(50) not null
//, ccode integer not null
//, cwmark integer null
//, tutor  varchar(50) not null
//, constraint reg_pk primary key (sname, ccode)
//, constraint reg_ug_fk foreign key (sname) references ug (sname)
//);
//
//
//
//--------------------------------------------------------------------------
//
//-- Schema S1
//insert into studies (sname,ccode,sem,mark,title,dname) values ('student1',500,'1993-1',90,'course500','BSc Computer Science');
//insert into studies (sname,ccode,sem,mark,title,dname) values ('student1',600,'1994-1',80,'course600','BSc Computer Science');
//insert into studies (sname,ccode,sem,mark,title,dname) values ('student1',700,'1995-2',70,'course700','BSc Computer Science');
//insert into studies (sname,ccode,sem,mark,title,dname) values ('student1',800,'1996-1',90,'course800','BSc Computer Science');
//insert into studies (sname,ccode,sem,mark,title,dname) values ('student1',900,'1997-1',90,'course900','BSc Computer Science');
//insert into studies (sname,ccode,sem,mark,title,dname) values ('student2',500,'1994-2',90,'course500','BSc Mathematics');
//insert into studies (sname,ccode,sem,mark,title,dname) values ('student2',600,'1995-1',80,'course600','BSc Mathematics');
//insert into studies (sname,ccode,sem,mark,title,dname) values ('student2',700,'1996-2',70,'course700','BSc Mathematics');
//insert into studies (sname,ccode,sem,mark,title,dname) values ('student2',800,'1997-1',90,'course800','BSc Mathematics');
//insert into studies (sname,ccode,sem,mark,title,dname) values ('student2',900,'1998-2',90,'course900','BSc Mathematics');
//
//
//-- Schema S2
//insert into teach (sname,ccode,sem,mark,tname) values ('student1',100,'1993-2',90,'tutor1');
//insert into teach (sname,ccode,sem,mark,tname) values ('student1',200,'1994-2',70,'tutor2');
//insert into teach (sname,ccode,sem,mark,tname) values ('student1',300,'1995-1',80,'tutor3');
//insert into teach (sname,ccode,sem,mark,tname) values ('student1',400,'1996-2',90,'tutor4');
//insert into teach (sname,ccode,sem,mark,tname) values ('student2',100,'1994-2',90,'tutor1');
//insert into teach (sname,ccode,sem,mark,tname) values ('student2',200,'1995-2',70,'tutor2');
//insert into teach (sname,ccode,sem,mark,tname) values ('student2',300,'1996-1',80,'tutor3');
//insert into teach (sname,ccode,sem,mark,tname) values ('student2',400,'1997-2',90,'tutor4');
//insert into teach (sname,ccode,sem,mark,tname) values ('student2',450,'1997-2',90,'tutor4');
//
//-- Schema S3
//insert into degree (dcode, dname, qual) values (100,'BSc Computer Science', 'Bachelors');
//insert into degree (dcode, dname, qual) values (200,'BSc Mathematics', 'Masters');
//
//insert into ug (sname, dcode) values ('student1', 100);
//insert into ug (sname, dcode) values ('student2', 200);
//
//insert into reg (sname,ccode,cwmark,tutor) values ('student1',200,75,'tutor2');
//insert into reg (sname,ccode,cwmark,tutor) values ('student1',250,65,'tutor2');
//insert into reg (sname,ccode,cwmark,tutor) values ('student1',300,85,'tutor3');
//insert into reg (sname,ccode,cwmark,tutor) values ('student1',600,70,'tutor6');
//insert into reg (sname,ccode,cwmark,tutor) values ('student2',500,80,'tutor5');
//insert into reg (sname,ccode,cwmark,tutor) values ('student1',210,null,'tutor2');
//insert into reg (sname,ccode,cwmark,tutor) values ('student1',220,null,'tutor2');
//--------------------------------------------------------------------------------
