package de.hsadmin.mods.dom;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

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.CopyFileProcessor;
import de.hsadmin.core.qserv.CreateFileProcessor;
import de.hsadmin.core.qserv.EntityProcessorFactory;
import de.hsadmin.core.qserv.Processor;
import de.hsadmin.core.qserv.ProcessorException;
import de.hsadmin.core.qserv.ShellProcessor;
import de.hsadmin.core.qserv.TemplateProcessor;
import de.hsadmin.core.qserv.WaitingTasksProcessor;
import de.hsadmin.mods.email.EMailAddress;
import de.hsadmin.mods.email.EMailAddressProcessorFactory;
import de.hsadmin.mods.pac.Pac;
import de.hsadmin.mods.user.UnixUser;

public class DomainProcessorFactory implements EntityProcessorFactory {

	/**
	 * @return a Processor which creates a domain
	 * @throws ProcessorException 
	 */
	public <T extends AbstractEntity> Processor createCreateProcessor(EntityManager em, T entity) throws ProcessorException {
		String hiveName = entity.getHiveName();
		Domain dom = (Domain) entity;
		UnixUser domUser = dom.getUser();
		Pac pac = domUser.getPac();
		String domName = dom.getName();
		String zonefileTargetPath = "/etc/bind/pri." + domName;
		Map<String, String> templateVars = new HashMap<String, String>();
		templateVars.put("SIO", Long.toString(System.currentTimeMillis()/1000L));
		templateVars.put("DOM_HOSTNAME", domName);
		templateVars.put("PAC_HOSTNAME", pac.getName() + ".hostsharing.net");
		templateVars.put("DOM_IPNUMBER", pac.getCurINetAddr().getInetAddr());
		Processor zonefileTemplateProcessor = 
			new TemplateProcessor("/de/hsadmin/mods/dom/zonefile.jtpl", templateVars, zonefileTargetPath, false);
		Processor zonefileACLProcessor = 
			new ShellProcessor("chown root:bind " + zonefileTargetPath + " && chmod 644 " + zonefileTargetPath);
		Processor prizonesFileProcessor = 
			new ShellProcessor("echo 'zone \"" + domName + "\" { type master; file \"pri." + domName + "\"; };' >>/etc/bind/named.pri-zones" +
				" && sort /etc/bind/named.pri-zones | uniq >/etc/bind/named.pri-zones.tmp" +
				" && mv /etc/bind/named.pri-zones.tmp /etc/bind/named.pri-zones");
		String hiveInetAddr = pac.getHive().getInetAddr().getInetAddr();
		Processor dnsReloadProcessor = new ShellProcessor("invoke-rc.d bind9 reload");
		EMailAddressProcessorFactory eMailAddressProcessorFactory = new EMailAddressProcessorFactory();
		Processor dnsSetupProcessor = 
			new CompoundProcessor(zonefileTemplateProcessor, zonefileACLProcessor, prizonesFileProcessor, dnsReloadProcessor);
		WaitingTasksProcessor mainProcessor = new WaitingTasksProcessor(dnsSetupProcessor);
		CompoundProcessor emailAdrProcessor = new CompoundProcessor();
		Query query = em.createQuery("SELECT adr FROM " + EMailAddress.class.getAnnotation(javax.persistence.Entity.class).name() 
			+ " adr WHERE adr.domain.name='" + domName + "'");
		List<?> resultList = query.getResultList();
		for (Object obj : resultList) {
			EMailAddress eMailAddress = (EMailAddress) obj;
			emailAdrProcessor.appendProcessor(eMailAddressProcessorFactory.createCreateProcessor(em, eMailAddress));
		}
		mainProcessor.appendProcessor(hiveName, emailAdrProcessor, "Setup EMail");
		Processor seczonesFileProcessor = null; 
		String[] dnsServerQueues = { "dns1", "dns2", "dns3" };
		for (String queueName : dnsServerQueues) {
			seczonesFileProcessor = 
				new ShellProcessor("echo 'zone \"" + domName + "\" { type slave; file \"sec." + domName + "\"; masters { " + hiveInetAddr + "; }; };' >>/etc/bind/named-hsh.conf" +
					" && sort /etc/bind/named-hsh.conf | uniq >/etc/bind/named-hsh.conf.tmp" +
					" && mv /etc/bind/named-hsh.conf.tmp /etc/bind/named-hsh.conf" +
			        " && invoke-rc.d bind9 reload");
			mainProcessor.appendProcessor(queueName, seczonesFileProcessor, queueName + ".hostsharing.net");
		}
		
		Processor relayDomainsProcessor = null;
		String[] mailServerQueues = { "mail1", "mail2", "mail3" };
		for (String queueName : mailServerQueues) {
			relayDomainsProcessor = new CompoundProcessor(
				new ShellProcessor("postmap -r -i /etc/postfix-mailin/relaydomains", 
							domName + " anything\n" +
							"." + domName + " anything\n"), 
				new ShellProcessor("postmap -r -i /etc/postfix-mailin/transport", 
							domName + " smtp:[" + pac.getName() + ".hostsharing.net]\n" +
							"." + domName + " smtp:[" + pac.getName() + ".hostsharing.net]\n")
			);
			mainProcessor.appendProcessor(queueName, relayDomainsProcessor, queueName + ".hostsharing.net");
		}
		
		Processor backupMXSMTPTransportsProcessor =
			new ShellProcessor("echo " + domName + " >> /etc/postfix/relaydomains" +
					" && invoke-rc.d postfix reload");
		mainProcessor.appendProcessor("backupmx", backupMXSMTPTransportsProcessor, "backupmx.hostsharing.net");
		String domsDir = domUser.getHomedir() + "/doms";
		String domainDir = domsDir + "/" + dom.getName();
		String[] subDirs = new String[] { "htdocs", "htdocs-ssl", "subs", "subs/www", "subs-ssl", "subs-ssl/www", "cgi", "fastcgi", "cgi-ssl", "fastcgi-ssl", "etc", "var" };
		String pacName = pac.getName();
		String userName = domUser.getName();
		Processor mkDomainDirProzessor = 
			new ShellProcessor(
					"mkdir --mode=1550 --parents " + domsDir + " && " +
					"chown httpd:" + pacName + " " + domsDir + " && " +
					"mkdir --mode=750 " + domainDir + " && " +
					"chown " + userName + ":httpd " + domainDir 
					);
		CompoundProcessor domDirsProcessor = new CompoundProcessor(mkDomainDirProzessor);
		for (String subDir : subDirs) {
			domDirsProcessor.appendProcessor(new ShellProcessor(
					"mkdir --mode=755 " + domainDir + "/" + subDir + " && " +
					"chown " + userName + ":" + pacName +  " " + domainDir + "/" + subDir
				));
		}
		templateVars = new HashMap<String, String>();
		templateVars.put("DOMAIN", domName);
		templateVars.put("USER_NAME", domUser.getComment());
		templateVars.put("PROTOCOL", "http");
		domDirsProcessor.appendProcessor(
				new CreateFileProcessor("/de/hsadmin/mods/dom/htaccess.jtpl", templateVars, domainDir + "/htdocs/.htaccess", userName, pacName, "644")
			);
		templateVars.put("PROTOCOL", "https");
		domDirsProcessor.appendProcessor(
				new CreateFileProcessor("/de/hsadmin/mods/dom/htaccess.jtpl", templateVars, domainDir + "/htdocs-ssl/.htaccess", userName, pacName, "644")
			);
		domDirsProcessor.appendProcessor(
				new CreateFileProcessor("/de/hsadmin/mods/dom/index.html.jtpl", templateVars, domainDir + "/subs/www/index.html", userName, pacName, "644")
			);
		domDirsProcessor.appendProcessor(
				new CreateFileProcessor("/de/hsadmin/mods/dom/index.html.jtpl", templateVars, domainDir + "/subs-ssl/www/index.html", userName, pacName, "644")
			);
		domDirsProcessor.appendProcessor(
				new CreateFileProcessor("/de/hsadmin/mods/dom/test.cgi.jtpl", templateVars, domainDir + "/cgi/test.cgi", userName, pacName, "755")
			);
		domDirsProcessor.appendProcessor(
				new CreateFileProcessor("/de/hsadmin/mods/dom/test.cgi.jtpl", templateVars, domainDir + "/cgi-ssl/test.cgi", userName, pacName, "755")
			);
		domDirsProcessor.appendProcessor(
				new CopyFileProcessor("/usr/local/src/phpstub/phpstub", domainDir + "/fastcgi/phpstub", userName, pacName, "755")
			);
		domDirsProcessor.appendProcessor(
				new CopyFileProcessor("/usr/local/src/phpstub/phpstub", domainDir + "/fastcgi-ssl/phpstub", userName, pacName, "755")
		);
		domDirsProcessor.appendProcessor(
				new ShellProcessor("ln -s " + domainDir + " /home/doms/ && " +
						"chown --no-dereference " + userName + ":" + pacName + " /home/doms/" + domName 
						 + " && " + "chown " + userName + ":httpd /home/doms/" + domName + "/")
			);
		mainProcessor.appendProcessor(hiveName, domDirsProcessor, "Setup doms/" + domName + "-Directory");
		
		Processor domSetupProcessor = 
			new ShellProcessor("mk-httpd-conf " + pacName + " && invoke-rc.d apache2 reload >/dev/null 2>&1");
		mainProcessor.appendProcessor(hiveName, domSetupProcessor, "Setup Apache VHost");
		return mainProcessor;
	}

	/**
	 * @return a Processor which updates a domain
	 */
	public <T extends AbstractEntity> Processor createUpdateProcessor(EntityManager em, T entity) {
		return null;
	}

	/**
	 * @return a Processor which deletes a domain
	 */
	public <T extends AbstractEntity> Processor createDeleteProcessor(EntityManager em, T entity) {
		Domain dom = (Domain) entity;
		String domName = dom.getName();
		ShellProcessor emailAddressRemoveProcessor = new ShellProcessor("for KEY in $(postmap -s /etc/postfix/virtual|grep " + domName + "|cut -f1); do postmap -d $KEY /etc/postfix/virtual; done");
		ShellProcessor dnsRemoveRemoveProcessor = 
			new ShellProcessor("grep -v pri." + domName + " /etc/bind/named.pri-zones > /etc/bind/named.pri-zones.tmp" +
				" && mv /etc/bind/named.pri-zones.tmp /etc/bind/named.pri-zones" +
				" && rm /etc/bind/pri." + domName +
				" && invoke-rc.d bind9 reload");
		WaitingTasksProcessor mainProcessor = new WaitingTasksProcessor(new CompoundProcessor(emailAddressRemoveProcessor, dnsRemoveRemoveProcessor));

		Processor seczonesFileProcessor = null; 
		String[] dnsQueues = { "dns1", "dns2", "dns3" }; 
		for (String queueName : dnsQueues) {
			seczonesFileProcessor =
				new ShellProcessor("grep -v sec." + domName + " /etc/bind/named-hsh.conf >/etc/bind/named-hsh.conf.tmp" +
						" && mv /etc/bind/named-hsh.conf.tmp /etc/bind/named-hsh.conf" +
						" && rm /var/cache/bind/sec." + domName + 
						" && invoke-rc.d bind9 reload");
			mainProcessor.appendProcessor(queueName, seczonesFileProcessor, queueName + ".hostsharing.net");
		}
		
		Processor mailQueueProcessor = null; 
		String[] mailServerQueues = { "mail1", "mail2", "mail3" };
		for (String queueName : mailServerQueues) {
			mailQueueProcessor = new ShellProcessor("postmap -d '" + domName + "' /etc/postfix-mailin/relaydomains && " +
					"postmap -d '" + domName + "' /etc/postfix-mailin/transport && " +
					"postmap -d '." + domName + "' /etc/postfix-mailin/relaydomains && " +
					"postmap -d '." + domName + "' /etc/postfix-mailin/transport");
			mainProcessor.appendProcessor(queueName, mailQueueProcessor, queueName + ".hostsharing.net");
		}
		
		Processor vhostDelProcessor = 
			new ShellProcessor("rm /home/doms/" + domName +
				" && rm -rf " + dom.getUser().getHomedir() + "/doms/" + domName +
				" && rm /etc/apache2/sites-generated/" + domName +
				" && rm /etc/apache2/sites-*/`ls -1 /etc/apache2/sites-enabled/ | egrep \"^[01]+-" + domName + "$\"`" +
				" && invoke-rc.d apache2 reload >/dev/null 2>&1");
		mainProcessor.appendProcessor(dom.getHiveName(), vhostDelProcessor, "remove apache vhost");
		
		Processor backupMXSMTPRelayDelProcessor = 
			new ShellProcessor("grep -v " + domName + " /etc/postfix/relaydomains > /etc/postfix/relaydomains.tmp" +
				" && mv /etc/postfix/relaydomains.tmp /etc/postfix/relaydomains" +
				" && invoke-rc.d postfix reload");
		mainProcessor.appendProcessor("backupmx", backupMXSMTPRelayDelProcessor, "backupmx.hostsharing.net");
		return mainProcessor;
	}

}
