package de.hsadmin.core.model;

import java.lang.reflect.Field;
import java.util.List;
import java.util.regex.Pattern;

import de.hsadmin.core.util.ReflectionUtil;

public class GenericModuleImpl implements ModuleInterface {

	private Transaction tx;
	
	public GenericModuleImpl(Transaction transaction) {
		tx = transaction;
	}
	
	public Transaction getTransaction() {
		return tx;
	}

	@Override
	public AbstractEntity initialize(AbstractEntity newEntity) throws HSAdminException {
		AbstractModuleImpl wrapper = 
			EntitySessionHelper.createEntitySessionWrapper(newEntity.getClass(), tx);
		return wrapper.initialize(newEntity);
	}

	@Override
	public AbstractEntity add(AbstractEntity newEntity) throws HSAdminException {
		validateFields(newEntity);
		if (!newEntity.isNew())
			throw new HSAdminException("cannot add an already persistent entity");
		AbstractModuleImpl wrapper = 
			EntitySessionHelper.createEntitySessionWrapper(newEntity.getClass(), tx);
		return wrapper.add(newEntity);
	}

	@Override
	public AbstractEntity find(Class<? extends AbstractEntity> entityClass, Object key) throws HSAdminException {
		AbstractModuleImpl wrapper = EntitySessionHelper.createEntitySessionWrapper(entityClass, tx);
		return wrapper.find(entityClass, key);
	}

	@Override
	public AbstractEntity findByString(Class<? extends AbstractEntity> entityClass, String key) throws HSAdminException {
		AbstractModuleImpl wrapper = EntitySessionHelper.createEntitySessionWrapper(entityClass, tx);
		return wrapper.findByString(entityClass, key);
	}

	@Override
	public List<AbstractEntity> search(Class<? extends AbstractEntity> entityClass, String condition, String orderBy) throws HSAdminException {
		AbstractModuleImpl wrapper = EntitySessionHelper.createEntitySessionWrapper(entityClass, tx);
		return wrapper.search(entityClass, condition, orderBy);
	}

	@Override
	public AbstractEntity update(AbstractEntity existingEntity) throws HSAdminException {
		validateFields(existingEntity);
		if (existingEntity.isNew())
			return add(existingEntity);
		AbstractModuleImpl wrapper = EntitySessionHelper.createEntitySessionWrapper(existingEntity.getClass(), tx);
		return wrapper.update(existingEntity);
	}

	@Override
	public void delete(AbstractEntity existingEntity) throws HSAdminException {
		AbstractModuleImpl wrapper = 
			EntitySessionHelper.createEntitySessionWrapper(existingEntity.getClass(), tx);
		wrapper.delete(existingEntity);
	}

	private void validateFields(AbstractEntity anEntity) throws HSAdminException {
		Class<? extends AbstractEntity> clasz = anEntity.getClass();
		validateAllFields(clasz, anEntity);
		// Bei Datenbanken und DB-Usern stehen die Attribute in der Oberklasse
		Class<?> superclass = clasz.getSuperclass();
		if (superclass != AbstractEntity.class) {
			validateAllFields(superclass, anEntity);
		}
	}

	private void validateAllFields(Class<?> clasz, AbstractEntity anEntity)
			throws HSAdminException {
		for (Field f : clasz.getDeclaredFields()) {
			AnnFieldIO fieldValidation = f.getAnnotation(AnnFieldIO.class);
			if (fieldValidation != null) {
				try {
					Object valueObject = ReflectionUtil.invokeGetter(anEntity, clasz, f);
					if (valueObject instanceof String) {
						if (!Pattern.matches(fieldValidation.validation(), (String) valueObject)) {
							throw new HSAdminException("validation of field " + f.getName() + " failed, pattern: " + fieldValidation.validation());
						}
					}
				} catch (Exception e) {
					throw new HSAdminException(e);
				}
			}
		}
	}

}
