var ArrowLink = require("../elements/links/ArrowLink");
var BoxArrowLink = require("../elements/links/BoxArrowLink");
var PlainLink = require("../elements/links/PlainLink");
var OwlDisjointWith = require("../elements/properties/implementations/OwlDisjointWith");
var SetOperatorProperty = require("../elements/properties/implementations/SetOperatorProperty");
/**
* Stores the passed properties in links.
* @returns {Function}
*/
module.exports = (function (){
var linkCreator = {};
/**
* Creates links from the passed properties.
* @param properties
*/
linkCreator.createLinks = function ( properties ){
var links = groupPropertiesToLinks(properties);
for ( var i = 0, l = links.length; i < l; i++ ) {
var link = links[i];
countAndSetLayers(link, links);
countAndSetLoops(link, links);
}
return links;
};
/**
* Creates links of properties and - if existing - their inverses.
* @param properties the properties
* @returns {Array}
*/
function groupPropertiesToLinks( properties ){
var links = [],
property,
addedProperties = require("../util/set")();
for ( var i = 0, l = properties.length; i < l; i++ ) {
property = properties[i];
if ( !addedProperties.has(property) ) {
var link = createLink(property);
property.link(link);
if ( property.inverse() ) {
property.inverse().link(link);
}
links.push(link);
addedProperties.add(property);
if ( property.inverse() ) {
addedProperties.add(property.inverse());
}
}
}
return links;
}
function countAndSetLayers( link, allLinks ){
var layer,
layers,
i, l;
if ( typeof link.layers() === "undefined" ) {
layers = [];
// Search for other links that are another layer
for ( i = 0, l = allLinks.length; i < l; i++ ) {
var otherLink = allLinks[i];
if ( link.domain() === otherLink.domain() && link.range() === otherLink.range() ||
link.domain() === otherLink.range() && link.range() === otherLink.domain() ) {
layers.push(otherLink);
}
}
// Set the results on each of the layers
for ( i = 0, l = layers.length; i < l; ++i ) {
layer = layers[i];
layer.layerIndex(i);
layer.layers(layers);
}
}
}
function countAndSetLoops( link, allLinks ){
var loop,
loops,
i, l;
if ( typeof link.loops() === "undefined" ) {
loops = [];
// Search for other links that are also loops of the same node
for ( i = 0, l = allLinks.length; i < l; i++ ) {
var otherLink = allLinks[i];
if ( link.domain() === otherLink.domain() && link.domain() === otherLink.range() ) {
loops.push(otherLink);
}
}
// Set the results on each of the loops
for ( i = 0, l = loops.length; i < l; ++i ) {
loop = loops[i];
loop.loopIndex(i);
loop.loops(loops);
}
}
}
function createLink( property ){
var domain = property.domain();
var range = property.range();
if ( property instanceof OwlDisjointWith ) {
return new PlainLink(domain, range, property);
} else if ( property instanceof SetOperatorProperty ) {
return new BoxArrowLink(domain, range, property);
}
return new ArrowLink(domain, range, property);
}
return function (){
// Return a function to keep module interfaces consistent
return linkCreator;
};
})();