public class OMTGCardinality {

	public static final String ONE_TO_ONE = "(1,1)";
	public static final String ONE_TO_MANY = "(1,*)";
	public static final String MANY_TO_ONE = "(*,1)";
	public static final String MANY_TO_MANY = "(*,*)";
	public static final int PARTIAL = 0;
	public static final int TOTAL = 1;

	private String min;
	private String max;
	private int participation;

	public OMTGCardinality(String cardString) {
		Scanner in = new Scanner(cardString);
		in.useDelimiter(",");
		this.min = in.next();
		this.max = in.next();
		if (min.equals("0")) 
			this.participation = 0; //partial
		else this.participation = 1; //total
		
		in.close();
	}

	public OMTGCardinality(String min, String max) {
		this.min = min;
		this.max = max;
		if (min.equals("0")) 
			this.participation = 0; //partial
		else this.participation = 1; //total
	}

	public int getParticipation() {
		return participation;
	}

	public String getMin() {
		return min;
	}

	public String getMax() {
		return max;
	}

	public boolean isEqual(OMTGCardinality card) {
		if ((min.equals(card.getMin()) && max.equals(card.getMax())) ||
				(min.equals(card.getMax()) && max.equals(card.getMin()))) {
			return true;
		}
		return false;
	}

	public String toString() {
		return "(" + min + "," + max + ")";
	}
} public class OMTGClass implements Cloneable {

	public static final String PLANAR_SUBDIVISION = "planar-subdivision";
	public static final String ISOLINES = "isolines";
	public static final String TESSELATION = "tesselation";
	public static final String TIN = "TIN";

	private String name, type;
	private List<OMTGRelationship> relationships;
	private List<OMTGAttribute> attributes;
	private OMTGGeneralization generalization;
	private boolean isSuperClass;

	public OMTGClass(String name, String type, List<OMTGAttribute> attributes) {
		this.name = name;
		this.type = type;
		this.attributes = attributes;
		this.relationships = new ArrayList<OMTGRelationship>();
		this.isSuperClass = false;
	}

	public String getName() {
		return name;
	}

	public List<OMTGAttribute> getAttributes() {
		return attributes;
	}

	public List<OMTGAttribute> getAttributesWithPrefix(String prefix) {

		prefix += "_";

		List<OMTGAttribute> attributesAux = new ArrayList<OMTGAttribute>();
		for (int i = 0; i < attributes.size(); i++) {

			OMTGAttribute newAttribute;
			try {
				newAttribute = (OMTGAttribute) attributes.get(i).clone();
				newAttribute.setName(prefix + newAttribute.getName());
				attributesAux.add(newAttribute);
			} catch (CloneNotSupportedException e) {
				e.printStackTrace();
			}
		}

		return attributesAux;
	}

	public void addRelationship(OMTGRelationship r) {
		relationships.add(r);
	}

	public List<OMTGRelationship> getRelationships() {
		return relationships;
	}

	public void addAttribute(OMTGAttribute a) {
		attributes.add(a);
	}

	public String toString() {
		return name;
	}

	public OMTGGeneralization getGeneralization() {
		return generalization;
	}

	public boolean hasGeneralization() {
		return generalization != null;
	}

	public void setGeneralization(OMTGGeneralization i) {
		generalization = i;
	}

	public boolean isSuperClass() {
		return isSuperClass;
	}

	public void setSuperClass(boolean isSuperClass) {
		this.isSuperClass = isSuperClass;
	}

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public boolean typeEquals(String type) {
		return this.type.equalsIgnoreCase(type);
	}

	public boolean isSpatial() {
		return !typeEquals("conventional");
	}

	public boolean isPlanarSubdivision() {
		return type.equalsIgnoreCase(PLANAR_SUBDIVISION);
	}

	public boolean isIsoline() {
		return type.equalsIgnoreCase(ISOLINES);
	}

	public boolean isTesselation() {
		return type.equalsIgnoreCase(TESSELATION);
	}

	public boolean isTIN() {
		return type.equalsIgnoreCase(TIN);
	}

	public void setAttributes(List<OMTGAttribute> attributes) {
		this.attributes = attributes;
	}

	public List<String> getAttributesName() {
		List<String> attributesName = new ArrayList<String>();
		for (OMTGAttribute attribute : attributes) {
			attributesName.add(attribute.getName());
		}
		return attributesName;
	}

	public List<String> getAttributesType() {
		List<String> attributesType = new ArrayList<String>();
		for (OMTGAttribute attribute : attributes) {
			attributesType.add(attribute.getType());
		}
		return attributesType;
	}

	public List<String> getKeysName() {
		List<String> keys = new ArrayList<String>();
		for (OMTGAttribute attribute : attributes) {
			if (attribute.isKey() == true) {
				keys.add(attribute.getName());
			}
		}
		return keys;
	}

	public List<String> getKeysType() {
		List<String> keysType = new ArrayList<String>();
		for (OMTGAttribute attribute : attributes) {
			if (attribute.isKey() == true) {
				keysType.add(attribute.getType());
			}
		}
		return keysType;
	}

	public List<String> getKeysLength() {
		List<String> keysType = new ArrayList<String>();
		for (OMTGAttribute attribute : attributes) {
			if (attribute.isKey() == true) {
				keysType.add(attribute.getLength());
			}
		}
		return keysType;
	}

	public List<String> getKeysScale() {
		List<String> keysType = new ArrayList<String>();
		for (OMTGAttribute attribute : attributes) {
			if (attribute.isKey() == true) {
				keysType.add(attribute.getScale());
			}
		}
		return keysType;
	}

	public List<OMTGAttribute> getAttributeKeys() {
		List<OMTGAttribute> keys = new ArrayList<OMTGAttribute>();
		for (OMTGAttribute attribute : attributes) {
			if (attribute.isKey() == true) {
				keys.add(attribute);
			}
		}
		return keys;
	}

	public List<String> getAttributeLength() {
		List<String> lengthAttributes = new ArrayList<String>();
		for (OMTGAttribute attribute : attributes) {
			lengthAttributes.add(attribute.getLength());
		}
		return lengthAttributes;
	}

	public List<String> getAttributeScale() {
		List<String> scaleAttributes = new ArrayList<String>();
		for (OMTGAttribute attribute : attributes) {
			scaleAttributes.add(attribute.getScale());
		}
		return scaleAttributes;
	}

	public List<Boolean> getAttributeNotNulls() {
		List<Boolean> notNullsAttributes = new ArrayList<Boolean>();
		for (OMTGAttribute attribute : attributes) {
			notNullsAttributes.add(attribute.isNotNull());
		}
		return notNullsAttributes;
	}

	public List<String> getAttributeDefault() {
		List<String> defaultAttribute = new ArrayList<String>();
		for (OMTGAttribute attribute : attributes) {
			defaultAttribute.add(attribute.getDefaultValue());
		}
		return defaultAttribute;
	}

	public List<String> getAttributeSize() {
		List<String> sizeAttribute = new ArrayList<String>();
		for (OMTGAttribute attribute : attributes) {
			sizeAttribute.add(attribute.getSize());
		}
		return sizeAttribute;
	}

	public List<List<String>> getAttributeDomain() {
		List<List<String>> domain = new ArrayList<List<String>>();
		for (OMTGAttribute attribute : attributes) {
			domain.add(attribute.getDomain());
		}
		return domain;
	}

	public boolean hasAttributeWithDomain() {

		for (OMTGAttribute attribute : attributes) {
			if (attribute.getDomain() != null) {
				return true;
			}
		}
		return false;
	}

	public Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
} public class OMTGSchema {

	private Map<String, OMTGClass> classes;
	private Map<String, OMTGRelationship> relationships;

	public OMTGSchema(Map<String, OMTGClass> classes, Map<String, OMTGRelationship> relationships) throws CloneNotSupportedException {
		this.classes = classes;
		this.relationships = relationships;
	}

	public OMTGClass getClass(String className) {
		return classes.get(className);
	}

	public List<OMTGClass> getClassesNotInGeneralization() {

		List<OMTGClass> classesNotInGeneralization = new ArrayList<OMTGClass>();
		List<OMTGClass> generalizationClasses = getClassesInGeneralization();

		for (OMTGClass omtgClass : classes.values()) {

			if (!generalizationClasses.contains(omtgClass)) {
				classesNotInGeneralization.add(omtgClass);
			}
		}

		return classesNotInGeneralization;
	}

	public List<OMTGClass> getClassesInGeneralization() {

		List<OMTGClass> generalizationClasses = new ArrayList<OMTGClass>();
		generalizationClasses.addAll(getSubClasses());
		generalizationClasses.addAll(getSuperClasses());

		return generalizationClasses;
	}

	public List<OMTGClass> getSuperClasses() {

		List<OMTGClass> superClasses = new ArrayList<OMTGClass>();

		for (OMTGRelationship omtgRel : relationships.values()) {
			if (omtgRel.typeEquals("conventional-generalization") || omtgRel.typeEquals("conceptual-generalization")) {

				OMTGClass superClass = getClass(((OMTGGeneralization)omtgRel).getSuperClass());
				superClasses.add(superClass);
			}
		}

		return superClasses;
	}

	public List<OMTGClass> getSuperClassesOfTotalGeneralization() {

		List<OMTGClass> superClasses = new ArrayList<OMTGClass>();

		for (OMTGRelationship omtgRel : relationships.values()) {
			
			if (omtgRel.typeEquals("conventional-generalization")) {

				if (((OMTGConventionalGeneralization)omtgRel).isTotal()) {
					OMTGClass superClass = getClass(((OMTGGeneralization)omtgRel).getSuperClass());
					superClasses.add(superClass);
				}

				if (omtgRel.typeEquals("conceptual-generalization")) {

					OMTGClass superClass = getClass(((OMTGGeneralization)omtgRel).getSuperClass());
					superClasses.add(superClass);
				}
			}
		}

		return superClasses;
	}

	public List<OMTGClass> getSubClasses() {

		List<OMTGClass> subClasses = new ArrayList<OMTGClass>();

		for (OMTGRelationship omtgRel : relationships.values()) {
			if (omtgRel.typeEquals("conventional-generalization") || omtgRel.typeEquals("conceptual-generalization")) {

				subClasses.addAll(getSubClasses((OMTGGeneralization)omtgRel));
			}
		}

		return subClasses;
	}

	public List<OMTGClass> getSubClasses(OMTGGeneralization rel) {

		List<OMTGClass> subClasses = new ArrayList<OMTGClass>();
		List<String> subClassesName = rel.getSubclasses();

		for (int i = 0; i < subClassesName.size(); i++) {

			subClasses.add(getClass(subClassesName.get(i)));
		}

		return subClasses;
	}

	public List<OMTGClass> getSubClasses(OMTGClass superClass) {

		for (OMTGRelationship omtgRel : relationships.values()) {
			if (omtgRel.typeEquals("conventional-generalization") || omtgRel.typeEquals("conceptual-generalization")) {

				if (((OMTGGeneralization)omtgRel).getSuperClass().equalsIgnoreCase(superClass.getName())) {

					return getSubClasses((OMTGGeneralization)omtgRel);
				}
			}
		}

		return null;
	}

	public OMTGRelationship getRelationship(String relationshipName) {
		return relationships.get(relationshipName);
	}

	public List<OMTGClass> getClasses(String relationshipName) {

		OMTGRelationship rel = relationships.get(relationshipName);
		List<OMTGClass> classesList = new ArrayList<OMTGClass>();

		classesList.add(classes.get(rel.getClass1()));
		if (rel.getClass2() != null) { // in generalization and conceptual-generalization class2 is null
			classesList.add(classes.get(rel.getClass2()));
			return classesList;
		}
		return null;
	}

	public List<OMTGRelationship> getRelationshipsWithoutGeneralization() {

		List<OMTGRelationship> r = new ArrayList<OMTGRelationship>();
		for (OMTGRelationship omtgRel : relationships.values()) {

			if (!omtgRel.typeEquals("conventional-generalization") && !omtgRel.typeEquals("conceptual-generalization")) {

				r.add(omtgRel);
			}
		}
		return r;
	}

	public List<OMTGClass> getClasses() {
		return new ArrayList<OMTGClass>(classes.values());
	}

	public List<OMTGRelationship> getRelationships() {
		return new ArrayList<OMTGRelationship>(relationships.values());
	}

	public List<OMTGRelationship> getRelationships(String className) {
		return classes.get(className).getRelationships();
	}

	public List<String> getClassesNames() {
		return new ArrayList<String>(classes.keySet());
	}

	public List<String> getRelationshipsNames() {
		return new ArrayList<String>(relationships.keySet());
	}
} public class OMTGConceptualGeneralization extends OMTGGeneralization {

//	private static final String DISJOINT = "disjoint";
//	private static final String OVERLAPPING = "overlapping";

	/*
	 * completeness = (t)/(p) total, partial disjointness = (d)/(o) disjoint,
	 * overlapping
	 */
	private String disjointness, scaleShape;

	public OMTGConceptualGeneralization(String scaleShape, String disjointness,
			String superClass, List<String> subclasses) {
		super(disjointness, "conceptual-generalization", superClass, subclasses);
		this.scaleShape = scaleShape;
		this.disjointness = disjointness;
	}

	public String getDisjointness() {
		return disjointness;
	}

	public void setDisjointness(String disjointness) {
		this.disjointness = disjointness;
	}

	public String getScaleShape() {
		return scaleShape;
	}

	public void setScaleShape(String scaleShape) {
		this.scaleShape = scaleShape;
	}
} public class OMTGConventionalGeneralization extends OMTGGeneralization {

	/*
	 * completeness = (t)/(p) total, partial
	 * disjointness = (d)/(o) disjoint, overlapping
	 */
	private String completeness;

	public OMTGConventionalGeneralization(String completeness, String disjointness, String superClass, List<String> subclasses) {
		super(disjointness, "conventional-generalization", superClass, subclasses);
		this.completeness = completeness;
	}
	
	public boolean isTotal() {
		return completeness.equalsIgnoreCase("total");
	}
	
	public boolean isPartial() {
		return completeness.equalsIgnoreCase("partial");
	}
	
	public String getCompleteness() {
		return completeness;
	}

	public void setCompleteness(String completeness) {
		this.completeness = completeness;
	}
} public class OMTGConventionalRelationship extends OMTGRelationship {
	
	private OMTGCardinality cardinality1, cardinality2;
	
	public OMTGConventionalRelationship(String name, String class1, OMTGCardinality cardinality1, String class2, OMTGCardinality cardinality2) {
		super("conventional-relationship-" + class1 + "-" + name + "-" + class2, "conventional-relationship", class1, class2);
		this.cardinality1 = cardinality1;
		this.cardinality2 = cardinality2;
	}
	
	public String getCardinality() {
		return "(" + cardinality1.getMax() + "," + cardinality2.getMax() + ")";
	}
	
	public boolean cardinalityIsEqual(String card) {
		return getCardinality().equalsIgnoreCase(card);
	}

	public OMTGCardinality getCardinality1() {
		return cardinality1;
	}

	public void setCardinality1(OMTGCardinality cardinality1) {
		this.cardinality1 = cardinality1;
	}

	public OMTGCardinality getCardinality2() {
		return cardinality2;
	}

	public void setCardinality2(OMTGCardinality cardinality2) {
		this.cardinality2 = cardinality2;
	}

}
 public class OMTGGeneralization extends OMTGRelationship {
	
	private static final String TOTAL = "total";
	private static final String PARTIAL = "partial";
	private static final String DISJOINT = "disjoint";

	/*
	 * completeness = (t)/(p) total, partial
	 * disjointness = (d)/(o) disjoint, overlapping
	 */
	private String superClass, disjointness;
	private List<String> subclasses;

	public OMTGGeneralization(String disjointness, String type, String superClass, List<String> subclasses) {
		super("generalization-" + superClass, type, superClass, null);
		this.superClass = superClass;
		this.disjointness = disjointness;
		this.subclasses = subclasses;
	}
	
	public String getSuperClass() {
		return superClass;
	}

	public void setSuperClass(String superClass) {
		this.superClass = superClass;
	}

	public String getDisjointness() {
		return disjointness;
	}

	public void setDisjointness(String disjointness) {
		this.disjointness = disjointness;
	}

	public List<String> getSubclasses() {
		return subclasses;
	}

	public void setSubclasses(List<String> subclasses) {
		this.subclasses = subclasses;
	}

	public static String getTotal() {
		return TOTAL;
	}

	public static String getPartial() {
		return PARTIAL;
	}

	public static String getDisjoint() {
		return DISJOINT;
	}

	public boolean isDisjoint() {
		return disjointness.equalsIgnoreCase(DISJOINT);
	}
} public abstract class OMTGRelationship implements Cloneable {

	private String name;
	private String type;
	private String class1, class2;
	
	public OMTGRelationship(String name, String type, String class1, String class2) {
		this.name = name;
		this.type = type;
		this.class1 = class1;
		this.class2 = class2;
	}

	public String getName() {
		return name;
	}
	
	public String getType() {
		return type;
	}
	
	public boolean typeEquals(String type) {
		return this.type.equalsIgnoreCase(type);
	}
	
	public String getClass1() {
		return class1;
	}

	public void setClass1(String class1) {
		this.class1 = class1;
	}

	public String getClass2() {
		return class2;
	}

	public void setClass2(String class2) {
		this.class2 = class2;
	}
	
	public Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
} public class OMTGTopologicalRelationship extends OMTGRelationship {
	
	private List<String> spatialRelation; 
	private String distance, unit;
	private OMTGCardinality cardinality1, cardinality2;

	public OMTGTopologicalRelationship(List<String> spatialRelation, String distance, String unit, String class1, OMTGCardinality cardinality1, String class2, OMTGCardinality cardinality2) {
		super("topological-relationship-" + spatialRelation + "-" + class1 + "-" + class2, "topological-relationship", class1, class2);
		this.spatialRelation = spatialRelation;
		this.distance = distance;
		this.unit = unit;
		this.cardinality1 = cardinality1;
		this.cardinality2 = cardinality2;
	}

	public List<String> getSpatialRelation() {
		return spatialRelation;
	}

	public void setSpatialRelation(List<String> spatialRelation) {
		this.spatialRelation = spatialRelation;
	}

	public String getDistance() {
		return distance;
	}

	public void setDistance(String distance) {
		this.distance = distance;
	}

	public String getUnit() {
		return unit;
	}

	public void setUnit(String unit) {
		this.unit = unit;
	}

	public OMTGCardinality getCardinality1() {
		return cardinality1;
	}

	public void setCardinality1(OMTGCardinality cardinality1) {
		this.cardinality1 = cardinality1;
	}

	public OMTGCardinality getCardinality2() {
		return cardinality2;
	}

	public void setCardinality2(OMTGCardinality cardinality2) {
		this.cardinality2 = cardinality2;
	}
} public class PostgisGenerator {

	private DDLWriter ddl;
	private OffLineConstraintsWriter offLineConstraints;
	private OnLineConstraintsWriter onLineConstraints;

	public PostgisGenerator(String ddlFilePath, String offLineConstraintsFilePath,
			String onLineConstraintsFilePath) {

		this.ddl = new DDLWriter(ddlFilePath);
		this.offLineConstraints = new OffLineConstraintsWriter(
				offLineConstraintsFilePath);
		this.onLineConstraints = new OnLineConstraintsWriter(
				onLineConstraintsFilePath);
	}

	public PostgisGenerator(StringWriter ddlSW, StringWriter offLineConstraintsSW,
			StringWriter onLineConstraintsSW) {

		this.ddl = new DDLWriter(ddlSW);
		this.offLineConstraints = new OffLineConstraintsWriter(
				offLineConstraintsSW);
		this.onLineConstraints = new OnLineConstraintsWriter(
				onLineConstraintsSW);
	}
	
	private void createForeignKeyColumns(OMTGRelationship rel,
			OMTGClass omtgClassSec, OMTGClass omtgClassMain) {

		ddl.appendAlterTableAddColumn(rel.getName(), omtgClassMain.getName(),
				omtgClassSec.getName(), omtgClassSec.getKeysName(),
				omtgClassSec.getKeysType(), omtgClassSec.getKeysLength(),
				omtgClassSec.getKeysScale());
	}

	private void createForeignKeyConstraints(OMTGRelationship rel,
			OMTGClass omtgClassSec, OMTGClass omtgClassMain) {

		ddl.appendAlterTableAddForeignKeyConstraints(rel.getName(),
				omtgClassMain.getName(), omtgClassSec.getName(),
				omtgClassSec.getKeysName());
	}

	private void createForeignKeyConstraintsNN(OMTGRelationship rel,
			OMTGClass omtgClassM, OMTGClass omtgClassN) {

		ddl.appendAlterTableAddForeignKeyConstraintsMN(rel.getName(),
				omtgClassM.getName() + "_" + omtgClassN.getName(),
				omtgClassM.getName(), omtgClassM.getKeysName(),
				omtgClassN.getName(), omtgClassN.getKeysName());
	}

//	private void createInsertIntoUserSdoGeomMetadata(OMTGClass omtgClass) {
//
//		ddl.appendInsertIntoUserSdoGeomMetadata(omtgClass.getName(), null);
//	}

	private void createSpatialIndex(OMTGClass omtgClass) {

		ddl.appendCreateSpatialIndex(omtgClass.getName());
	}

	public void createTable(OMTGClass omtgClass) {

		ddl.appendCreateTable(omtgClass.getName(),
				omtgClass.getAttributesName(), omtgClass.getAttributesType(),
				omtgClass.getAttributeLength(), omtgClass.getAttributeScale(),
				omtgClass.getKeysName(), omtgClass.getAttributeNotNulls(),
				omtgClass.getAttributeDefault(), omtgClass.getType(),
				omtgClass.getAttributeDomain(), omtgClass.getAttributeSize(),
				omtgClass.hasAttributeWithDomain());

		ddl.createMultivaluedTables(omtgClass.getName(),
				omtgClass.getAttributesName(), omtgClass.getAttributesType(),
				omtgClass.getAttributeLength(), omtgClass.getAttributeScale(),
				omtgClass.getKeysName(), omtgClass.getKeysType(),
				omtgClass.getKeysLength(), omtgClass.getKeysScale(),
				omtgClass.getAttributeSize());

		if (omtgClass.isSpatial() && !omtgClass.isTesselation()) {
//			createSpatialClassConstraint(omtgClass);
			//createInsertIntoUserSdoGeomMetadata(omtgClass);
			createSpatialIndex(omtgClass);
		}
	}

	public void createTableFromRelationship(OMTGClass omtgClassM,
			OMTGClass omtgClassN) {

		ddl.appendCreateTable(
				omtgClassM.getName() + "_" + omtgClassN.getName(),
				omtgClassM.getName(), omtgClassN.getName(),
				omtgClassM.getKeysName(), omtgClassM.getKeysType(),
				omtgClassM.getAttributeLength(),
				omtgClassM.getAttributeScale(), omtgClassN.getKeysName(),
				omtgClassN.getKeysType(), omtgClassN.getAttributeLength(),
				omtgClassN.getAttributeScale());
	}

	private void createTopologicalRelationshipConstraint(
			OMTGTopologicalRelationship rel, OMTGClass omtgClassA,
			OMTGClass omtgClassB) {

		if (rel.getSpatialRelation().size() == 1
				&& rel.getSpatialRelation().get(0).equalsIgnoreCase("near")) {

			onLineConstraints.appendTopologicalRelationshipNearConstraint(
					omtgClassA.getName(), omtgClassB.getName(),
					omtgClassB.getKeysName(), rel.getDistance(), rel.getUnit());
		
		} else if (rel.getSpatialRelation().size() == 1
				&& rel.getSpatialRelation().get(0).equalsIgnoreCase("distant")) {
			
			onLineConstraints.appendTopologicalRelationshipDistantConstraint(
					omtgClassA.getName(), omtgClassB.getName(),
					omtgClassB.getKeysName(), rel.getDistance(), rel.getUnit());
		}
		else {
			onLineConstraints.appendTopologicalRelationshipConstraint(
					omtgClassA.getName(), omtgClassB.getName(),
					omtgClassB.getKeysName(), rel.getSpatialRelation());
		}
	}

//	private void createUserRestrictionConstraint(OMTGUserRestriction rel,
//			OMTGClass omtgClassA, OMTGClass omtgClassB) {
//
//		if (rel.getSpatialRelation().size() == 1
//				&& rel.getSpatialRelation().get(0).equalsIgnoreCase("near")) {
//
//			onLineConstraints.appendUserRestrictionNearConstraint(
//					omtgClassA.getName(), omtgClassB.getName(),
//					omtgClassB.getKeysName(), rel.getDistance(), rel.getUnit(),
//					rel.isSpatialRelationCanOccur());
//		} 
//		else if (rel.getSpatialRelation().size() == 1
//				&& rel.getSpatialRelation().get(0).equalsIgnoreCase("distant")) {
//
//			onLineConstraints.appendUserRestrictionDistantConstraint(
//					omtgClassA.getName(), omtgClassB.getName(),
//					omtgClassB.getKeysName(), rel.getDistance(), rel.getUnit(),
//					rel.isSpatialRelationCanOccur());
//		}
//		else {
//
//			onLineConstraints.appendUserRestrictionConstraint(
//					omtgClassA.getName(), omtgClassB.getName(),
//					omtgClassB.getKeysName(), rel.getSpatialRelation(),
//					rel.isSpatialRelationCanOccur());
//		}
//	}

//	private void createSpatialClassConstraint(OMTGClass omtgClass) {
//
//		if (omtgClass.isIsoline()) {
//			ddl.createSpatialErrorTable();
//			offLineConstraints.appendIsolineConstraint(omtgClass.getName(),
//					omtgClass.getKeysName());
//		} else if (omtgClass.isPlanarSubdivision()) {
//			ddl.createSpatialErrorTable();
//			offLineConstraints.appendPlanarSubdivisionConstraint(
//					omtgClass.getName(), omtgClass.getKeysName());
//		} else if (omtgClass.isTIN()) {
//			ddl.createSpatialErrorTable();
//			offLineConstraints.appendTINConstraint(omtgClass.getName(),
//					omtgClass.getKeysName());
//		}
//	}

	private void createSpatialAggregationConstraint(OMTGRelationship omtgRel,
			OMTGClass omtgClassWhole, OMTGClass omtgClassPart) {

//		ddl.createSpatialErrorTable();
//		ddl.createSaAuxTable();
//		ddl.appendInsertIntoUserSdoGeomMetadata("Sa_aux", null, "p_geom");
//		ddl.appendCreateSpatialIndex("Sa_aux");
//		offLineConstraints.appendJoinGeometryFunction();
		offLineConstraints.appendSpatialAggregationConstraint(
				omtgClassWhole.getName(), omtgClassWhole.getKeysName(),
				omtgClassPart.getName(), omtgClassPart.getKeysName());
	}

//	private void createTINConstraint(OMTGRelationship omtgRel,
//			OMTGClass omtgClass) {
//
//		ddl.createSpatialErrorTable();
//		offLineConstraints.appendTINConstraint(omtgClass.getName(),
//				omtgClass.getKeysName());
//	}

	private void createNetworkConstraint(OMTGRelationship omtgRel,
			OMTGClass omtgArc, OMTGClass omtgNode) {

//		ddl.createSpatialErrorTable();
//		offLineConstraints.appendGetPointFunction();
		offLineConstraints.appendNetworkConstraint(omtgArc.getName(),
				omtgArc.getKeysName(), omtgNode.getName(),
				omtgNode.getKeysName());
	}
	
	private void createNetworkConstraint(OMTGRelationship omtgRel,
			OMTGClass omtgArc) {

//		ddl.createSpatialErrorTable();
//		offLineConstraints.appendGetPointFunction();
		offLineConstraints.appendNetworkConstraint(omtgArc.getName(),
				omtgArc.getKeysName());
	}

	public void mapClass(OMTGClass omtgClass) {

		createTable(omtgClass);
	}

	public void mapRelationship(OMTGRelationship rel, OMTGClass omtgClass1a,
			OMTGClass omtgClass1b, List<OMTGClass> omtgClass1aList,
			List<OMTGClass> omtgClass1bList) {

		if (omtgClass1aList != null && omtgClass1bList != null) {
			for (OMTGClass omtgClassA : omtgClass1aList) {
				for (OMTGClass omtgClassB : omtgClass1bList) {

					createForeignKeyColumns(rel, omtgClassA, omtgClassB);
					createForeignKeyConstraints(rel, omtgClassA, omtgClassB);
				}
			}
		} else if (omtgClass1aList != null) {

			for (OMTGClass omtgClass : omtgClass1aList) {

				createForeignKeyColumns(rel, omtgClass, omtgClass1b);
				createForeignKeyConstraints(rel, omtgClass, omtgClass1b);
			}
		} else if (omtgClass1bList != null) {

			for (OMTGClass omtgClass : omtgClass1bList) {

				createForeignKeyColumns(rel, omtgClass1a, omtgClass);
				createForeignKeyConstraints(rel, omtgClass1a, omtgClass);
			}
		}

		if (omtgClass1aList == null && omtgClass1bList == null) {

			createForeignKeyColumns(rel, omtgClass1a, omtgClass1b);
			createForeignKeyConstraints(rel, omtgClass1a, omtgClass1b);
		}
	}

	public void mapConventionalRelationship11(OMTGRelationship rel,
			OMTGClass omtgClass1a, OMTGClass omtgClass1b,
			List<OMTGClass> omtgClass1aList, List<OMTGClass> omtgClass1bList) {

		mapRelationship(rel, omtgClass1a, omtgClass1b, omtgClass1aList,
				omtgClass1bList);
	}

	public void mapConventionalRelationship1N(OMTGRelationship rel,
			OMTGClass omtgClass1, OMTGClass omtgClassN,
			List<OMTGClass> omtgClass1List, List<OMTGClass> omtgClassNList) {

		mapRelationship(rel, omtgClass1, omtgClassN, omtgClass1List,
				omtgClassNList);
	}

	public void mapConventionalRelationshipN1(OMTGRelationship rel,
			OMTGClass omtgClassN, OMTGClass omtgClass1,
			List<OMTGClass> omtgClassNList, List<OMTGClass> omtgClass1List) {

		mapRelationship(rel, omtgClass1, omtgClassN, omtgClass1List,
				omtgClassNList);
	}

	public void mapConventionalRelationshipMN(OMTGRelationship rel,
			OMTGClass omtgClassM, OMTGClass omtgClassN,
			List<OMTGClass> omtgClassMList, List<OMTGClass> omtgClassNList) {

		if (omtgClassMList != null && omtgClassNList != null) {
			for (OMTGClass omtgClassA : omtgClassMList) {
				for (OMTGClass omtgClassB : omtgClassNList) {

					createTableFromRelationship(omtgClassA, omtgClassB);
					createForeignKeyConstraintsNN(rel, omtgClassA, omtgClassB);
				}
			}
		} else if (omtgClassMList != null) {

			for (OMTGClass omtgClass : omtgClassMList) {

				createTableFromRelationship(omtgClass, omtgClassN);
				createForeignKeyConstraintsNN(rel, omtgClass, omtgClassN);
			}
		} else if (omtgClassNList != null) {

			for (OMTGClass omtgClass : omtgClassNList) {

				createTableFromRelationship(omtgClassM, omtgClass);
				createForeignKeyConstraintsNN(rel, omtgClassM, omtgClass);
			}
		}

		if (omtgClassMList == null && omtgClassNList == null) {

			createTableFromRelationship(omtgClassM, omtgClassN);
			createForeignKeyConstraintsNN(rel, omtgClassM, omtgClassN);
		}
	}

	public void mapTopologicalRelationship(OMTGTopologicalRelationship rel,
			OMTGClass omtgClassA, OMTGClass omtgClassB,
			List<OMTGClass> omtgClassAList, List<OMTGClass> omtgClassBList) {

		if (omtgClassAList != null && omtgClassBList != null) {
			for (OMTGClass omtgClassAA : omtgClassAList) {
				for (OMTGClass omtgClassBB : omtgClassBList) {

					createTopologicalRelationshipConstraint(rel, omtgClassAA,
							omtgClassBB);
				}
			}
		} else if (omtgClassAList != null) {

			for (OMTGClass omtgClass : omtgClassAList) {

				createTopologicalRelationshipConstraint(rel, omtgClass,
						omtgClassB);
			}
		} else if (omtgClassBList != null) {

			for (OMTGClass omtgClass : omtgClassBList) {

				createTopologicalRelationshipConstraint(rel, omtgClassA,
						omtgClass);
			}
		}

		if (omtgClassAList == null && omtgClassBList == null) {

			createTopologicalRelationshipConstraint(rel, omtgClassA, omtgClassB);
		}
	}

//	public void mapUserRestriction(OMTGUserRestriction rel,
//			OMTGClass omtgClassA, OMTGClass omtgClassB,
//			List<OMTGClass> omtgClassAList, List<OMTGClass> omtgClassBList) {
//
//		if (omtgClassAList != null && omtgClassBList != null) {
//			for (OMTGClass omtgClassAA : omtgClassAList) {
//				for (OMTGClass omtgClassBB : omtgClassBList) {
//
//					createUserRestrictionConstraint(rel, omtgClassAA,
//							omtgClassBB);
//				}
//			}
//		} else if (omtgClassAList != null) {
//
//			for (OMTGClass omtgClass : omtgClassAList) {
//
//				createUserRestrictionConstraint(rel, omtgClass, omtgClassB);
//			}
//		} else if (omtgClassBList != null) {
//
//			for (OMTGClass omtgClass : omtgClassBList) {
//
//				createUserRestrictionConstraint(rel, omtgClassA, omtgClass);
//			}
//		}
//
//		if (omtgClassAList == null && omtgClassBList == null) {
//
//			createUserRestrictionConstraint(rel, omtgClassA, omtgClassB);
//		}
//	}

	public void mapConventionalAggregation(OMTGRelationship rel,
			OMTGClass omtgClass1, OMTGClass omtgClassN,
			List<OMTGClass> omtgClass1List, List<OMTGClass> omtgClassNList) {

		mapRelationship(rel, omtgClass1, omtgClassN, omtgClass1List,
				omtgClassNList);
	}

	public void mapSpatialAggregation(OMTGRelationship rel,
			OMTGClass omtgClassWhole, OMTGClass omtgClassPart,
			List<OMTGClass> omtgClassWholeList,
			List<OMTGClass> omtgClassPartList) {

		if (omtgClassWholeList != null && omtgClassPartList != null) {
			for (OMTGClass omtgClassA : omtgClassWholeList) {
				for (OMTGClass omtgClassB : omtgClassPartList) {

					createSpatialAggregationConstraint(rel, omtgClassA,
							omtgClassB);
				}
			}
		} else if (omtgClassWholeList != null) {

			for (OMTGClass omtgClass : omtgClassWholeList) {

				createSpatialAggregationConstraint(rel, omtgClass,
						omtgClassPart);
			}
		} else if (omtgClassPartList != null) {

			for (OMTGClass omtgClass : omtgClassPartList) {

				createSpatialAggregationConstraint(rel, omtgClassWhole,
						omtgClass);
			}
		}

		if (omtgClassWholeList == null && omtgClassPartList == null) {

			createSpatialAggregationConstraint(rel, omtgClassWhole,
					omtgClassPart);
		}
	}

//	public void mapTIN(OMTGRelationship omtgRel, OMTGClass omtgClass) {
//
//		createTINConstraint(omtgRel, omtgClass);
//	}

	public void mapNetwork(OMTGRelationship omtgRel, OMTGClass omtgArc,
			OMTGClass omtgNode, List<OMTGClass> omtgArcList,
			List<OMTGClass> omtgNodeList) {

		createNetworkConstraint(omtgRel, omtgArc, omtgNode);
	}
	
	public void mapNetwork(OMTGRelationship omtgRel, OMTGClass omtgArc, List<OMTGClass> omtgArcList) {

		createNetworkConstraint(omtgRel, omtgArc);
	}


	public void mapGeneralizationTotal(OMTGGeneralization omtgRel,
			OMTGClass superClass, List<OMTGClass> subClasses)
			throws CloneNotSupportedException {

		for (OMTGClass omtgSubClass : subClasses) {

			// List<OMTGAttribute> newAttributes =
			// superClass.getKeysAttribute();
			List<OMTGAttribute> newAttributes = superClass
					.getAttributesWithPrefix(superClass.getName());

			// OMTGClass subClassAux = (OMTGClass)omtgSubClass.clone();
			// join superclass and subclass attributes to subClassAux
			newAttributes.addAll(omtgSubClass.getAttributes());
			omtgSubClass.setAttributes(newAttributes);

			mapClass(omtgSubClass);
		}
	}

	public void mapGeneralizationPartial(OMTGGeneralization omtgRel,
			OMTGClass superClass, List<OMTGClass> subClasses)
			throws CloneNotSupportedException {

		mapClass(superClass);

		for (OMTGClass subClass : subClasses) {

			mapClass(subClass);
			createForeignKeyColumns(omtgRel, superClass, subClass);
			createForeignKeyConstraints(omtgRel, superClass, subClass);
		}
	}

//	private void createDisjointConstraint(OMTGGeneralization omtgRel,
//			OMTGClass superClass, List<OMTGClass> subClasses) {
//
//		for (int i = 0; i < subClasses.size(); i++) {
//
//			OMTGClass subClass = subClasses.get(i);
//			onLineConstraints.appendDisjointConstraint(subClass.getName(),
//					subClass.getKeysName(), omtgRel.getSubclasses());
//		}
//	}

//	private void createDisjointConstraintWithPartial(
//			OMTGGeneralization omtgRel, OMTGClass superClass,
//			List<OMTGClass> subClasses) {
//
//		for (int i = 0; i < subClasses.size(); i++) {
//
//			OMTGClass subClass = subClasses.get(i);
////			onLineConstraints.appendDisjointConstraintWithPartial(
////					subClass.getName(), superClass.getKeysName(),
////					omtgRel.getSubclasses(), superClass.getName());
//		}
//	}

//	private void createPartialConstraint(
//			OMTGConventionalGeneralization omtgRel, OMTGClass superClass,
//			List<OMTGClass> subClasses) {
//
//		onLineConstraints.appendPartialConstraint(superClass.getName(),
//				superClass.getKeysName(), omtgRel.getSubclasses());
//	}

	public void mapConventionalGeneralizationTotalDisjoint(
			OMTGConventionalGeneralization omtgRel, OMTGClass superClass,
			List<OMTGClass> subClasses) throws CloneNotSupportedException {

		mapGeneralizationTotal(omtgRel, superClass, subClasses);
		//createDisjointConstraint(omtgRel, superClass, subClasses);
	}

	public void mapConventionalGeneralizationTotalOverlap(
			OMTGConventionalGeneralization omtgRel, OMTGClass superClass,
			List<OMTGClass> subClasses) throws CloneNotSupportedException {

		mapGeneralizationTotal(omtgRel, superClass, subClasses);
	}

	public void mapConventionalGeneralizationPartialDisjoint(
			OMTGConventionalGeneralization omtgRel, OMTGClass superClass,
			List<OMTGClass> subClasses) throws CloneNotSupportedException {

		mapGeneralizationPartial(omtgRel, superClass, subClasses);
		//createDisjointConstraintWithPartial(omtgRel, superClass, subClasses);
		// createPartialConstraint(omtgRel, superClass, subClasses);
	}

	public void mapConventionalGeneralizationPartialOverlap(
			OMTGConventionalGeneralization omtgRel, OMTGClass superClass,
			List<OMTGClass> subClasses) throws CloneNotSupportedException {

		mapGeneralizationPartial(omtgRel, superClass, subClasses);
		// createPartialConstraint(omtgRel, superClass, subClasses);
	}

	public void mapConceptualGeneralizationDisjoint(
			OMTGConceptualGeneralization omtgRel, OMTGClass superClass,
			List<OMTGClass> subClasses) throws CloneNotSupportedException {

		mapGeneralizationTotal(omtgRel, superClass, subClasses);
		//createDisjointConstraint(omtgRel, superClass, subClasses);
	}

	public void mapConceptualGeneralizationOverlap(
			OMTGConceptualGeneralization omtgRel, OMTGClass superClass,
			List<OMTGClass> subClasses) throws CloneNotSupportedException {

		mapGeneralizationTotal(omtgRel, superClass, subClasses);
	}

	public void close() {
		try {
			ddl.close();
			offLineConstraints.close();
			onLineConstraints.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
import java.io.StringWriter;
import java.util.List;
import com.omtg2sql.omtg.classes.OMTGCardinality;
import com.omtg2sql.omtg.classes.OMTGClass;
import com.omtg2sql.omtg.model.OMTGSchema;
import com.omtg2sql.omtg.relationships.OMTGConceptualGeneralization;
import com.omtg2sql.omtg.relationships.OMTGConventionalGeneralization;
import com.omtg2sql.omtg.relationships.OMTGConventionalRelationship;
import com.omtg2sql.omtg.relationships.OMTGGeneralization;
import com.omtg2sql.omtg.relationships.OMTGRelationship;
import com.omtg2sql.omtg.relationships.OMTGTopologicalRelationship;
import com.omtg2sql.sql.postgis.PostgisGenerator;

package com.omtg2sql.core;


//import com.omtg2sql.omtg.relationships.OMTGUserRestriction;



public class OMTG2Postgis {

	private OMTGSchema omtSchema;
	private PostgisGenerator postgisGenerator;

	public OMTG2Postgis(OMTGSchema omtgSchema, String xmlDocName) {
		this.omtSchema = omtgSchema;
		xmlDocName = xmlDocName.replace(".xml", "");
		this.postgisGenerator = new PostgisGenerator("./"+xmlDocName+"-ddl-structures.sql", "./"+xmlDocName+"-static-control.sql", 
		"./"+xmlDocName+"-dynamic-control.sql");
	}
	
	public OMTG2Postgis(OMTGSchema omtgSchema, StringWriter ddlSW, StringWriter staticSW, StringWriter dynamicSW) {
		this.omtSchema = omtgSchema;
		this.postgisGenerator = new PostgisGenerator(ddlSW, staticSW, dynamicSW);
	}

	public void mapOMTGSchemaToPostgis() throws CloneNotSupportedException {

		// map all classes not in generalization
		for (OMTGClass omtgClass : omtSchema.getClassesNotInGeneralization()) {
			postgisGenerator.mapClass(omtgClass);
		}

		//generalization
		for (OMTGRelationship omtgRel : omtSchema.getRelationships()) {

			if (omtgRel.typeEquals("conventional-generalization")) {
				OMTGClass superClass = omtSchema.getClass(omtgRel.getClass1());
				List<OMTGClass> subClasses = omtSchema.getSubClasses((OMTGGeneralization)omtgRel);
				if (((OMTGConventionalGeneralization)omtgRel).isTotal()) {
					if (((OMTGConventionalGeneralization)omtgRel).isDisjoint()) {
						postgisGenerator.mapConventionalGeneralizationTotalDisjoint((OMTGConventionalGeneralization)omtgRel, superClass, subClasses);
					}
					else {
						postgisGenerator.mapConventionalGeneralizationTotalOverlap((OMTGConventionalGeneralization)omtgRel, superClass, subClasses);
					}
				}
				else {
					if (((OMTGConventionalGeneralization)omtgRel).isDisjoint()) {
						postgisGenerator.mapConventionalGeneralizationPartialDisjoint((OMTGConventionalGeneralization)omtgRel, superClass, subClasses);
					}
					else {
						postgisGenerator.mapConventionalGeneralizationPartialOverlap((OMTGConventionalGeneralization)omtgRel, superClass, subClasses);
					}
				}
			}

			else if (omtgRel.typeEquals("conceptual-generalization")) {

				OMTGClass superClass = omtSchema.getClass(omtgRel.getClass1());
				List<OMTGClass> subClasses = omtSchema.getSubClasses((OMTGGeneralization)omtgRel);

				if (((OMTGConceptualGeneralization)omtgRel).isDisjoint()) {
					postgisGenerator.mapConceptualGeneralizationDisjoint((OMTGConceptualGeneralization)omtgRel, superClass, subClasses);
				}
				else {
					postgisGenerator.mapConceptualGeneralizationOverlap((OMTGConceptualGeneralization)omtgRel, superClass, subClasses);
				}
			}
		}

		List<OMTGClass> omtgSuperClasses = omtSchema.getSuperClassesOfTotalGeneralization();

		//map other relationships
		for (OMTGRelationship omtgRel : omtSchema.getRelationshipsWithoutGeneralization()) {

			OMTGClass omtgClassA = omtSchema.getClass(omtgRel.getClass1());
			OMTGClass omtgClassB = omtSchema.getClass(omtgRel.getClass2());
			boolean omtgClassesIsTesselation = omtgClassA.isTesselation() || omtgClassB.isTesselation();
			
			List<OMTGClass> omtgClassAList = null;
			if (omtgSuperClasses.contains(omtgClassA)) {
				omtgClassAList = omtSchema.getSubClasses(omtgClassA);
			}
			List<OMTGClass> omtgClassBList = null;
			if (omtgSuperClasses.contains(omtgClassB)) {
				omtgClassBList = omtSchema.getSubClasses(omtgClassB);
			}

			if (omtgRel.typeEquals("conventional-relationship")) {

				if (((OMTGConventionalRelationship)omtgRel).cardinalityIsEqual(OMTGCardinality.ONE_TO_ONE)) {
//					System.out.println("one_to_one");
					postgisGenerator.mapConventionalRelationship11(omtgRel, omtgClassA, omtgClassB, omtgClassAList, omtgClassBList);
				}
				else if (((OMTGConventionalRelationship)omtgRel).cardinalityIsEqual(OMTGCardinality.ONE_TO_MANY)) {
//					System.out.println("one_to_many");
					postgisGenerator.mapConventionalRelationship1N(omtgRel, omtgClassA, omtgClassB, omtgClassAList, omtgClassBList);
				}
				else if (((OMTGConventionalRelationship)omtgRel).cardinalityIsEqual(OMTGCardinality.MANY_TO_ONE)) {
//					System.out.println("many_to_one");
					postgisGenerator.mapConventionalRelationshipN1(omtgRel, omtgClassA, omtgClassB, omtgClassAList, omtgClassBList);
				}
				// Relationship is Many to Many
				else {
//					System.out.println("many_to_many");
					postgisGenerator.mapConventionalRelationshipMN(omtgRel, omtgClassA, omtgClassB, omtgClassAList, omtgClassBList);
				}
			}
			else if (omtgRel.typeEquals("topological-relationship") && !omtgClassesIsTesselation) {


				postgisGenerator.mapTopologicalRelationship((OMTGTopologicalRelationship)omtgRel, omtgClassA, omtgClassB, omtgClassAList, omtgClassBList);
