Ejemplo n.º 1
0
/**
 * Check the dependencies (recursively) of this content info
 * @param ci the content info to check the dependencies of
 */
void ClientNetworkContentSocketHandler::CheckDependencyState(ContentInfo *ci)
{
	if (ci->IsSelected() || ci->state == ContentInfo::ALREADY_HERE) {
		/* Selection is easy; just walk all children and set the
		 * autoselected state. That way we can see what we automatically
		 * selected and thus can unselect when a dependency is removed. */
		for (uint i = 0; i < ci->dependency_count; i++) {
			ContentInfo *c = this->GetContent(ci->dependencies[i]);
			if (c == NULL) {
				this->DownloadContentInfo(ci->dependencies[i]);
			} else if (c->state == ContentInfo::UNSELECTED) {
				c->state = ContentInfo::AUTOSELECTED;
				this->CheckDependencyState(c);
			}
		}
		return;
	}

	if (ci->state != ContentInfo::UNSELECTED) return;

	/* For unselection we need to find the parents of us. We need to
	 * unselect them. After that we unselect all children that we
	 * depend on and are not used as dependency for us, but only when
	 * we automatically selected them. */
	ConstContentVector parents;
	this->ReverseLookupDependency(parents, ci);
	for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) {
		const ContentInfo *c = *iter;
		if (!c->IsSelected()) continue;

		this->Unselect(c->id);
	}

	for (uint i = 0; i < ci->dependency_count; i++) {
		const ContentInfo *c = this->GetContent(ci->dependencies[i]);
		if (c == NULL) {
			DownloadContentInfo(ci->dependencies[i]);
			continue;
		}
		if (c->state != ContentInfo::AUTOSELECTED) continue;

		/* Only unselect when WE are the only parent. */
		parents.Clear();
		this->ReverseLookupDependency(parents, c);

		/* First check whether anything depends on us */
		int sel_count = 0;
		bool force_selection = false;
		for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) {
			if ((*iter)->IsSelected()) sel_count++;
			if ((*iter)->state == ContentInfo::SELECTED) force_selection = true;
		}
		if (sel_count == 0) {
			/* Nothing depends on us */
			this->Unselect(c->id);
			continue;
		}
		/* Something manually selected depends directly on us */
		if (force_selection) continue;

		/* "Flood" search to find all items in the dependency graph*/
		parents.Clear();
		this->ReverseLookupTreeDependency(parents, c);

		/* Is there anything that is "force" selected?, if so... we're done. */
		for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) {
			if ((*iter)->state != ContentInfo::SELECTED) continue;

			force_selection = true;
			break;
		}

		/* So something depended directly on us */
		if (force_selection) continue;

		/* Nothing depends on us, mark the whole graph as unselected.
		 * After that's done run over them once again to test their children
		 * to unselect. Don't do it immediatelly because it'll do exactly what
		 * we're doing now. */
		for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) {
			const ContentInfo *c = *iter;
			if (c->state == ContentInfo::AUTOSELECTED) this->Unselect(c->id);
		}
		for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) {
			this->CheckDependencyState(this->GetContent((*iter)->id));
		}
	}
}