package de.hsadmin.mods.pac;

import java.util.Set;

import javax.persistence.EntityManager;

import de.hsadmin.core.model.AbstractEntity;
import de.hsadmin.core.qserv.CompoundProcessor;
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.VelocityProcessor;
import de.hsadmin.core.qserv.WaitingTasksProcessor;
import de.hsadmin.core.util.PasswordTool;
import de.hsadmin.mods.user.UnixUser;


public class PacProcessorFactory implements EntityProcessorFactory {

	@Override
	public <T extends AbstractEntity> Processor createCreateProcessor(
			EntityManager em, T entity) throws ProcessorException {
		Pac pac = (Pac) entity;
		String pacName = pac.getName();
		Hive hive = pac.getHive();
		UnixUser unixUser = getPacAdminUser(pac);
		String password = PasswordTool.generatePassword();
		Processor priProcessor = new CompoundProcessor(
				createAddUserProc(pacName, unixUser, password), 
				createSetQuotaProc(pac),
				createEtcHostsProc(hive), 
				createNetworkInterfacesProc(hive),
				createIPTablesProc(),
				createSudouersProc(hive), 
				createProftpdConfProc(hive), 
				createMakePacDirectoryStructure(unixUser),
				createIfUp(pacName),
				createHttpdVirtualProc(hive),
				createAccountingRulesProc());
		WaitingTasksProcessor secProcessor = new WaitingTasksProcessor(priProcessor);
		return secProcessor;
	}

	private Processor createAccountingRulesProc() {
		return new ShellProcessor("mk-iptables-rules Accounting");
	}

	private Processor createHttpdVirtualProc(Hive hive) throws ProcessorException {
		Processor domSetupProcessor = new CompoundProcessor(
				new CreateFileProcessor("/de/hsadmin/mods/pac/httpd-virtual.vm", hive, 
						"/etc/apache2/virtual.conf.tmp", "root", "root", "644", true),
				new ShellProcessor("for PEM in $( cat /etc/apache2/virtual.conf.tmp | grep SSLCertificateFile | cut -c24- ); do " +
						"ls $PEM >/dev/null 2>&1 || ( " +
						" sed -i \"/SSLCertificateFile.*${PEM:18}/c \\\n" +
						"\\ \\ \\ \\ SSLCertificateFile \\/etc\\/apache2\\/pems\\/default.pem\" /etc/apache2/virtual.conf.tmp && " +
						" sed -i \"/SSLCertificateChainFile.*${PEM:18:5}.chain.pem/c \\\n" +
						"\\ \\ \\ \\ SSLCertificateChainFile \\/etc\\/apache2\\/pems\\/default.chain.pem\" /etc/apache2/virtual.conf.tmp " +
						"); " +
						"done"),
				new ShellProcessor("for PEM in $( cat /etc/apache2/virtual.conf.tmp | grep SSLCertificateChainFile | cut -c29- ); do " +
						"ls $PEM >/dev/null 2>&1 || " +
						" sed -i \"/SSLCertificateChainFile.*${PEM:18:5}.chain.pem/d \" /etc/apache2/virtual.conf.tmp ; " +
						"done"),
				new ShellProcessor("(diff -q /etc/apache2/virtual.conf.tmp /etc/apache2/virtual.conf"
								+ " && rm /etc/apache2/virtual.conf.tmp )"
								+ " || ( mv /etc/apache2/virtual.conf.tmp /etc/apache2/virtual.conf " 
								+ " && invoke-rc.d apache2 reload >/dev/null 2>&1 ) "));
		return domSetupProcessor;
	}

	@Override
	public <T extends AbstractEntity> Processor createUpdateProcessor(EntityManager em, T entity) 
			throws ProcessorException {
		Pac pac = (Pac) entity;
		return createSetQuotaProc(pac);
	}

	@Override
	public <T extends AbstractEntity> Processor createDeleteProcessor(EntityManager em, T entity) throws ProcessorException {
		Pac pac = (Pac) entity;
		Hive hive = pac.getHive();
		WaitingTasksProcessor waiting = new WaitingTasksProcessor(createDelUserProc(pac.getName()));
		waiting.appendProcessor(pac.getHiveName(), new CompoundProcessor(
				createIfDown(pac.getName()),
				createEtcHostsProc(hive), 
				createNetworkInterfacesProc(hive), 
				createSudouersProc(hive), 
				createProftpdConfProc(hive),
		        createHttpdVirtualProc(hive),
		        createAccountingRulesProc()), "remove packet");
		return waiting;
	}

	private Processor createEtcHostsProc(Hive hive) throws ProcessorException {
		return new VelocityProcessor("/de/hsadmin/mods/pac/hosts.vm", hive, "/etc/hosts", true);
	}

	private Processor createNetworkInterfacesProc(Hive hive) throws ProcessorException {
		return new VelocityProcessor("/de/hsadmin/mods/pac/interfaces.vm", hive, "/etc/network/interfaces", true);
	}

	private Processor createIPTablesProc() {
		return new ShellProcessor("mk-iptables-rules Accounting");
	}

	private Processor createSudouersProc(Hive hive) throws ProcessorException {
		return new VelocityProcessor("/de/hsadmin/mods/pac/sudoers.vm", hive, "/etc/sudoers", true);
	}

	private Processor createProftpdConfProc(Hive hive) throws ProcessorException {
		return new VelocityProcessor("/de/hsadmin/mods/pac/proftpd-conf.vm", hive, "/etc/proftpd/proftpd.conf", true);
	}

	private Processor createAddUserProc(String pacName, UnixUser unixUser, String password) {
		return new ShellProcessor(
				"newusers", pacName + ":" + password  + ":"
						+ unixUser.getUserId() + ":" + unixUser.getUserId()
						+ ":" + unixUser.getComment() + ":" + unixUser.getHomedir()
						+ ":" + unixUser.getShell() + "\n");
	}

	private Processor createSetQuotaProc(Pac pac) {
		int quota = 128;
		Set<PacComponent> pacComponents = pac.getPacComponents();
		for (PacComponent pacComponent : pacComponents) {
			BaseComponent baseComponent = pacComponent.getBaseComponent();
			String feature = baseComponent.getFeature();
			if ("QUOTA".equals(feature)) {
				quota = pacComponent.getQuantity();
			}
		}
		int blocksSoft = quota * 1024;
		int blocksHard = quota * 1024 * 2;
		int inodesSoft = blocksSoft / 4;
		int inodesHard = blocksHard / 4;
		return new ShellProcessor("setquota -g " + pac.getName() + " " 
				+ blocksSoft + " " + blocksHard + " " 
				+ inodesSoft + " " + inodesHard + " "
				+ "`df /home/pacs/ | tail -n1 | cut -d' ' -f1`");
	}

	private Processor createDelUserProc(String pacName) {
		return new ShellProcessor("rm -rf /home/pacs/" + pacName + "/* && deluser --remove-all-files " + pacName + ">/dev/null 2>&1");
	}

	private Processor createMakePacDirectoryStructure(UnixUser unixUser) {
		String homedir = unixUser.getHomedir();
		String username = unixUser.getName();
		return new ShellProcessor("chmod 711 " + homedir + " && " +
				"su -l " + username + " -s \"/bin/bash\" -c \"mkdir -p " +
				homedir + "/.bak " +
				homedir + "/doms " + 
				homedir + "/etc " +
				homedir + "/users " + 
				homedir + "/var " + 
				"\" && " +
				"chmod 0700 " + homedir + "/.bak && " +
				"chown httpd " + homedir + "/doms && " +
				"chmod 1550 " + homedir + "/doms && " +
				"chmod 2700 " + homedir + "/etc && " +
				"chmod 2750 " + homedir + "/var && " +
				"chmod 2755 " + homedir + "/users"
				);
	}

	private Processor createIfUp(String pacName) {
		return new ShellProcessor("ifup eth0:" + pacName);
	}

	private Processor createIfDown(String pacName) {
		return new ShellProcessor("ifdown eth0:" + pacName);
	}

	private UnixUser getPacAdminUser(Pac pac) throws ProcessorException {
		UnixUser unixUser = null;
		Set<UnixUser> unixUserSet = pac.getUnixUser();
		if (unixUserSet.size() == 1) {
			unixUser = unixUserSet.iterator().next();
		} else {
			throw new ProcessorException("packet contains users");
		}
		return unixUser;
	}

}
