import utest.Assert;
import utest.Test;
import source.Mocodo;
import model.Field;
import transform.DiagramToMLD;

class TestMCDToMLD extends Test {
	//01: no association
	public function test01_NoAssoc_01() {
		var mocodoStr = "Ent1: ent1Id [counter], ent1F1 [varchar(50)]\n";
		var mld = DiagramToMLD.transform(Mocodo.load(mocodoStr));

		Assert.equals(1, Lambda.count(mld.relations));
		var r = mld.relations.get("Ent1");
		Assert.isFalse(r == null);
		Assert.equals(2, r.fields.length);
		Assert.equals("ent1F1", r.fields[1].name);
		Assert.equals("varchar(50)", r.fields[1].type);
		Assert.equals(1, r.key.length);
		Assert.equals("ent1Id", r.key[0]);
	}

	public function test01_NoAssoc_02_TwoIDs() {
		var mocodoStr = "Ent1: ent1Id1, _ent1Id2, ent1F1\n";
		var mld = DiagramToMLD.transform(Mocodo.load(mocodoStr));
		
		var r = mld.relations.get("Ent1");
		Assert.equals(2, r.key.length);
	}

	//02: 1-N association
	public function test02_Assoc1N_01() {
		var mocodoStr = "Ent1: ent1Id, ent1F1\n" +
						"Ent2: ent2Id, ent2F1\n" +
						"REnt1Ent2, 11 Ent1, 0N Ent2\n";
		var mld = DiagramToMLD.transform(Mocodo.load(mocodoStr));

		Assert.equals(2, Lambda.count(mld.relations));
		var r1 = mld.relations.get("Ent1");
		Assert.equals(3, r1.fields.length);
		Assert.equals(1, r1.foreignKeys.length);
		Assert.equals("ent2Id", r1.foreignKeys[0].name);
		Assert.equals("ent2Id", r1.foreignKeys[0].key);
		Assert.equals("Ent2", r1.foreignKeys[0].relation.name);

		var r2 = mld.relations.get("Ent2");
		Assert.equals(2, r2.fields.length);
		Assert.equals(0, r2.foreignKeys.length);
	}

	public function test02_Assoc1N_02_TwoIDs() {
		var mocodoStr = "Ent1: ent1Id1, _ent1Id2, ent1F1\n" +
						"Ent2: ent2Id, ent2F1\n" +
						"REnt1Ent2, 0N Ent1, 11 Ent2\n";
		var mld = DiagramToMLD.transform(Mocodo.load(mocodoStr));

		var r1 = mld.relations.get("Ent1");
		Assert.equals(3, r1.fields.length);
		Assert.equals(0, r1.foreignKeys.length);

		var r2 = mld.relations.get("Ent2");
		Assert.equals(4, r2.fields.length);
		Assert.equals(2, r2.foreignKeys.length);
		Assert.equals("ent1Id1", r2.foreignKeys[0].name);
		Assert.equals("ent1Id2", r2.foreignKeys[1].name);
	}

	public function test02_Assoc1N_03_sameIDs() {
		var mocodoStr = "Ent1: id, ent1F1\n" +
						"Ent2: id, ent2F1\n" +
						"REnt1Ent2, 0N Ent1, 11 Ent2\n";
		var mld = DiagramToMLD.transform(Mocodo.load(mocodoStr));

		var r = mld.relations.get("Ent2");
		Assert.equals("idEnt1", r.foreignKeys[0].name);
		Assert.equals("id", r.foreignKeys[0].key);
		Assert.equals("Ent1", r.foreignKeys[0].relation.name);
	}

	public function test02_Assoc1N_04_role() {
		var mocodoStr = "Ent1: id, ent1F1\n" +
						"Ent2: id, ent2F1\n" +
						"REnt1Ent2, 0N [super_role] Ent1, 11 Ent2\n";
		var mld = DiagramToMLD.transform(Mocodo.load(mocodoStr));

		var r = mld.relations.get("Ent2");
		Assert.equals("super_role", r.foreignKeys[0].name);
		Assert.equals("id", r.foreignKeys[0].key);
		Assert.equals("Ent1", r.foreignKeys[0].relation.name);
	}

	public function test02_Assoc1N_05_TwoSameIDs() {
		var mocodoStr = "Ent1: id, _idBis, ent1F1\n" +
						"Ent2: id, ent2F1\n" +
						"REnt1Ent2, 0N Ent1, 11 Ent2\n";
		var mld = DiagramToMLD.transform(Mocodo.load(mocodoStr));

		var r = mld.relations.get("Ent2");
		Assert.equals("idEnt1", r.foreignKeys[0].name);
		Assert.equals("id", r.foreignKeys[0].key);
		Assert.equals("idBis", r.foreignKeys[1].name);
		Assert.equals("idBis", r.foreignKeys[1].key);
	}

	public function test02_Assoc1N_06_TwoIDsAndRole() {
		var mocodoStr = "Ent1: id1, _id2, ent1F1\n" +
						"Ent2: id1, ent2F1\n" +
						"REnt1Ent2, 0N [super_role] Ent1, 11 Ent2\n";
		var mld = DiagramToMLD.transform(Mocodo.load(mocodoStr));

		var r = mld.relations.get("Ent2");
		Assert.equals("id1_super_role", r.foreignKeys[0].name);
		Assert.equals("id1", r.foreignKeys[0].key);
		Assert.equals("id2_super_role", r.foreignKeys[1].name);
		Assert.equals("id2", r.foreignKeys[1].key);
	}

	//03: reflexive association
	public function test03_Reflexive_01_1N() {
		var mocodoStr = "Ent1: id, ent1F1\n" +
						"REnt1Ent1, 0N Ent1, 11 Ent1\n";
		var mld = DiagramToMLD.transform(Mocodo.load(mocodoStr));

		Assert.equals(1, Lambda.count(mld.relations));
		var r = mld.relations.get("Ent1");
		Assert.equals(3, r.fields.length);
		Assert.equals(1, r.key.length);
		Assert.equals(1, r.foreignKeys.length);
		Assert.equals("idEnt1", r.foreignKeys[0].name);
		Assert.equals("id", r.foreignKeys[0].key);
	}

	public function test03_Reflexive_02_NN() {
		var mocodoStr = "Ent1: id, ent1F1\n" +
						"REnt1Ent1, 0N Ent1, 0N Ent1\n";
		var mld = DiagramToMLD.transform(Mocodo.load(mocodoStr));

		Assert.equals(2, Lambda.count(mld.relations));

		var r1 = mld.relations.get("Ent1");
		Assert.equals(2, r1.fields.length);
		Assert.equals(0, r1.foreignKeys.length);

		var r2 = mld.relations.get("REnt1Ent1");
		Assert.equals(2, r2.fields.length);
		Assert.equals(2, r2.key.length);
		Assert.equals(2, r2.foreignKeys.length);
		Assert.equals("idEnt1", r2.foreignKeys[0].name);
		Assert.equals("Ent1", r2.foreignKeys[0].relation.name);
		Assert.equals("id", r2.foreignKeys[0].key);
		Assert.equals("idEnt11", r2.foreignKeys[1].name);
		Assert.equals("Ent1", r2.foreignKeys[1].relation.name);
		Assert.equals("id", r2.foreignKeys[1].key);
	}

	//04: 1-1 associations
	public function test04_Assoc11() {
		var mocodoStr = "Ent1: idEnt1, ent1F1\n" +
						"Ent2: idEnt2, ent2F1\n" +
						"REnt1Ent2, 01 Ent1, 11 Ent2\n";
		var mld = DiagramToMLD.transform(Mocodo.load(mocodoStr));

		var r1 = mld.relations.get("Ent1");
		Assert.equals(0, r1.foreignKeys.length);
		var r2 = mld.relations.get("Ent2");
		Assert.equals(1, r2.foreignKeys.length);
		Assert.equals("idEnt1", r2.foreignKeys[0].name);
	}

	//05: relative associations (weak sets)
	public function test05_RelAssoc_01() {
		var mocodoStr = "Ent1: idEnt1, ent1F1\n" +
						"REnt1: idREnt1, rent1F1\n" +
						"REnt1REnt1, 0N Ent1, _11 REnt1\n";
		var mld = DiagramToMLD.transform(Mocodo.load(mocodoStr));

		var r = mld.relations.get("REnt1");
		Assert.equals(2, r.key.length);
		Assert.equals(1, r.foreignKeys.length);
		Assert.equals("idEnt1", r.key[0]);
		Assert.equals("idREnt1", r.key[1]);
	}
	
	public function test05_RelAssoc_02_no_fields() {
		var mocodoStr = "Ent1: idEnt1, ent1F1\n" +
						"REnt1: idREnt1\n" +
						"REnt1REnt1, 0N Ent1, _11 REnt1\n";
		var mld = DiagramToMLD.transform(Mocodo.load(mocodoStr));
		
		Assert.equals(2, Lambda.count(mld.relations));
	}

	public function test05_RelAssoc_03_1N() {
		var mocodoStr = "Ent1: idEnt1, ent1F1\n" +
						"REnt1: idREnt1, rent1F1\n" +
						"REnt1REnt1, 0N Ent1, _11 REnt1\n" +
						"Ent2: idEnt2, ent2F1\n" +
						"REnt1Ent2, 0N REnt1, 01 Ent2\n";
		var mld = DiagramToMLD.transform(Mocodo.load(mocodoStr));

		Assert.equals(3, Lambda.count(mld.relations));
		var r = mld.relations.get("Ent2");
		Assert.equals(2, r.foreignKeys.length);
		Assert.equals("idEnt1", r.foreignKeys[0].name);
		Assert.equals("idREnt1", r.foreignKeys[1].name);
		Assert.equals("REnt1", r.foreignKeys[0].relation.name);
		Assert.equals("REnt1", r.foreignKeys[1].relation.name);
	}

	public function test05_RelAssoc_04_NN() {
		var mocodoStr = "Ent1: idEnt1, ent1F1\n" +
						"REnt1: idREnt1, rent1F1\n" +
						"REnt1REnt1, 0N Ent1, _11 REnt1\n" +
						"Ent2: idEnt2, ent2F1\n" +
						"REnt1Ent2, 0N REnt1, 0N Ent2\n";
		var mld = DiagramToMLD.transform(Mocodo.load(mocodoStr));

		Assert.equals(4, Lambda.count(mld.relations));
		var r = mld.relations.get("REnt1Ent2");
		Assert.equals(3, r.key.length);
		Assert.equals(3, r.foreignKeys.length);
	}

	//06: N-N associations
	public function test06_AssocNN_01() {
		var mocodoStr = "Ent1: idEnt1, ent1F1\n" +
						"Ent2: idEnt2, ent2F1\n" +
						"REnt1Ent2, 0N Ent1, 0N Ent2\n";
		var mld = DiagramToMLD.transform(Mocodo.load(mocodoStr));

		Assert.equals(3, Lambda.count(mld.relations));
		var r = mld.relations.get("REnt1Ent2");
		Assert.equals(2, r.key.length);
		Assert.equals(2, r.foreignKeys.length);
	}

	public function test06_AssocNN_02_prop() {
		var mocodoStr = "Ent1: idEnt1, ent1F1\n" +
						"Ent2: idEnt2, ent2F1\n" +
						"REnt1Ent2, 0N Ent1, 0N Ent2: rent12F1 [varchar(50)]\n";
		var mld = DiagramToMLD.transform(Mocodo.load(mocodoStr));

		var r = mld.relations.get("REnt1Ent2");
		Assert.equals(3, r.fields.length);
		Assert.equals("varchar(50)", r.fields[2].type);
	}

	public function test06_AssocNN_03_tern() {
		var mocodoStr = "Ent1: idEnt1, ent1F1\n" +
						"Ent2: idEnt2, ent2F1\n" +
						"Ent3: idEnt3, ent3F1\n" +
						"REnt123, 0N Ent1, 0N Ent2, 0N Ent3\n";
		var mld = DiagramToMLD.transform(Mocodo.load(mocodoStr));

		Assert.equals(4, Lambda.count(mld.relations));
		var r = mld.relations.get("REnt123");
		Assert.equals(3, r.key.length);
		Assert.equals(3, r.foreignKeys.length);
	}

	//07: subclasses
	public function test07L_subclasses() { //(legacy syntax)
		var mocodoStr = "Ent1: idEnt1, ent1F1\n" +
						"SubEnt11: ent11F1\n" +
						"SubEnt11 C Ent1\n";
		var mld = DiagramToMLD.transform(Mocodo.load(mocodoStr));

		Assert.equals(2, Lambda.count(mld.relations));
		var r = mld.relations.get("SubEnt11");
		Assert.equals(2, r.fields.length);
		Assert.equals(1, r.key.length);
		Assert.equals(1, r.foreignKeys.length);
		Assert.equals("idEnt1", r.foreignKeys[0].key);
		Assert.equals("idEnt1", r.key[0]);
	}

	public function test07_subclasses_01() {
		var mocodoStr = "Ent1: idEnt1, ent1F1\n" +
						"SubEnt11: _ent11F1\n" +
						"/\\ Ent1 - SubEnt11\n";
		var mld = DiagramToMLD.transform(Mocodo.load(mocodoStr));

		Assert.equals(2, Lambda.count(mld.relations));
		var r = mld.relations.get("SubEnt11");
		Assert.equals(2, r.fields.length);
		Assert.equals(1, r.key.length);
		Assert.equals(1, r.foreignKeys.length);
		Assert.equals("idEnt1", r.foreignKeys[0].key);
		Assert.equals("idEnt1", r.key[0]);
	}

	public function test07_subclasses_02() {
		var mocodoStr = "Ent1: idEnt1, ent1F1\n" +
						"SubEnt11: _ent11F1\n" +
						"/\\ Ent1 > SubEnt11\n";
		var mld = DiagramToMLD.transform(Mocodo.load(mocodoStr));

		Assert.equals(1, Lambda.count(mld.relations)); //superset > 1 seul enfant, le superset disparait
		var r = mld.relations.get("SubEnt11");
		Assert.equals(3, r.fields.length);
	}

	public function test07_subclasses_03() {
		var mocodoStr = "Ent1: idEnt1, ent1F1\n" +
						"SubEnt11: _ent11F1\n" +
						"SubEnt12: _ent12F1\n" +
						"/X\\ Ent1 > SubEnt11, SubEnt12\n";
		var mld = DiagramToMLD.transform(Mocodo.load(mocodoStr));

		Assert.equals(3, Lambda.count(mld.relations)); //superset > enfants avec exclusion (sans totalité), le superset reste
		Assert.equals(3, mld.relations.get("SubEnt11").fields.length);
		Assert.equals(1, mld.relations.get("SubEnt11").foreignKeys.length);
	}

	public function test07_subclasses_04() {
		var mocodoStr = "Ent1: idEnt1, ent1F1\n" +
						"SubEnt11: ent11F1\n" +
						"SubEnt12: ent12F1\n" +
						"/XT\\ Ent1 > SubEnt11, SubEnt12\n";
		var mld = DiagramToMLD.transform(Mocodo.load(mocodoStr));

		Assert.equals(2, Lambda.count(mld.relations)); //superset > enfants avec partition, le superset disparait 
		Assert.equals(null, mld.relations.get("Ent1"));
		Assert.equals(0, mld.relations.get("SubEnt11").foreignKeys.length);
	}
	
	public function test07_subclasses_05() {
		var mocodoStr = "Ent1: idEnt1, ent1F1\n" +
						"Ent2: idEnt2, ent2F1\n" +
						"AssocE1E2, 11 Ent1, 0N Ent2\n" +
						"SubEnt11: _ent11F1\n" +
						"SubEnt12: _ent12F1\n" +
						"/XT\\ Ent1 > SubEnt11, SubEnt12\n";
		var mld = DiagramToMLD.transform(Mocodo.load(mocodoStr));

		Assert.equals(3, Lambda.count(mld.relations)); //Ent1 disparait
		Assert.equals(null, mld.relations.get("Ent1"));
		var r = mld.relations.get("SubEnt11");
		Assert.equals(1, r.foreignKeys.length);
		Assert.equals(4, r.fields.length); //Ent1(2) + SubEnt11(1) + Ent2-FK(1)
		Assert.equals("idEnt2", r.foreignKeys[0].key);
	}
	
	public function test07_subclasses_06() {
		var mocodoStr = "Ent1: idEnt1, ent1F1\n" +
						"Ent2: idEnt2, ent2F1\n" +
						"AssocE1E2, 0N Ent1, 11 Ent2\n" +
						"SubEnt11: _ent11F1\n" +
						"SubEnt12: _ent12F1\n" +
						"/XT\\ Ent1 > SubEnt11, SubEnt12\n";
		var mld = DiagramToMLD.transform(Mocodo.load(mocodoStr));

		Assert.equals(4, Lambda.count(mld.relations)); //Ent1 ne disparait pas, car Ent2 pointe dessus
	}
	
	public function test07_subclasses_07() {
		var mocodoStr = "Ent1: idEnt1, ent1F1\n" +
						"SubEnt11: _ent11F1\n" +
						"SubEnt12: _ent12F1\n" +
						"/XT\\ Ent1 < [codeSub] SubEnt11, SubEnt12\n";
		var mld = DiagramToMLD.transform(Mocodo.load(mocodoStr));

		Assert.equals(1, Lambda.count(mld.relations));
		Assert.equals(null, mld.relations.get("SubEnt11"));
		Assert.equals(5, mld.relations.get("Ent1").fields.length);
		var fields : Array<Field> = mld.relations.get("Ent1").fields;
		Assert.equals("codeSub", fields[2].name);
		Assert.equals("INT", fields[2].type);
	}
	
	public function test07_subclasses_08() {
		var mocodoStr = "Ent1: idEnt1, ent1F1\n" +
						"SubEnt11: _ent11F1\n" +
						"SubEnt12: idSubEnt12, ent12F1\n" +
						"/XT\\ Ent1 - SubEnt11, SubEnt12\n";
		var mld = DiagramToMLD.transform(Mocodo.load(mocodoStr));

		var r = mld.relations.get("SubEnt12");
		Assert.equals(3, r.fields.length);
		Assert.equals(1, r.key.length);
		Assert.equals(1, r.foreignKeys.length);
		Assert.equals("idEnt1", r.key[0]);
		Assert.equals("idEnt1", r.foreignKeys[0].key);
		r = mld.relations.get("SubEnt11");
		Assert.equals(2, r.fields.length);
		Assert.equals(1, r.key.length);
		Assert.equals(1, r.foreignKeys.length);
		Assert.equals("idEnt1", r.key[0]);
		Assert.equals("idEnt1", r.foreignKeys[0].key);
	}
}
