import utest.Assert;
import utest.Test;
import model.Relation;
import model.Diagram;
import model.MLD;
import model.Field;
import model.ForeignKey;
import transform.MLDToDiagram;

class TestMLDToMCD extends Test {
	function getLen(iterator : Iterator<Dynamic>) : Int {
		var n : Int = 0;
		for (o in iterator) n++;
		return n;
	}
	
	function buildRelation(name : String, fields : Array<Field>, key : Array<String>, foreignKeys : Array<ForeignKey>) : Relation {
		var r = new Relation(name);
		r.key = key;
		r.foreignKeys = foreignKeys;
		r.fields = fields;
		return r;
	}

	public function test01_NoAssoc() {
		var mld = new MLD();
		var r1 = buildRelation("R1", [new Field("idR1", ""),new Field("r1F1", "")],["idR1"], []);
		mld.relations.set(r1.name, r1);
		var mcd = MLDToDiagram.transform(mld);
		Assert.equals(1, Lambda.count(mcd.sets));
		var e1 = mcd.sets.get("R1");
		Assert.equals(2, e1.fields.length);
		Assert.equals(1, e1.id.length);
		Assert.equals("idR1", e1.id[0]);
	}
	
	public function test01_xKeysNoAssoc() {
		var mld = new MLD();
		var r1 = buildRelation("R1", [new Field("idR1", ""),new Field("idR1bis", ""),new Field("r1F1", "")],["idR1","idR1bis"], []);
		mld.relations.set(r1.name, r1);
		var mcd = MLDToDiagram.transform(mld);
		Assert.equals(1, Lambda.count(mcd.sets));
		var e1 = mcd.sets.get("R1");
		Assert.equals(3, e1.fields.length);
		Assert.equals(2, e1.id.length);
		Assert.equals("idR1", e1.id[0]);
		Assert.equals("idR1bis", e1.id[1]);
	}
	
	public function test02_Assoc1() {
		var mld = new MLD();
		var r1 = buildRelation("R1", [new Field("idR1", ""),new Field("r1F1", "")],["idR1"], []);
		mld.relations.set(r1.name, r1);
		var r2 = buildRelation("R2", [new Field("idR2", ""),new Field("r2F1", ""),new Field("idR1", "")], ["idR2"], [{name:"idR1",relation:r1,key:"idR1"}]);
		mld.relations.set(r2.name, r2);
		var mcd = MLDToDiagram.transform(mld);
		Assert.equals(2, Lambda.count(mcd.sets));
		var e1 = mcd.sets.get("R1");
		Assert.equals(2, e1.fields.length);
		var e2 = mcd.sets.get("R2");
		Assert.equals(2, e2.fields.length);
		Assert.equals(1, Lambda.count(mcd.associations));
		var a = mcd.associations.get("R2R1");
		Assert.equals(2, a.links.length);
		Assert.equals("R2", a.links[0].set.name);
		Assert.equals("1", a.links[0].max);
		Assert.equals("R1", a.links[1].set.name);
		Assert.equals("N", a.links[1].max);
	}

	public function test02_Assoc1xkeys() {
		var mld = new MLD();
		var r1 = buildRelation("R1", [new Field("idR1", ""),new Field("idR1bis", ""),new Field("r1F1", "")],["idR1", "idR1Bis"], []);
		mld.relations.set(r1.name, r1);
		var r2 = buildRelation("R2", [new Field("idR2", ""),new Field("r2F1", ""),new Field("idR1", ""),new Field("idR1bis", "")], ["idR2"], 
			[{name:"idR1",relation:r1,key:"idR1"},{name:"idR1bis",relation:r1,key:"idR1bis"}]);
		mld.relations.set(r2.name, r2);
		var mcd = MLDToDiagram.transform(mld);
		Assert.equals(2, Lambda.count(mcd.sets));
		var e1 = mcd.sets.get("R1");
		Assert.equals(3, e1.fields.length);
		var e2 = mcd.sets.get("R2");
		Assert.equals(2, e2.fields.length);
		Assert.equals(1, Lambda.count(mcd.associations));
		var a = mcd.associations.get("R2R1");
		Assert.equals(2, a.links.length);
		Assert.equals("R2", a.links[0].set.name);
		Assert.equals("1", a.links[0].max);
		Assert.equals("R1", a.links[1].set.name);
		Assert.equals("N", a.links[1].max);
	}

	public function test03_AssocNN() { //with field
		var mld = new MLD();
		var r1 = buildRelation("R1", [new Field("idR1", ""),new Field("r1F1", "")],["idR1"], []);
		mld.relations.set(r1.name, r1);
		var r2 = buildRelation("R2", [new Field("idR2", ""),new Field("r2F1", "")], ["idR2"], []);
		mld.relations.set(r2.name, r2);
		var r3 = buildRelation("R3", [new Field("idR1", ""),new Field("idR2", ""),new Field("r3F1", "")], ["idR1","idR2"], 
			[{name:"idR1",relation:r1,key:"idR1"},{name:"idR2",relation:r2,key:"idR2"}]);
		mld.relations.set(r3.name, r3);
		var mcd = MLDToDiagram.transform(mld);
		Assert.equals(2, Lambda.count(mcd.sets));
		var e1 = mcd.sets.get("R1");
		Assert.equals(2, e1.fields.length);
		var e2 = mcd.sets.get("R2");
		Assert.equals(2, e2.fields.length);
		Assert.equals(1, Lambda.count(mcd.associations));
		var a = mcd.associations.get("R3");
		Assert.equals(2, a.links.length);
		Assert.equals(1, a.fields.length);
		Assert.equals("r3F1", a.fields[0].name);
		Assert.equals("R1", a.links[0].set.name);
		Assert.equals("N", a.links[0].max);
		Assert.equals("R2", a.links[1].set.name);
		Assert.equals("N", a.links[1].max);
	}

	public function test03_AssocNNxKeys() {
		var mld = new MLD();
		var r1 = buildRelation("R1", [new Field("idR1", ""),new Field("idR1bis", ""),new Field("r1F1", "")],["idR1","idR1bis"], []);
		mld.relations.set(r1.name, r1);
		var r2 = buildRelation("R2", [new Field("idR2", ""),new Field("idR2bis", ""),new Field("r2F1", "")], ["idR2","idR2bis"], []);
		mld.relations.set(r2.name, r2);
		var r3 = buildRelation("R3", [new Field("idR1", ""),new Field("idR1bis", ""),new Field("idR2", ""),new Field("idR2bis", "")], 
			["idR1","idR1bis","idR2","idR2bis"], 
			[{name:"idR1",relation:r1,key:"idR1"},{name:"idR1bis",relation:r1,key:"idR1bis"},
			{name:"idR2",relation:r2,key:"idR2"},{name:"idR2bis",relation:r2,key:"idR2bis"}]);
		mld.relations.set(r3.name, r3);
		var mcd = MLDToDiagram.transform(mld);
		Assert.equals(2, Lambda.count(mcd.sets));
		Assert.equals(1, Lambda.count(mcd.associations));
		var a = mcd.associations.get("R3");
		Assert.equals(2, a.links.length);
		Assert.equals("R1", a.links[0].set.name);
		Assert.equals("N", a.links[0].max);
		Assert.equals("R2", a.links[1].set.name);
		Assert.equals("N", a.links[1].max);
	}

	public function test03_TernaryAssoc() {
		var mld = new MLD();
		var r1 = buildRelation("R1", [new Field("idR1", ""),new Field("r1F1", "")],["idR1"], []);
		mld.relations.set(r1.name, r1);
		var r2 = buildRelation("R2", [new Field("idR2", ""),new Field("r2F1", "")], ["idR2"], []);
		mld.relations.set(r2.name, r2);
		var r3 = buildRelation("R3", [new Field("idR3", ""),new Field("r3F1", "")], ["idR3"], []);
		mld.relations.set(r3.name, r3);
		var r4 = buildRelation("R4", [new Field("idR1", ""),new Field("idR2", ""),new Field("idR3", "")], ["idR1","idR2","idR3"], 
			[{name:"idR1",relation:r1,key:"idR1"},{name:"idR2",relation:r2,key:"idR2"},{name:"idR3",relation:r3,key:"idR3"}]);
		mld.relations.set(r4.name, r4);
		var mcd = MLDToDiagram.transform(mld);
		Assert.equals(3, Lambda.count(mcd.sets));
		Assert.equals(1, Lambda.count(mcd.associations));
		var a = mcd.associations.get("R4");
		Assert.equals(3, a.links.length);
		Assert.equals(0, a.fields.length);
		Assert.equals("R1", a.links[0].set.name);
		Assert.equals("N", a.links[0].max);
		Assert.equals("R2", a.links[1].set.name);
		Assert.equals("N", a.links[1].max);
		Assert.equals("R3", a.links[2].set.name);
		Assert.equals("N", a.links[2].max);
	}

	public function test04_ReflexiveAssoc1() {
		var mld = new MLD();
		var r1 = new Relation("R1");
		r1.key = ["idR1"];
		r1.foreignKeys = [{name:"idR1FK",relation:r1,key:"idR1"}];
		r1.fields = [new Field("idR1", ""),new Field("r1F1", ""),new Field("idR1FK", "")];
		mld.relations.set(r1.name, r1);
		var mcd = MLDToDiagram.transform(mld);
		Assert.equals(1, Lambda.count(mcd.sets));
		Assert.equals(1, Lambda.count(mcd.associations));
		var a = mcd.associations.get("R1R1");
		Assert.equals(2, a.links.length);
		Assert.equals("R1", a.links[0].set.name);
		Assert.equals("1", a.links[0].max);
		Assert.equals("R1", a.links[1].set.name);
		Assert.equals("N", a.links[1].max);
	}

	public function test04_ReflexiveAssocNN() {
		var mld = new MLD();
		var r1 = buildRelation("R1", [new Field("idR1", ""),new Field("r1F1", "")],["idR1"], []);
		mld.relations.set(r1.name, r1);
		var r2 = buildRelation("R2", [new Field("idR11", ""),new Field("idR12", "")],["idR11","idR12"], 
			[{name:"idR11",relation:r1,key:"idR1"},{name:"idR12",relation:r1,key:"idR1"}]);
		mld.relations.set(r2.name, r2);
		var mcd = MLDToDiagram.transform(mld);
		Assert.equals(1, Lambda.count(mcd.sets));
		Assert.equals(1, Lambda.count(mcd.associations));
		var a = mcd.associations.get("R2");
		Assert.equals(2, a.links.length);
		Assert.equals("R1", a.links[0].set.name);
		Assert.equals("N", a.links[0].max);
		Assert.equals("R1", a.links[1].set.name);
		Assert.equals("N", a.links[1].max);
	}

	public function test04_ReflexiveAssocNNxKeys() {
		var mld = new MLD();
		var r1 = buildRelation("R1", [new Field("idR1", ""),new Field("idR1bis", ""),new Field("r1F1", "")],["idR1","idR1bis"], []);
		mld.relations.set(r1.name, r1);
		var r2 = buildRelation("R2", [new Field("idR11", ""),new Field("idR1bis1", ""),new Field("idR12", ""),new Field("idR1bis2", "")],
			["idR11","idR1bis1","idR12","idR1bis2"], [{name:"idR11",relation:r1,key:"idR1"},{name:"idR1bis1",relation:r1,key:"idR1bis"},
			{name:"idR12",relation:r1,key:"idR1"}, {name:"idR1bis2",relation:r1,key:"idR1bis"}]);
		mld.relations.set(r2.name, r2);
		var mcd = MLDToDiagram.transform(mld);
		Assert.equals(1, Lambda.count(mcd.sets));
		Assert.equals(1, Lambda.count(mcd.associations));
		var a = mcd.associations.get("R2");
		Assert.equals(2, a.links.length);
	}

	public function test05_Subclass() {
		var mld = new MLD();
		var r1 = buildRelation("R1", [new Field("idR1", ""),new Field("r1F1", "")],["idR1"], []);
		mld.relations.set(r1.name, r1);
		var r2 = buildRelation("R2", [new Field("idR1", ""),new Field("r2F1", "")], ["idR1"], [{name:"idR1",relation:r1,key:"idR1"}]);
		mld.relations.set(r2.name, r2);
		var mcd = MLDToDiagram.transform(mld);
		Assert.equals(2, Lambda.count(mcd.sets));
		Assert.equals(0, Lambda.count(mcd.associations));
		var e1 = mcd.sets.get("R1");
		var e2 = mcd.sets.get("R2");
		Assert.equals(1, e1.subsets.length);
		Assert.equals("R2", e1.subsets[0].name);
		Assert.equals(0, e2.subsets.length);
		Assert.equals("R1", e2.superset.name);
		Assert.equals(0, e2.id.length);
	}

	public function test05_xKeysSubclass() {
		var mld = new MLD();
		var r1 = buildRelation("R1", [new Field("idR1", ""),new Field("idR1bis", ""),new Field("r1F1", "")],["idR1","idR1bis"], []);
		mld.relations.set(r1.name, r1);
		var r2 = buildRelation("R2", [new Field("idR1", ""),new Field("idR1bis", ""),new Field("r2F1", "")],
			["idR1","idR1bis"], [{name:"idR1",relation:r1,key:"idR1"},{name:"idR1bis",relation:r1,key:"idR1bis"}]);
		mld.relations.set(r2.name, r2);
		var mcd = MLDToDiagram.transform(mld);
		Assert.equals(2, Lambda.count(mcd.sets));
		Assert.equals(0, Lambda.count(mcd.associations));
		var e2 = mcd.sets.get("R2");
		Assert.equals(0, e2.subsets.length);
		Assert.equals("R1", e2.superset.name);
		Assert.equals(0, e2.id.length);
	}
	
	public function test05_SubclassAssoc() {
		var mld = new MLD();
		var r1 = buildRelation("R1", [new Field("idR1", ""),new Field("r1F1", "")],["idR1"], []);
		mld.relations.set(r1.name, r1);
		var r2 = buildRelation("R2", [new Field("idR1", ""),new Field("r2F1", "")], ["idR1"], [{name:"idR1",relation:r1,key:"idR1"}]);
		mld.relations.set(r2.name, r2);
		var r3 = buildRelation("R3", [new Field("idR3", ""),new Field("idR1", ""),new Field("r3F1", "")],
			["idR3"], [{name:"idR1",relation:r2,key:"idR1"}]);
		mld.relations.set(r3.name, r3);
		var mcd = MLDToDiagram.transform(mld);
		Assert.equals(3, Lambda.count(mcd.sets));
		Assert.equals(1, Lambda.count(mcd.associations));
		var e3 = mcd.sets.get("R3");
		var a = mcd.associations.get("R3R2");
		Assert.equals(2, e3.fields.length);
		Assert.equals(2, a.links.length);
		Assert.equals("R3", a.links[0].set.name);
		Assert.equals("1", a.links[0].max);
		Assert.equals("R2", a.links[1].set.name);
		Assert.equals("N", a.links[1].max);
	}

	public function test06_Compound() {
		var mld = new MLD();
		var r1 = buildRelation("R1", [new Field("idR1", ""),new Field("r1F1", "")],["idR1"], []);
		mld.relations.set(r1.name, r1);
		var r2 = buildRelation("R2", [new Field("idR1", ""),new Field("idR2", ""),new Field("r2F1", "")], ["idR1","idR2"], [{name:"idR1",relation:r1,key:"idR1"}]);
		mld.relations.set(r2.name, r2);
		var mcd = MLDToDiagram.transform(mld);
		Assert.equals(2, Lambda.count(mcd.sets));
		Assert.equals(1, Lambda.count(mcd.associations));
		var a = mcd.associations.get("R2R1");
		Assert.isTrue(a.links[0].isWeak);
		var e1 = mcd.sets.get("R1");
		Assert.equals(null, e1.compound);
		var e2 = mcd.sets.get("R2");
		Assert.equals(2, e2.fields.length);
		Assert.equals(1, e2.id.length);
		Assert.equals("idR2", e2.id[0]);
		Assert.equals("R1", e2.compound.name);
	}

	public function test06_CompoundAssoc() {
		var mld = new MLD();
		var r1 = buildRelation("R1", [new Field("idR1", ""),new Field("r1F1", "")],["idR1"], []);
		mld.relations.set(r1.name, r1);
		var r2 = buildRelation("R2", [new Field("idR1", ""),new Field("idR2", ""),new Field("r2F1", "")], ["idR1","idR2"], 
			[{name:"idR1",relation:r1,key:"idR1"}]);
		mld.relations.set(r2.name, r2);
		var r3 = buildRelation("R3", [new Field("idR3", ""),new Field("idR1", ""),new Field("idR2", ""),new Field("r3F1", "")],
			["idR3"], [{name:"idR1",relation:r2,key:"idR1"},{name:"idR2",relation:r2,key:"idR2"}]);
		mld.relations.set(r3.name, r3);
		var mcd = MLDToDiagram.transform(mld);
		Assert.equals(3, Lambda.count(mcd.sets));
		Assert.equals(2, Lambda.count(mcd.associations));
		var a = mcd.associations.get("R3R2");
		var e3 = mcd.sets.get("R3");
		Assert.equals(2, e3.fields.length);
		Assert.equals(1, e3.id.length);
		Assert.equals("R2", a.links[1].set.name);
		Assert.equals("N", a.links[1].max);
	}

	public function test07_Aggregation() {
		var mld = new MLD();
		var r1 = buildRelation("R1", [new Field("idR1", ""),new Field("r1F1", "")],["idR1"], []);
		mld.relations.set(r1.name, r1);
		var r2 = buildRelation("R2", [new Field("idR2", ""),new Field("r2F1", "")], ["idR2"], []);
		mld.relations.set(r2.name, r2);
		var r3 = buildRelation("R3", [new Field("idR1", ""),new Field("idR2", ""),new Field("r3F1", "")], ["idR1","idR2"], 
			[{name:"idR1",relation:r1,key:"idR1"},{name:"idR2",relation:r2,key:"idR2"}]);
		mld.relations.set(r3.name, r3);
		var r4 = buildRelation("R4", [new Field("idR4", ""),new Field("idR1", ""),new Field("idR2", ""),new Field("r4F1", "")],["idR4"], 
			[{name:"idR1",relation:r3,key:"idR1"},{name:"idR2",relation:r3,key:"idR2"}]);
		mld.relations.set(r4.name, r4);
		var mcd = MLDToDiagram.transform(mld);
		Assert.equals(3, Lambda.count(mcd.sets));
		Assert.equals(2, Lambda.count(mcd.associations));
		var e4 = mcd.sets.get("R4");
		Assert.equals(2, e4.fields.length);
		var a = mcd.associations.get("R4R3");
		Assert.equals(2, a.links.length);
		Assert.equals("R4", a.links[0].set.name);
		Assert.equals("1", a.links[0].max);
		Assert.equals("R3", a.links[1].set.name);
		Assert.equals("N", a.links[1].max);
	}
}
