package org.aksw.jena_sparql_api.views;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.aksw.commons.collections.MapUtils;
import org.aksw.commons.collections.multimaps.ISetMultimap;
import org.aksw.jena_sparql_api.utils.QuadUtils;
import org.apache.jena.graph.Node;
import org.apache.jena.sparql.core.Quad;
import org.apache.jena.sparql.core.Var;
import com.google.common.collect.Sets;
class NodeV {
private Node node;
private int id;
public NodeV(Node node, int id)
{
super();
this.node = node;
this.id = id;
}
public Node getNode()
{
return node;
}
public int getId()
{
return id;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + id;
result = prime * result + ((node == null) ? 0 : node.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
NodeV other = (NodeV) obj;
if (id != other.id)
return false;
if (node == null) {
if (other.node != null)
return false;
} else if (!node.equals(other.node))
return false;
return true;
}
@Override
public String toString()
{
return node + "(" + id +")";
}
}
/**
* In its current state this class only hides the copying that should be
* avoided by a view
*
* @author raven
*
* @param <K>
* @param <V>
*/
//class UnionBiMultiMap<K, V>
// implements IBiSetMultimap<K, V>
//{
// private Collection<IBiSetMultimap<K, V>> wrapped;
// private UnionBiMultiMap<V, K> inverse;
//
//
// public static <K, V> UnionBiMultiMap<K, V> create(IBiSetMultimap<K, V> a, IBiSetMultimap<K, V> b)
// {
// Collection<IBiSetMultimap<K, V>> union = new ArrayList<IBiSetMultimap<K, V>>();
// union.add(a);
// union.add(b);
//
// return new UnionBiMultiMap<K, V>(union);
// }
//
// public UnionBiMultiMap(Collection<IBiSetMultimap<K, V>> wrapped)
// {
// this.wrapped = wrapped;
// inverse = new UnionBiMultiMap<V, K>(this);
// }
//
// protected UnionBiMultiMap(UnionBiMultiMap<V, K> original)
// {
// this.inverse = original;
//
// wrapped = new ArrayList<IBiSetMultimap<K, V>>();
// for(IBiSetMultimap<V, K> item : original.wrapped) {
// wrapped.add(item.getInverse());
// }
// }
//
// /**
// * Making a copy of the values is just what we want to avoid by doing all
// * that stuff... guava doesn't have a union multimap view it seems
// * But too much work to implement properly for now.
// *
// */
// private SetMultimap<K, V> copyAll()
// {
// SetMultimap<K, V> copy = HashMultimap.create();
//
// for(IBiSetMultimap<K, V> item : wrapped) {
// copy.asMap().putAll(item.asMap());
// }
//
// return copy;
// }
//
// @Override
// public Map<K, Collection<V>> asMap()
// {
// return copyAll().asMap();
// }
//
// @Override
// public boolean put(K key, V value)
// {
// throw new NotImplementedException();
// }
//
// @Override
// public Set<V> removeAll(Object key)
// {
// throw new NotImplementedException();
// }
//
//
// // TODO This should be a view
// @Override
// public Set<V> get(Object key)
// {
// Set<V> result = new HashSet<V>();
//
// for(IBiSetMultimap<K, V> item : wrapped) {
// result.addAll(item.get(key));
// }
//
// return result;
// }
//
// @Override
// public IBiSetMultimap<V, K> getInverse()
// {
// return inverse;
// }
//
// @Override
// public Set<Entry<K, V>> entries()
// {
// return copyAll().entries();
// }
//
// @Override
// public void putAll(ISetMultimap<K, V> other)
// {
// throw new NotImplementedException();
// }
//
// @Override
// public void clear()
// {
// throw new NotImplementedException();
// }
//
// @Override
// public boolean containsEntry(Object key, Object value) {
// throw new NotImplementedException();
// }
//
// @Override
// public boolean containsValue(Object value) {
// throw new NotImplementedException();
// }
//
// @Override
// public boolean containsKey(Object key) {
// throw new NotImplementedException();
// }
//
// @Override
// public int size() {
// throw new NotImplementedException();
// }
//
// @Override
// public void putAll(K key, Collection<V> values) {
// for(V value : values) {
// put(key, value);
// }
// }
//
// @Override
// public Set<K> keySet() {
// throw new NotImplementedException();
// }
//
// @Override
// public Collection<K> keys() {
// throw new NotImplementedException();
// }
//}
public class TwoWayBinding
{
private EquiMap<Var, Node> equiMap = new EquiMap<Var, Node>();
/**
* Returns union of the keySets of
* equiMap.getEquivalences and equiMap.getKeyToValue
*
* @return
*/
public Set<Var> keySet() {
return Sets.union(equiMap.getEquivalences().asMap().keySet(), equiMap.getKeyToValue().keySet());
}
/**
* Copies the map.
* Leave null for a deep copy
*
* @param map
* @return
*/
public TwoWayBinding copySubstitute(Map<? extends Node, Node> map)
{
//EquiMap<Var, Node> result = new EquiMap<Var, Node>();
TwoWayBinding result = new TwoWayBinding();
// Copy equivalences
for(Entry<Var, Collection<Var>> entry : equiMap.getEquivalences().asMap().entrySet()) {
Var newKey = map == null
? entry.getKey()
: (Var)MapUtils.getOrElse(map, entry.getKey(), entry.getKey());
for(Var item : entry.getValue()) {
Var newValue = map == null
? item
:(Var)MapUtils.getOrElse(map, item, item);
result.getEquiMap().getEquivalences().put(newKey, newValue);
}
}
// Copy to values
for(Entry<Var, Node> entry : equiMap.getKeyToValue().entrySet()) {
Var newKey = map == null
? entry.getKey()
: (Var)MapUtils.getOrElse(map, entry.getKey(), entry.getKey());
Node newValue = map == null
? entry.getValue()
: MapUtils.getOrElse(map, entry.getValue(), entry.getValue());
result.getEquiMap().getKeyToValue().put(newKey, newValue);
}
return result;
}
public TwoWayBinding()
{
super();
}
public void clear()
{
equiMap.clear();
}
/*
public boolean isConsistent()
{
for(NodeV key : equiMap.getKeyToValue().keySet()) {
if(equiMap.get(key).size() > 1) {
return false;
}
}
return true;
}
*/
public EquiMap<Var, Node> getEquiMap()
{
return equiMap;
}
/*
public boolean isConsistent(NodeV a, NodeV b)
{
return Sets.union(equiMap.get(a), equiMap.get(b)).size() <= 1;
}
public boolean makeEqual(NodeV a, NodeV b)
{
if(isConsistent(a, b)) {
equiMap.makeEqual(a, b);
return true;
}
return false;
}
*/
/*
public boolean isInsertConsistent(Var a, Node b)
{
Set<Node> values = equiMap.get(a);
if(values.size() > 1) {
throw new RuntimeException("Should not happen");
}
return equiMap.isConsistentSet(values);
}*/
public boolean put(Var a, Node b)
{
if(equiMap.isConsistentInsertValue(a, b)) {
equiMap.put(a, b);
return true;
}
return false;
}
public boolean makeEqual(Var a, Var b)
{
if(equiMap.isConsistentInsertEquiv(a, b)) {
equiMap.makeEqual(a, b);
return true;
}
return false;
}
/**
* Returns false if the entry could not be added due to not being compatible
* with the remaining mappings.
*
* @param entry
* @return
*/
//public boolean add(Map.Entry<Node, Node> entry)
//{
public boolean add(Node a, Node b)
{
//Node a = entry.getKey();
//Node b = entry.getValue();
//NodeV av = new NodeV(a, 1);
//NodeV bv = new NodeV(b, 2);;
if(a.isVariable() && b.isVariable()) {
return makeEqual((Var)a, (Var)b);
} else if(a.isVariable() && b.isConcrete()) {
return put((Var)a, b);
} else if(a.isConcrete() && b.isVariable()) {
return put((Var)b, a);
} else if(a.isConcrete() && b.isConcrete()) {
return a.equals(b);
}
throw new RuntimeException("Should not happen.");
}
public void addAll(TwoWayBinding other)
{
this.equiMap.getEquivalences().putAll(other.getEquiMap().getEquivalences());
this.equiMap.getKeyToValue().putAll(other.getEquiMap().getKeyToValue());
}
@Override
public String toString()
{
return equiMap.toString();
}
public boolean isCompatible(TwoWayBinding other)
{
return equiMap.isCompatible(other.getEquiMap());
}
public static TwoWayBinding getVarMappingTwoWay(Quad a, Quad b)
{
TwoWayBinding result = new TwoWayBinding();
List<Node> nAs = QuadUtils.quadToList(a);
List<Node> nBs = QuadUtils.quadToList(b);
for(int i = 0; i < 4; ++i) {
Node nA = nAs.get(i);
Node nB = nBs.get(i);
if(!result.add(nA, nB)) {
return null;
}
}
return result;
}
public Set<Var> getQueryVariables() {
return this.equiMap.getEquivalences().asMap().keySet();
}
/**
*
* @return The multimap that maps query variables to the corresponding set of view variables
*/
public ISetMultimap<Var, Var> getVariableMap() {
return this.equiMap.getEquivalences();
}
/**
*
* @return The map that maps query variables to an optionally associated constant
*/
public Map<Var, Node> getConstantMap() {
return this.equiMap.getKeyToValue();
}
public Set<Var> getViewVariablesForQueryVariable(Var queryVar) {
return this.equiMap.getEquivalences().get(queryVar);
}
public Set<Var> getViewVariables() {
return this.equiMap.getEquivalences().getInverse().asMap().keySet();
}
}