<!--
   Licensed to the Apache Software Foundation (ASF) under one
   or more contributor license agreements.  See the NOTICE file
   distributed with this work for additional information
   regarding copyright ownership.  The ASF licenses this file
   to you under the Apache License, Version 2.0 (the
   "License"); you may not use this file except in compliance
   with the License.  You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing,
   software distributed under the License is distributed on an
   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   KIND, either express or implied.  See the License for the
   specific language governing permissions and limitations
   under the License.    
-->
<html>
Here are some explanations about the conflict management algorithm in Ivy.<br/><br/>

First, one should have a good understanding on how Ivy resolves dependencies, and especially
transitive dependencies.<br/><br/>

During the resolve process, ivy visits each module of the dependency graph. <br/>
Let's call each module a <b>node</b>, including the module we are trying to resolve dependencies for.<br/><br/>

Each node should be able to give a conflict manager for a particular ModuleId.<br/>
Let's name it <b>node.cm(mid)</b>.<br/><br/>

Each node should be able to matain a map from ModuleId to a resolved Collection of nodes.<br/>
This resolved collection will never contain any evicted node FOR the concerned node as far
as ivy knows, dependening on where it is in graph visit.<br/>
Let's call this map resolved, and the corresponding resolved collection <b>node.resolved(mid)</b>.<br/><br/>

During the visit, ivy should always know from which node it came to visit another node. Let's call
the first node from which ivy came <b>node.parent</b>. Note that this concept is slightly different from
node parent, since a node can have several parents in the graph, but there is also one <b>node.parent</b>
during the visit.<br/><br/>

Let's say that a conflict manager is able to filter a collection of nodes to return only those
that are not evicted. Let's call that <b>cm.resolveConflicts(collection)</b>.<br/><br/>

Let's call <b>node.dependencies</b> the collection of direct dependencies of a node.<br/><br/>

Let's call <b>node.revision</b> the module revision id of a node.<br/><br/>

And now for the algo. This algo attempts to evict nodes on the fly, i.e. during the ivy visit,
to minimize the number of resolved modules, and thus the number of ivy files to download.<br/><br/>

It is presented in a very simplified description language, far away from the whole real complexity,
but giving a good understanding of how it works. In particular, it completely hides some complexity due
to configurations management.<br/><br/>

<pre>
resolve(node) {
	node.resolved(node.mid) = <i>collection</i>(node);
	resolveConflict(node, node.parent, empty);
	if (!node.evicted && !node.alreadyResolved) {
		node.loadData();
		resolveConflict(node, node.parent, empty);
		if (!node.evicted) {
			// actually do resolve
			foreach (dep in node.dependencies) {
				resolve(dep);
			}
		}
	}
}

resolveConflict(node, parent, toevict) {
	if (node.revision.exact && parent.resolved(node.mid).revision.contains(node.revision)) { 
		// exact revision already in resolved
		// => job already done
		return;
	}
	if (parent.resolved(node.mid).containsAny(toevict)) {
		// parent.resolved(node.mid) is not up to date:
		// recompute resolved from all sub nodes
		resolved = parent.cm(node.mid).resolveConflicts(
		                                 parent.dependencies.resolved(node.mid));
	} else {
		resolved = parent.cm(node.mid).resolveConflicts(<i>collection</i>(node, parent.resolved(node.mid)));
	}
	if (resolved.contains(node)) {
		// node has been selected for the current parent
		// we update its eviction... but it can still be evicted by parent !
		node.evicted = false;
		
		// handle previously selected nodes that are now evicted by this new node
		toevict = parent.resolved(node.mid) - resolved;
		foreach (te in toevict) {
			te.evicted = true;
		}
		
		// it's very important to update resolved BEFORE recompute parent call
		// to allow it to recompute its resolved collection with correct data
		// if necessary
		parent.resolved(node.mid) = resolved; 
		if (parent.parent != null) {
			resolveConflict(node, parent.parent, toevict);
		}
	} else {
		// node has been evicted for the current parent
		
		// it's time to update parent resolved with found resolved...
		// if they have not been recomputed, it does not change anything
		parent.resolved(node.mid) = resolved; 
		
		node.evicted = true;
	}
}

</pre>
</html>
