|
|
|
package net.yacy.search.schema;
|
|
|
|
|
|
|
|
import java.lang.reflect.Array;
|
|
|
|
import java.util.HashMap;
|
|
|
|
import java.util.Iterator;
|
|
|
|
import java.util.LinkedHashMap;
|
|
|
|
import java.util.LinkedHashSet;
|
|
|
|
import java.util.Map;
|
|
|
|
import java.util.Set;
|
|
|
|
|
|
|
|
import net.yacy.cora.document.id.MultiProtocolURL;
|
|
|
|
|
|
|
|
public class HyperlinkEdges implements Iterable<HyperlinkEdge> {
|
|
|
|
|
|
|
|
public static class Targets {
|
|
|
|
public Set<HyperlinkEdge.Target> targets;
|
|
|
|
public int depth;
|
|
|
|
|
|
|
|
public Targets(int depth) {
|
|
|
|
this.targets = new LinkedHashSet<HyperlinkEdge.Target>();
|
|
|
|
this.depth = depth;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private final Map<MultiProtocolURL, Targets> edges;
|
|
|
|
private final Map<MultiProtocolURL, Integer> singletonDepth;
|
|
|
|
|
|
|
|
public HyperlinkEdges() {
|
|
|
|
this.edges = new LinkedHashMap<MultiProtocolURL, Targets>();
|
|
|
|
this.singletonDepth = new HashMap<MultiProtocolURL, Integer>();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void add(final HyperlinkEdge edge) {
|
|
|
|
addEdge(edge.source, edge.target);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void addEdge(final MultiProtocolURL source, final HyperlinkEdge.Target target) {
|
|
|
|
Targets targets = this.edges.get(source);
|
|
|
|
Integer d = this.singletonDepth.get(source);
|
|
|
|
if (d == null) d = -1; else this.singletonDepth.remove(source);
|
|
|
|
if (target.type == HyperlinkType.Inbound) {
|
|
|
|
Integer e = this.singletonDepth.remove(target);
|
|
|
|
if (e != null && d.intValue() == -1) d = e.intValue() - 1;
|
|
|
|
}
|
|
|
|
if (targets == null) {
|
|
|
|
targets = new Targets(d.intValue());
|
|
|
|
this.edges.put(source, targets);
|
|
|
|
}
|
|
|
|
targets.targets.add(target);
|
|
|
|
}
|
|
|
|
|
|
|
|
public int size() {
|
|
|
|
int s = 0;
|
|
|
|
for (Targets t: edges.values()) s += t.targets.size();
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void addAll(final HyperlinkEdges oe) {
|
|
|
|
for (Map.Entry<MultiProtocolURL, Targets> edges: oe.edges.entrySet()) {
|
|
|
|
for (HyperlinkEdge.Target t: edges.getValue().targets) {
|
|
|
|
this.addEdge(edges.getKey(), t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void updateDepth(final MultiProtocolURL url, final int newdepth) {
|
|
|
|
Targets targets = this.edges.get(url);
|
|
|
|
if (targets == null) {
|
|
|
|
singletonDepth.put(url, newdepth);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (targets.depth == -1) {
|
|
|
|
targets.depth = newdepth;
|
|
|
|
} else {
|
|
|
|
targets.depth = Math.min(targets.depth, newdepth);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getDepth(final MultiProtocolURL url) {
|
|
|
|
Targets targets = this.edges.get(url);
|
|
|
|
if (targets != null) return targets.depth;
|
|
|
|
Integer d = this.singletonDepth.get(url);
|
|
|
|
if (d != null) return d.intValue();
|
|
|
|
// now search in targets
|
|
|
|
String targetHost = url.getHost();
|
|
|
|
for (Map.Entry<MultiProtocolURL, Targets> e: this.edges.entrySet()) {
|
|
|
|
if (e.getValue().targets.contains(url)) {
|
|
|
|
String sourceHost = e.getKey().getHost();
|
|
|
|
// check if this is an inbound match
|
|
|
|
if ((sourceHost == null && targetHost == null) || (sourceHost != null && targetHost != null && sourceHost.equals(targetHost))) return e.getValue().depth + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Iterator<HyperlinkEdge> iterator() {
|
|
|
|
final Iterator<Map.Entry<MultiProtocolURL, Targets>> i = this.edges.entrySet().iterator();
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
final Iterator<HyperlinkEdge.Target>[] tc = (Iterator<HyperlinkEdge.Target>[]) Array.newInstance(Iterator.class, 1);
|
|
|
|
tc[0] = null;
|
|
|
|
final MultiProtocolURL[] su = new MultiProtocolURL[1];
|
|
|
|
su[0] = null;
|
|
|
|
return new Iterator<HyperlinkEdge>() {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean hasNext() {
|
|
|
|
return i.hasNext() || (tc[0] != null && tc[0].hasNext());
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public HyperlinkEdge next() {
|
|
|
|
while (tc[0] == null || !tc[0].hasNext()) {
|
|
|
|
Map.Entry<MultiProtocolURL, Targets> entry = i.next();
|
|
|
|
tc[0] = entry.getValue().targets.iterator();
|
|
|
|
su[0] = entry.getKey();
|
|
|
|
}
|
|
|
|
if (!tc[0].hasNext()) return null;
|
|
|
|
return new HyperlinkEdge(su[0], tc[0].next());
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void remove() {
|
|
|
|
tc[0].remove();
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|