import uk.ac.ic.doc.automed.templates.wrapper.*;
import uk.ac.ic.doc.automed.reps.*;
import uk.ac.ic.doc.automed.wrappers.SQLWrapperFactory;
import uk.ac.ic.doc.automed.InconsistentException;
import uk.ac.ic.doc.automed.IntegrityException;


public class MandatoryFieldHierarchyEquivalence extends TemplateCompilerSimulator
{
  static final Model defaultModel;

  static {
    SQLWrapperFactory swf=new SQLWrapperFactory();

    try {
      swf.setFeatures(2);
    }
    catch (IntegrityException e) {
      throw new InconsistentException("Unable to set features of new wrapper"+
				      " factory",e);
    }

    defaultModel=swf.getAutoMedModel();
  } 

	public MandatoryFieldHierarchyEquivalence()
		throws Exception
	{
		super();
	}

	//Define the abstract methods//

	protected String templateName()
	{
		return "Field to Hierarchy Equivalence (sql_2 model, no foreign key creation)";
	}

	protected String templateDescription()
	{
		return "Removes mandatory field and creates specialization relations for each instance of the field";
	}

	protected String defaultModel()
	{
		return defaultModel.getName();
	}



	//Define the template//


	protected void defineTemplate()
		throws Exception
	{
		Model rel =defaultModel;
		Construct table = rel.getConstruct("table");
		Construct field = rel.getConstruct("column");
//		Construct foreignkey = rel.getConstruct("foreign_key");
		Construct primarykey = rel.getConstruct("primary_key");

		INPUTS();
			OBJECT parentTable = askForObject("Existing parent relation", table);
			OBJECT mandatoryField = askForObject("Mandatory attribute", field);
			OBJECT parentPrimaryKey = askForObject("Primary key of parent relation", field);
			NAMELIST specializationTableNames = askForNameList("Names of specialization relations");
			NAMELIST descriptiveInstances = askForNameList("Values of the attribute that correspond to the specialization relations", 
							SIZEOF(specializationTableNames));

		START();
			FOREACH(); NAME specializationTableName = IN (specializationTableNames);
				NAME descriptiveInstance = IN (descriptiveInstances);
				OBJECT parentfield = VARIES_WITH(mandatoryField);
				OBJECT parent = VARIES_WITH(parentTable);
				OBJECT primaryKey = VARIES_WITH(parentPrimaryKey);

			DO();
				ALIAS(specializationTableName, "specializationTableName");
				ALIAS(descriptiveInstance, "descriptiveInstance");
				ALIAS(parentfield, "parentfield");
				ALIAS(parent, "parent");
				ALIAS(primaryKey,"primarykey");

				FUNCTION tableExtent = DEFINE_FUNCTION("[ {x} | {x,y} <- @parentfield?scheme ; (=) y '@descriptiveInstance']");
				OBJECT newSpecialization= ADD( CONSTRUCT.IS(table), 
												  SCHEME.IS(new Object[]{my(specializationTableName)}),
												  FUNCTION.IS(tableExtent)
												);

				
				FUNCTION fieldExtent = DEFINE_FUNCTION("[ {x,y} | {x,y} <- @primarykey?scheme ; {x1,z} <- @parentfield?scheme ; (=) z '@descriptiveInstance' ; (=) x x1]");
				NAME fieldName = DEFINE_NAME("@primarykey?name");
				OBJECT newField = ADD( CONSTRUCT.IS(field),
									SCHEME.IS(new Object[]{newSpecialization, my(fieldName)}),
									FUNCTION.IS(fieldExtent)
								  );

				OBJECTLIST primaryKeyFields = (OBJECTLIST)CREATE_LIST(new ITEM[]{newField});
				NAME primarykeyName = DEFINE_NAME("@(specializationTableName)_pk");
				ADD( CONSTRUCT.IS(primarykey),
					 SCHEME.IS(new Object[]{my(primarykeyName),newSpecialization, primaryKeyFields})
				   );
				
				//NAME foreignkeyName = DEFINE_NAME("@(specializationTableName)_fk");
				//ADD( CONSTRUCT.IS(foreignkey),
			//		 SCHEME.IS(new Object[]{my(foreignkeyName),newSpecialization,newField,parent,parentfield})
			//	   );

				ALIAS(newSpecialization,"specialization");
				STRING partialQuery= DEFINE_STRING("[ {x,y}|{x} <- @specialization?scheme; (=) y '@descriptiveInstance']");
				STRINGLIST partialQueriesForMandatoryField = (STRINGLIST)COLLECTS(partialQuery);				

			ENDFOREACH();

			STRING query = DEFINE_STRING(partialQueriesForMandatoryField, "++");
			ALIAS(query,"query");
			FUNCTION mandatoryFieldExtent = DEFINE_FUNCTION("@query");
			mandatoryField.DELETE(mandatoryFieldExtent);
		END();
	}

	
	public static void main(String[] args){
		try{
			new MandatoryFieldHierarchyEquivalence();
		}
		catch(Exception e){
			e.printStackTrace();
		}
	}
}
