/*******************************************************************************
* Copyright (c) 2013 AKSW Xturtle Project, itemis AG (http://www.itemis.eu).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
******************************************************************************/
package de.itemis.tooling.xturtle.resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.xtext.naming.QualifiedName;
import org.eclipse.xtext.nodemodel.INode;
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
import com.google.common.base.Optional;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import de.itemis.tooling.xturtle.xturtle.Base;
import de.itemis.tooling.xturtle.xturtle.PrefixId;
import de.itemis.tooling.xturtle.xturtle.QNameDef;
import de.itemis.tooling.xturtle.xturtle.QNameRef;
import de.itemis.tooling.xturtle.xturtle.UriDef;
import de.itemis.tooling.xturtle.xturtle.UriRef;
import de.itemis.tooling.xturtle.xturtle.XturtlePackage;
//THE central class for most of the turtle functionality, as it attaches a resolved URI to
//each Resource(Reference). Otherwise handling the model would become even more messy.
//this is done via an Adapter stored in the model root which holds maps with all the
//necessary information
class TurtleResourceIndex implements Adapter {
public void notifyChanged(Notification notification) {}
public Notifier getTarget() {
return null;
}
public void setTarget(Notifier newTarget) {}
public boolean isAdapterForType(Object type) {
return false;
}
private TurtleUriResolver resolver;
private BiMap<EObject,String> fragmentMap;
private Map<EObject,QualifiedName> qNameMap;
private PrefixId currentEmptyPrefix=null;
String getFragment(EObject o){
return fragmentMap.get(o);
}
EObject getObject(String fragment){
return fragmentMap.inverse().get(fragment);
}
QualifiedName getName(EObject object){
return qNameMap.get(object);
}
void initIndex(EObject root){
resetMaps(root.eResource());
int i=0;
addFragmentEntry(i++, root);
//make sure blank node labels get proper qualified name; base is file URI
//TODO check if this works
QualifiedName blankName=resolver.getPrefixName("_", "#");
qNameMap.put(root, blankName);
TreeIterator<EObject> iterator = root.eAllContents();
while(iterator.hasNext()) {
EObject obj = iterator.next();
addFragmentEntry(i++, obj);
addUriAndNameEntries(obj);
}
}
private void addUriAndNameEntries(EObject obj) {
if(obj instanceof PrefixId){
addPrefixIdEntries((PrefixId) obj);
} else if(obj instanceof Base){
addBaseEntries((Base) obj);
} else if(obj instanceof QNameDef){
String prefix=getPrefixText(obj,XturtlePackage.Literals.QNAME_DEF__PREFIX);
QualifiedName name=resolver.resolveWithLocalName(prefix, ((QNameDef) obj).getId());
if(name!=null){
qNameMap.put(obj, name);
}
} else if(obj instanceof UriDef){
QualifiedName qName=resolver.resolveWithUri(((UriDef) obj).getUri());
if(qName!=null){
qNameMap.put(obj, qName);
}
} else if(obj instanceof QNameRef){
String prefix=getPrefixText(obj, XturtlePackage.Literals.QNAME_REF__PREFIX);
List<INode> refNodes = NodeModelUtils.findNodesForFeature(obj, XturtlePackage.Literals.RESOURCE_REF__REF);
String ref=NodeModelUtils.getTokenText(refNodes.get(0));
if(ref!=null&& ref.length()>0&& ref.charAt(0)==':'){
QualifiedName name=resolver.resolveWithLocalName(prefix, ref.substring(1));
if(name!=null){
qNameMap.put(obj, name);
//empty prefix linking hack
if(prefix.length()==0){
((QNameRef)obj).setPrefix(currentEmptyPrefix);
}
}
}
} else if(obj instanceof UriRef){
QualifiedName qName;
List<INode> refNodes = NodeModelUtils.findNodesForFeature(obj, XturtlePackage.Literals.RESOURCE_REF__REF);
if(refNodes.size()==1){
String ref = refNodes.get(0).getText();
ref=ref.substring(1, ref.length()-1);
qName=resolver.resolveWithUri(ref);
qNameMap.put(obj, qName);
}
// else{
// qNameMap.put(obj, QualifiedName.create("invalid","invalid"));
// }
}
}
private String getPrefixText(EObject obj, EReference ref) {
String prefix=null;
List<INode> nodes = NodeModelUtils.findNodesForFeature(obj, ref);
switch(nodes.size()){
case 0:
prefix="";
break;
case 1:
prefix=NodeModelUtils.getTokenText(nodes.get(0));
break;
}
return prefix;
}
private void addBaseEntries(Base obj) {
QualifiedName newBase=resolver.updateAndGetBase(obj.getUri());
if(newBase!=null){
qNameMap.put(obj, newBase);
}
}
private void addPrefixIdEntries(PrefixId obj) {
if(obj.getId()==null){
currentEmptyPrefix=obj;
}
String prefix = Optional.fromNullable(obj.getId()).or("");
String uriString=obj.getUri();
QualifiedName name=resolver.getPrefixName(prefix, uriString);
if(name!=null){
qNameMap.put(obj, name);
}
}
private void resetMaps(Resource resource){
fragmentMap=HashBiMap.create();
qNameMap=new HashMap<EObject, QualifiedName>();
resolver=new TurtleUriResolver(resource.getURI());
}
private void addFragmentEntry(int index, EObject object){
fragmentMap.put(object, ""+index);
}
}