package query_processing.hospital.update;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.logging.Logger;

import uk.ac.bbk.dcs.automed.qproc.QProcLogger;
import uk.ac.bbk.dcs.automed.qproc.QueryProcessorConfiguration;
import uk.ac.bbk.dcs.automed.qproc.iql.ASG;
import uk.ac.bbk.dcs.automed.qproc.iql.Cell;
import uk.ac.bbk.dcs.automed.qproc.iql.IQLUtility;
import uk.ac.bbk.dcs.automed.qproc.iql.ParseException;
import uk.ac.bbk.dcs.automed.qproc.iql.SchemeInfo;
import uk.ac.bbk.dcs.automed.qproc.reformulate.BuildViewException;
import uk.ac.bbk.dcs.automed.qproc.reformulate.ReformulationUtility;
import uk.ac.bbk.dcs.automed.qproc.reformulate.ViewKey;
import uk.ac.ic.doc.automed.InconsistentException;
import uk.ac.ic.doc.automed.NotFoundException;
import uk.ac.ic.doc.automed.reps.Construct;
import uk.ac.ic.doc.automed.reps.Schema;
import uk.ac.ic.doc.automed.reps.SchemaObject;
import uk.ac.ic.doc.automed.reps.Scheme;
import uk.ac.ic.doc.automed.reps.Transformation;

public class HospitalPeerQuery {

	// protected static Logger _logger = QProcLogger.getDebugLogger();

	protected static Map _instanceCache = new HashMap();

	protected Schema _sourceSchema;

	protected Schema _targetSchema;

	protected String _name;

	protected Map _viewMap = new HashMap();

	protected QueryProcessorConfiguration _qpc;

	public static void main(String[] args) throws Exception {
		HospitalPeerQuery hsp = new HospitalPeerQuery();
		hsp._sourceSchema = Schema.getSchema("hs1");
		hsp._targetSchema = Schema.getSchema("pubh1");
		hsp.buildViews("snslabel");
		hsp._sourceSchema = Schema.getSchema("pubh1");
		hsp._targetSchema = Schema.getSchema("hs1");
		hsp.buildViews("isnslabel");
		hsp._sourceSchema = Schema.getSchema("hs2");
		hsp._targetSchema = Schema.getSchema("pubh1");
		hsp.buildViews("snslabel");
		hsp._sourceSchema = Schema.getSchema("pubh1");
		hsp._targetSchema = Schema.getSchema("hs2");
		hsp.buildViews("isnslabel");
		hsp._sourceSchema = Schema.getSchema("hs1");
		hsp._targetSchema = Schema.getSchema("hs2");
		hsp.buildViews("snslabel");
		hsp._sourceSchema = Schema.getSchema("hs2");
		hsp._targetSchema = Schema.getSchema("hs1");
		hsp.buildViews("snslabel");
	}

	protected void buildViews(String direction) throws Exception {
		try {
			Schema[] path = _sourceSchema.findShortestPath(_targetSchema);
			log("\\subsection{$" + _sourceSchema.getName().toUpperCase()
					+ "\\rightarrow " + _targetSchema.getName().toUpperCase()
					+ "$}\n");
			log("\\begin{small}\\begin{snstranslist}");
			for (int i = 0; i < (path.length - 1); i++) {
				Schema from = path[i];
				Schema to = path[i + 1];
				Transformation t = Transformation.getTransformation(from, to);
				log(toText(t, from));
				//log(toLaTeX(t, from, direction));
			}
			log("\\end{snstranslist}\n\\end{small}\\newline\n");

		} catch (Exception e) {
			throw new BuildViewException(
					"Exception while building Atomic views", e);
		}
	}

	private String toText(Transformation t, Schema s1) throws Exception {
		String act = t.getActionNameFrom(s1);
		String lat = "";
		Schema s2 = t.getOtherSchema(s1);
		SchemaObject so;

		switch (t.getActionFrom(s1)) {
		case Transformation.ACTION_ADD:
		case Transformation.ACTION_EXTEND:
			so = t.getSchemaObject(s2);
			break;
		case Transformation.ACTION_RENAME:
			so = (SchemaObject) t.getSchemaObject(s1).getSchemeDefinition()[0];
			break;
		case Transformation.ACTION_DELETE:
		case Transformation.ACTION_CONTRACT:
			so = t.getSchemaObject(s1);
			break;
		case Transformation.ACTION_IDENT:
			return lat;
		default:
			throw new InconsistentException(
					"Don't know about transformations of " + "type="
							+ t.getActionFrom(s1));
		}
		// Get on the construct name, with first letter capitalised
		Construct c = so.getConstruct();
		String cname = c.getName();
		cname = cname.substring(0, 1).toUpperCase() + cname.substring(1);
		// Scheme[] scheme = so.getSchemeObjects();
		// String soStr = "";
		// for (int i = 0; i < scheme.length; i++) {
		// if (scheme[i].isKey()) {
		// if (i > 0)
		// soStr += ",";
		// soStr += scheme[i].getRefSchemaObject().getValue();
		// }
		// }
		//		
		// String schemeName = formatSchemaObject(so);
		lat += act + cname + "(" + so.getSchemeNamesString(true) + ","
				+ t.getFunction() + ")";
		return lat;
	}

	private String toLaTeX(Transformation t, Schema s1, String direction)
			throws Exception {
		String act = t.getActionNameFrom(s1);
		String lat = "";
		Schema s2 = t.getOtherSchema(s1);
		SchemaObject so;

		switch (t.getActionFrom(s1)) {
		case Transformation.ACTION_ADD:
		case Transformation.ACTION_EXTEND:
			so = t.getSchemaObject(s2);
			break;
		case Transformation.ACTION_RENAME:
			so = (SchemaObject) t.getSchemaObject(s1).getSchemeDefinition()[0];
			break;
		case Transformation.ACTION_DELETE:
		case Transformation.ACTION_CONTRACT:
			so = t.getSchemaObject(s1);
			break;
		case Transformation.ACTION_IDENT:
			return lat;
		default:
			throw new InconsistentException(
					"Don't know about transformations of " + "type="
							+ t.getActionFrom(s1));
		}
		// Get on the construct name, with first letter capitalised
		Construct c = so.getConstruct();
		String cname = c.getName();
		cname = cname.substring(0, 1).toUpperCase() + cname.substring(1);
		String schemeName = formatSchemaObject(so);
		// \snslabel{12}\iqlcode
		// {extendTable(\hdme{allTreatments, ni, date, desc}, Range\ Void\
		// Any)}\\
		// \snslabel{13}
		// \iqlcode{contractAttribute(\hdme{hpatient, age}, Range\ Void\ Any)}\\
		// \snslabel{}\iqlcode{extendTable(\hdme{allPatients},Range
		// [{ni}|{ni}<-<<patient>>] Any)

		// SNS label
		String snslabel = _sourceSchema + "_" + _targetSchema + "_" + act + "_"
				+ schemeName.replace(",", "_");
		;
		// Format output
		String prefix = "\\" + direction + "{" + snslabel + "}\\ \\iqlcode{{";
		lat += prefix + act + cname + "(\\hdme{" + schemeName + "},";
		// Format transformation query
		String qs = t.getFunction();
		String outLat = "";
		if (qs != null) {
			qs = qs.replaceAll("\\{", "\\\\{");
			qs = qs.replaceAll("\\}", "\\\\}");
			qs = qs.replaceAll("<<", " \\\\hdme{");
			qs = qs.replaceAll(">>", "}");
			qs = qs.replaceAll("<-", " \\\\leftarrow ");
			qs = qs.replaceAll("Range", "Range\\\\ ");
			qs = qs.replaceAll("Void", "\\\\ Void\\\\ ");
			qs = qs.replaceAll("Any", "\\\\ Any\\\\ ");
			qs = qs.replaceAll("]", "]\\\\ ");
			qs = qs.replaceAll("' '", "'\\\\ '");
			while (qs.indexOf(";  ") != -1) {
				qs = qs.replaceAll(";  ", ";");
			}
			String tempLat = lat;
			int bi = 0;
			while (true) {
				int sc = qs.indexOf(";", bi);
				if (sc == -1) {
					tempLat += qs.substring(bi) + ")}}\\\\";
					outLat += tempLat;
					break;
				}
				if ((tempLat.length() + (sc - bi + 1)) > 100) {
					outLat += tempLat + "}}\\\\";
					tempLat = "\n\\multicolumn{1}{l}{\\indent\\iqlcode{";
				}
				tempLat += qs.substring(bi, sc + 1);
				bi = sc + 1;
			}
		} else {
			outLat = lat + ")}}\\\\";
		}

		// if (t.getActionFrom(s1)==Transformation.ACTION_RENAME)
		// lat+=","+((SchemaObject)t.getSchemaObject(s2).getSchemeDefinition()[0]).
		// toLaTeX();
		// if (c.getConstructClass()!=Construct.CLASS_CONSTRAINT &&
		// t.getFunction()!=null)
		// lat+=","+t.getFunction();
		//			    
		// if (t.getConstraint()!=null &&
		// !Transformation.IQL_TRUE_CONSTRAINT.equals(t.getConstraint()))
		// lat+=","+t.getConstraint();

		return outLat;

	}

	private String formatSchemaObject(SchemaObject s) {
		String so = "";
		Scheme[] scheme = s.getSchemeObjects();
		so += "";
		for (int i = 0; i < scheme.length; i++) {
			if (scheme[i].isKey()) {
				if (i > 0)
					so += ",";
				so += scheme[i].getRefSchemaObject().getValue();
			}
		}
		return so;
	}

	private void log(String s) {
		System.out.println(s);
	}
}
