package de.hsadmin.core.model;

import java.util.LinkedList;
import java.util.List;

/**
 *  allows access only for hostmasters, used as fallback wrapper.
 */
public class SecureDefaultModuleImpl extends AbstractModuleImpl {
	
	private static final long serialVersionUID = 4567381515459292565L;

	@Override
	public AbstractEntity initialize(AbstractEntity newEntity) throws AuthorisationException {
		return super.initialize(newEntity);
	}

	@Override
	public AbstractEntity find(Class<? extends AbstractEntity> entityClass, Object key) throws HSAdminException {
		AbstractEntity entity = super.find(entityClass, key);
		if (entity != null && !entity.isReadAllowedFor(getLoginUser()))
			throw new AuthorisationException(getLoginUser(), "find");
		return entity;
	}

	@Override
	public AbstractEntity findByString(Class<? extends AbstractEntity> entityClass, String key) throws HSAdminException {
		AbstractEntity entity = super.findByString(entityClass, key);
		if (entity != null && !entity.isReadAllowedFor(getLoginUser()))
			throw new AuthorisationException(getLoginUser(), "findByString");
		return entity;
	}

	@Override
	public List<AbstractEntity> search(Class<? extends AbstractEntity> entityClass, String condition, String orderBy) 
			throws HSAdminException {
		// restrict query to entities where the loginUser could have rights on
		SearchFilter filterAnnot;
		if (!getLoginUser().hasHostmasterRole()
				&& (filterAnnot = getSecurityFilterAnnotation(entityClass)) != null) {
			String securityCondition = filterAnnot.value();
			if (condition != null && condition.length() > 0)
				condition = "(" + condition + ")" + " AND ( "
						+ securityCondition + ")";
			else
				condition = securityCondition;
		}

		// do query
		List<AbstractEntity> res = super.search(entityClass, condition, orderBy);
		List<AbstractEntity> ret = new LinkedList<AbstractEntity>();

		// remove entities where login user has no access rights
		if (res != null) {
			for (AbstractEntity entity : res) {
				AbstractEntity returnedEntity = entity;
				if (returnedEntity.isReadAllowedFor(getLoginUser()))
					ret.add(returnedEntity);
			}
		}

		// return clean result
		return ret;

	}

	// helper method to get annotation from class or superclass
	private SearchFilter getSecurityFilterAnnotation(Class<?> entityClass) {
		SearchFilter ret;
		while (entityClass != null) {
			ret = (SearchFilter) entityClass.getAnnotation(SearchFilter.class);
			if (ret != null)
				return ret;
			entityClass = entityClass.getSuperclass();
		}
		return null;
	}

	@Override
	public AbstractEntity add(AbstractEntity newEntity) throws HSAdminException {
		// access rights checking is done by base class
		return super.add(newEntity);
	}

	@Override
	public AbstractEntity update(AbstractEntity existingEntity) throws HSAdminException {
		// access rights checking is done by base class
		return super.update(existingEntity);
	}

	@Override
	public void delete(AbstractEntity detachedEntity) throws HSAdminException {
		// get the entity from the database
		AbstractEntity attachedEntity = getTransaction().getEntityManager().find(detachedEntity.getClass(),
				detachedEntity.id());

		// does the login user have the right to delete?
		if (!attachedEntity.isWriteAllowedFor(getLoginUser()))
			throw new AuthorisationException(getLoginUser(), "delete",
					detachedEntity);

		super.delete(attachedEntity);
	}

}
