-- In this more contracted solution compared to r7.qvt, relations createSquareForInitialArrow and createSquareForFinalArrow are melted into one relation createSquare, using a primitive domain to pass the name string. 
transformation r7_shorter_solution(source : Shapes, target : Shapes) {

	top relation ArrowSource2ArrowSource {
		
		enforce domain source sourceArrow : Shapes::Arrow {
			source = sourceArrowSource : Shapes::Shape {
			}
		};
		
		enforce domain target targetArrow : Shapes::Arrow {
			source = targetArrowSource : Shapes::Shape {
			}
		};
		
		when {
			Source2Target(sourceArrow, targetArrow);
			Source2Target(sourceArrowSource, targetArrowSource);
		}
		
	}
	
	top relation ArrowTarget2ArrowTarget {
		
		enforce domain source sourceArrow : Shapes::Arrow {
			target = sourceArrowTarget : Shapes::Shape {
			}
		};
		
		enforce domain target targetArrow : Shapes::Arrow {
			target = targetArrowTarget : Shapes::Shape {
			}
		};
		
		when {
			Source2Target(sourceArrow, targetArrow);
			Source2Target(sourceArrowTarget, targetArrowTarget);
		}
		
	}
	
	top relation ModelElementName2ModelElementName {
		
		varName : String;
		
		enforce domain source sourceModelElement : Shapes::ModelElement {
			name = varName
		};
		
		enforce domain target targetModelElement : Shapes::ModelElement {
			name = varName
		};
		
		when {
			Source2Target(sourceModelElement, targetModelElement);
		}
		
	}
	
	top relation ModelElementblock2ModelElementblock {
		
		enforce domain source sourceModelElement : Shapes::ModelElement {
			block = sourceblock : Shapes::Block {
			}
		};
		
		enforce domain target targetModelElement : Shapes::ModelElement {
			block = targetblock : Shapes::Block {
			}
		};
		
		when {
			Source2Target(sourceModelElement, targetModelElement);
			Source2Target(sourceblock, targetblock);
		}
		
	}
	
	top relation Source2Target {
		
		enforce domain source s : Shapes::ModelElement {
		};
		
		enforce domain target t : Shapes::ModelElement {
		};
		
		when {
			MapBlock(s, t) or MapRootBlock(s, t) or MapCircle(s, t) or MapTriangle(s, t) or MapSquare(s, t) or MapArrow(s, t);
		}
		
	}
	
	top relation MapRootBlock {
		
		enforce domain source s : Shapes::RootBlock {
		};
		
		enforce domain target t : Shapes::RootBlock {
		};
		
	}
	
	top relation MapBlock {
		
		enforce domain source s : Shapes::Block {
		};
		
		enforce domain target t : Shapes::Block {
		};
		
		when {
			not MapRootBlock(s, t);
		}
		
	}
		
	top relation MapCircle {
		
		hasAtLeaseOneInArrow : Boolean;
		hasAtLeaseOneOutArrow : Boolean;
		
		enforce domain source s : Shapes::Circle { };
		
		enforce domain target t : Shapes::Arrow {
			source = c1 : Shapes::Shape { },
			target = c2 : Shapes::Shape { }
		};
		
		when {
			hasAtLeaseOneInArrow = MapArrow(s.inArrow->asSequence()->first(), c1);
			hasAtLeaseOneOutArrow = MapArrow(s.outArrow->asSequence()->first(), c2);
		}
		
		where {
			if hasAtLeaseOneInArrow then
				true
			else
				createSquare(s, 'initial square', c1)
			endif;
			if hasAtLeaseOneOutArrow then
				true
			else
				createSquare(s, 'final square', c2)
			endif;
		}
		
	}
	
	relation createSquare {
		
		enforce domain source s : Shapes::Circle {
			block = sourceblock : Shapes::Block {
			}
		};
		
		primitive domain nameParameter : String;
		
		enforce domain target t : Shapes::Square {
			name = nameParameter,
			block = targetblock : Shapes::Block {
			}
		};	
		
		when {
			Source2Target(sourceblock, targetblock);
		}
			
	}
		
	top relation MapTriangle {
		
		enforce domain source s : Shapes::Triangle {
		};
		
		enforce domain target t : Shapes::Triangle {
		};
		
	}
	
	top relation MapSquare {
		
		enforce domain source s : Shapes::Square {
		};
		
		enforce domain target t : Shapes::Square {
		};
		
	}
		
	top relation MapArrow {
		
		enforce domain source s : Shapes::Arrow {
		};
		
		enforce domain target t : Shapes::Circle {
		};
		
	}
	
}
