package de.hsadmin.mods.email;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import de.hsadmin.core.model.AbstractEntity;
import de.hsadmin.core.qserv.CompoundProcessor;
import de.hsadmin.core.qserv.EntityProcessorFactory;
import de.hsadmin.core.qserv.Processor;
import de.hsadmin.core.qserv.ShellProcessor;
import de.hsadmin.core.qserv.WaitingTasksProcessor;
import de.hsadmin.core.util.Config;
import de.hsadmin.mods.pac.Pac;

public class EMailAddressProcessorFactory implements EntityProcessorFactory {
	
	public <T extends AbstractEntity> Processor createCreateProcessor(EntityManager em, T entity) {
		// TODO: combine both keys in a single call (optimization)
		EMailAddress email = (EMailAddress) entity;
		Pac pac = email.getDomain().getUser().getPac();
		CompoundProcessor cp = new CompoundProcessor();
		cp.appendProcessor(new ShellProcessor( "postmap -r -i /etc/postfix-mailin/virtual",
				email.getFullDomain() + " -" ) );
		cp.appendProcessor(new ShellProcessor( "postmap -r -i /etc/postfix-mailin/virtual",
				email.getEMailAddress() + " " + email.getTarget() ) );
		if (emailAddressCount(em, email) < 2) {
			WaitingTasksProcessor waitingTasksProcessor = new WaitingTasksProcessor(cp);
			String domName = email.getDomain().getName();
			Config config = Config.getInstance();
			for (String queueName : config.getProperty("queues.mail").split(",")) {
				waitingTasksProcessor.appendProcessor(queueName, createMailinSetupProcessor(domName, pac), queueName + ".hostsharing.net");
			}
			return waitingTasksProcessor;
		} else {
			return cp;
		}
	}
	
	public <T extends AbstractEntity> Processor createUpdateProcessor(EntityManager em, T entity) {
		// TODO: if update is specified by primary-key or DB query instead of OID,
		// 	a  postmap -d might be neccessary 
		return createCreateProcessor(em, entity);
	}
	
	public <T extends AbstractEntity> Processor createDeleteProcessor(EntityManager em, T entity) {
		CompoundProcessor cp = new CompoundProcessor();
		EMailAddress email = (EMailAddress) entity;
		cp.appendProcessor( 
				new ShellProcessor( "postmap -d '" + email.getEMailAddress() + "' /etc/postfix-mailin/virtual" ) );
		int emailAddressCount = emailAddressCount(em, email);
		if (emailAddressCount == 0) {
			// remove the domain from virtual.db
			String fullDomain = email.getFullDomain();
			cp.appendProcessor( 
					new ShellProcessor( "postmap -d '" + fullDomain + "' /etc/postfix-mailin/virtual" ) );
			WaitingTasksProcessor waitingTasksProcessor = new WaitingTasksProcessor(cp);
			Config config = Config.getInstance();
			for (String queueName : config.getProperty("queues.mail").split(",")) {
				waitingTasksProcessor.appendProcessor(queueName, createMailinDeleteProcessor(fullDomain), queueName + ".hostsharing.net");
			}
			return waitingTasksProcessor;
		} else {
			return cp;
		}
	}

	private int emailAddressCount(EntityManager em, EMailAddress email) {
		Query query;
		if ( email.getSubdomain() != null ) {
			query = em.createQuery("SELECT e FROM EMailAddresses e WHERE e.subdomain=:subdomain AND e.domain=:domain");
			query.setParameter("subdomain", email.getSubdomain());
		}
		else {
			query = em.createQuery("SELECT e FROM EMailAddresses e WHERE ( e.subdomain IS NULL OR e.subdomain = '' ) AND e.domain=:domain");
		}
		query.setParameter("domain", email.getDomain());
		List<?> result = query.getResultList();
		if (result == null) {
			return 0;
		}
		return result.size();
	}

	private Processor createMailinSetupProcessor(String domName, Pac pac) {
		String inetAddr = pac.getCurINetAddr().getInetAddr();
		return
			new ShellProcessor("postmap -r -i /etc/postfix-mailin/transport", 
						domName + " smtp:" + inetAddr + ":225\n" +
						"." + domName + " smtp:" + inetAddr + ":225\n");
	}

	private Processor createMailinDeleteProcessor(String domName) {
		return new ShellProcessor(
				"postmap -d '" + domName + "' /etc/postfix-mailin/transport && " +
				"postmap -d '." + domName + "' /etc/postfix-mailin/transport");
	}

}
