package eu.dnetlib.r2d2.neo4j;

import org.apache.log4j.Logger;
import org.neo4j.graphdb.Node;

import com.google.common.collect.Iterables;

import eu.dnetlib.r2d2.neo4j.dao.Neo4JDao;
import eu.dnetlib.r2d2.neo4j.util.TransactionStatusHolder;

public abstract class Neo4jBean {
	private static Logger logger = Logger.getLogger(Neo4jBean.class);
	
	public final static String ID = "_id";
	public final static String PREFIX = "_prefix";
	
	private Node node = null;
	
	public void setValue(String propertyName, Object value) {
		logger.debug("setting " + propertyName + " to " + value);
		String nodeName = null;
		
		if (propertyName.equals(ID))
			nodeName = ID;
		else if (propertyName.equals(PREFIX))
			nodeName = PREFIX;
		else
			nodeName = getClass().getName() + "." + propertyName;
		
		if (value != null) {
			node.setProperty(nodeName, value);
		} else {
			if (node.hasProperty(nodeName))
				node.removeProperty(nodeName);
		}
		
		TransactionStatusHolder.setWriteStatus();
	}
	
	public Object getValue(String propertyName) {
		Object value = null;
		
		if (propertyName.equals(ID))
			value = node.getProperty(ID);
		else if (propertyName.equals(PREFIX))
			value = node.getProperty(PREFIX);
		else
			value = node.getProperty(this.getClass().getName() + "." + propertyName, null);
		
		return value;
	}
	
	public String getId() {
		return (String) node.getProperty(ID);
	}
	
	public void setId(String id) {
		String originalId = null;
		
		if (Iterables.contains(node.getPropertyKeys(), ID))
			originalId = (String) node.getProperty(ID);
		
		if (originalId != null && Neo4JDao.createdNodes.get().containsKey(originalId)) {
			Node n = Neo4JDao.createdNodes.get().remove(originalId);
			Neo4JDao.createdNodes.get().put(id, n);
		}
		
		node.setProperty(ID, id);
		TransactionStatusHolder.setWriteStatus();
	}

	public Node getNode() {
		return node;
	}
	
	@SuppressWarnings("unchecked")
	public void setNode(Node node) {
		String prefix = this.getClass().getName();
		
		if (!Iterables.contains(node.getPropertyKeys(), PREFIX)) {
			node.setProperty(PREFIX, prefix);
			TransactionStatusHolder.setWriteStatus();
		} else {
			String nodePrefix = (String) node.getProperty(PREFIX);

			if (!nodePrefix.equals(prefix)) {
				try {
					Class<? extends Neo4jBean> expected = this.getClass();
					Class<? extends Neo4jBean> given = (Class<? extends Neo4jBean>) Class.forName(nodePrefix);
					
					throw new WrongTypeException(given, expected);
				} catch (ClassNotFoundException e) {
					throw new RuntimeException("unknown type " + nodePrefix);
				}
			}
		}

		this.node = node;
	}
}