package sitris;

import javax.ejb.*;

import sitris.Literal;
import sitris.LiteralPK;
import sitris.LiteralHome;
import sitris.Resource;
import sitris.ResourcePK;
import sitris.ResourceHome;
import sitris.Statement;
import sitris.StatementPK;
import sitris.StatementHome;
import sitris.ModelPK;
import sitris.Model;
import sitris.ModelHome;
import sitris.RemoteNode;
import sitris.RemoteNodePK;
import java.util.Collection;
/**
 * This Entity EJB represents a RDF Model
  @ejb:entity-cmp
  @ejb:ejb-name sitris/Model
  @ejb:jndi-name ejb/sitris/Model
  @ejb:finder java.util.Collection findAll()
  @ejb:finder
  @ejb:ejb-ref sitris/Statement
  @ejb:ejb-ref sitris/Resource
  @ejb:ejb-ref sitris/Literal
  @ejb:security-role-ref admin Administrator
  @ejb:permission Teller
  @ejb:transaction Required
  @ejb:use-soft-locking
  @ejb:data-object container false
  @jboss:table-name model
  @jboss:create-table true
  @jboss:remove-table true
  @jboss:tuned-updates true
  @jboss:read-only false
  @jboss:container-configuration Standard CMP
 
  @version 0.01
  @author <a href="mailto:volz@aifb.uni-karlsruhe.de">Raphael Volz</a>
*/
public abstract class ModelBean {
	
	protected transient EntityContext ctx;

// EJB Required -------------------------------------------
	
	public void setEntityContext(javax.ejb.EntityContext ctx)
	{
		this.ctx = ctx;
	}

	protected EntityContext getEntityContext() {
		return ctx;
	}
	
// DATA FIELDS ------------------------------------------
	protected transient Resource default_uri; 
	/**
		Returns the default uri of this model
		@ejb:persistent-field
		@ejb:transaction Supports
		@jboss:column-name uri
	*/
	public abstract int getDefUri();
	public abstract void setDefUri(int resource_id);
	
	/**
		@ejb:remote-method
		@ejb:transaction Supports
		Returns the default URI of this model, throws exception if this doesn't exist
	*/
	public Resource getDefaultUri() throws java.util.NoSuchElementException {
		if(isModified()) {
			ResourceHome home = getResourceHome();
			if(getDefUri() > 0)
				default_uri = home.findByPrimaryKey(new ResourcePK(getDefUri()));
			else 
				throw new java.util.NoSuchElementException();
		}		
		return default_uri;
	}
	
	/**
		Sets the default URI of this model.
		@ejb:remote-method
		@ejb:transaction Supports
	*/
	public void setDefaultUri(Resource uri) {
		setDefUri(((ResourcePK) uri.getPrimaryKey()).hash);
		default_uri = uri;
	}
	
	/**
		Returns the alias of this model
		@ejb:remote-method
		@ejb:persistent-field
		@ejb:pk-field
		@ejb:transaction Supports
		@jboss:column-name uri
	*/
	public abstract String getAlias();
	public abstract void setAlias(String alias);
	
// --- CONSTRUCTORS ---------------------------------------------------
	
	public ModelPK ejbCreate(String alias) throws CreateException {
		setAlias(alias);
		setDefUri(-1);
		return null;
	}
	
	public ModelPK ejbCreate(String alias, Resource uri) throws CreateException {
		setAlias(alias);
		setDefUri(((ResourcePK) uri.getPrimaryKey()).hash);
		this.default_uri = uri;
		return null;
	}
	
	public void ejbPostCreate(String alias) throws CreateException {}
	public void ejbPostCreate(String alias, Resource uri) throws CreateException {}

// --- HELPER METHODS ---------------------------------------------------
	
		/**
		Is implemented by the Doclet generated Class
	*/
	public abstract boolean isModified();

	protected EJBHome findHome(String homeName) {
		Context initCtx = new InitialContext(ctx.getEnvironment());
		return home = initCtx.lookup(homeName);
	}

	protected ResourceHome getResourceHome() {
		return (ResourceHome) findHome(ResourceHome.JNDI_NAME);
	}
	
	protected StatementHome getStatementHome() {
		return (StatementHome) findHome(StatementHome.JNDI_NAME);
	}
	/**
		@ejb:remote-method
		@ejb:transaction Supports
		Checks, whether the given Statement is contained in this Model
	*/
	public boolean contains(Statement stmt) {
		return this.equals(stmt.getModel());
	}
	
	/**
		TO DO Effizient implementieren !!!
		@return Collection[Statement] all statements matching the criteria
		@ejb:remote-method
	*/
	public Collection find(Resource subj, Resource pred, RemoteNode obj) {
		if((subj == null) && (pred == null) && (obj == null)) return
			getStatements();
		if((pred == null) && (obj== null)) return findSubj(subj);
		if((subj == null) && (obj==null)) return findPred(pred);
		if((subj == null) && (pred == null)) return findObj(obj);
		if(subj == null) return findPredObj(pred, obj);
		if(pred == null) return findSubjObj(subj, obj);
		if(obj == null) return findSubjPred(subj, pred);
		
		// Nichts ist null
		StatementHome home = getStatementHome();
		ResourcePK subjKey = subj.getPrimaryKey();
		ResourcePK predKey = pred.getPrimaryKey();
		RemoteNodePK objKey = obj.getPrimaryKey();
		Statement result = home.findByPrimaryKey(new StatementPK(getAlias(), subjKey.gethash(),
							    predKey.gethash(), objKey.gethash()));
		java.util.ArrayList list = new java.util.ArrayList();
		list.add(result);
		return list;		
	}
	
	private Collection findSubj(Resource subj) {
		ResourcePK subjKey = subj.getPrimaryKey();
		Integer key = new Integer(subjKey.getHash());
		StatementHome home = getStatementHome();
		return home.findByModelSubject(getAlias(), key);
	}
	
	private Collection findPred(Resource pred) {
		ResourcePK predKey = pred.getPrimaryKey();
		Integer key = new Integer(predKey.getHash());
		StatementHome home = getStatementHome();
		return home.findByModelPredicate(getAlias(), key);
	}
	private Collection findObj(RemoteNode obj) {
		ResourcePK objKey = obj.getPrimaryKey();
		Integer key = new Integer(objKey.getHash());
		StatementHome home = getStatementHome();
		return home.findByModelPredicate(getAlias(), key, (RemoteNode instanceof Literal));
	}
	
	private Collection findPredObj(Resource pred, RemoteNode obj) {
		ResourcePK predKey = pred.getPrimaryKey();
		ResourcePK objKey = obj.getPrimaryKey();
		Integer o_key = new Integer(objKey.getHash());
		Integer p_key = new Integer(predKey.getHash());
		StatementHome home = getStatementHome();
		return home.findByModelPredObj(getAlias(), p_key, o_key, (RemoteNode instanceof Literal));
	}
	private Collection findSubjObj(Resource subj, RemoteNode obj) {
		ResourcePK subjKey = subj.getPrimaryKey();
		ResourcePK objKey = obj.getPrimaryKey();
		Integer o_key = new Integer(objKey.getHash());
		Integer s_key = new Integer(subjKey.getHash());
		StatementHome home = getStatementHome();
		return home.findByModelPredObj(getAlias(), s_key, o_key, (RemoteNode instanceof Literal));
	}
	private Collection findSubjPred(Resource subj, Resource pred) {
		ResourcePK subjKey = subj.getPrimaryKey();
		ResourcePK predKey =pred.getPrimaryKey();
		Integer p_key = new Integer(predKey.getHash());
		Integer s_key = new Integer(subjKey.getHash());
		StatementHome home = getStatementHome();
		return home.findByModelPredObj(getAlias(), s_key, p_key);
	}
	
	/**
		@ejb:remote-method
		@ejb:transaction Supports
		Adds a new Statement with the given [subj, pred, obj] to this model
	*/
	public void add(Resource subj, Resource pred, RemoteNode obj) {
		StatementHome home = getStatementHome();
		home.create(this, subj, pred, obj);
	}
	
	/**
		@ejb:remote-method
		@ejb:transaction Supports
		Removes the given Statement [stmt]
	*/
	public void remove(Statement stmt) {
		stmt.remove();
	}
	
	
	/**
		@ejb:remote-method
		@ejb:transaction Supports
		@return all statements contained in this model
	*/
	public Collection getStatements() {
		StatementHome home = getStatementHome();
		return home.findByModel(getAlias());
	}
}
