/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.rjconsultores.ventaboletos.web.gui.controladores.catalogos;

import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;

import javax.mail.AuthenticationFailedException;
import javax.mail.MessagingException;

import org.apache.commons.lang.NullArgumentException;
import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.zkoss.util.resource.Labels;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Desktop;
import org.zkoss.zk.ui.DesktopUnavailableException;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zul.Button;
import org.zkoss.zul.Label;

import com.rjconsultores.ventaboletos.entidad.Empresa;
import com.rjconsultores.ventaboletos.utilerias.SendMail;
import com.rjconsultores.ventaboletos.utilerias.SendMail.AuthType;
import com.rjconsultores.ventaboletos.web.utilerias.MyGenericForwardComposer;
import com.rjconsultores.ventaboletos.web.utilerias.MyListbox;
import com.rjconsultores.ventaboletos.web.utilerias.RJExecutorHolder;
import com.rjconsultores.ventaboletos.web.utilerias.render.RenderTestEmail;
import com.rjconsultores.ventaboletos.web.utilerias.render.RenderTestErrorEmail;

@Controller("viewTestEmailController")
@Scope("prototype")
public class ViewTestEmailController extends MyGenericForwardComposer {

	private static final long serialVersionUID = 1L;

	private static Logger log = LogManager.getLogger(ViewTestEmailController.class);

	private MyListbox tarefasList;
	private MyListbox errosList;
	private Label lblStatusInfo;
	private Button btnFechar;
	private Button btnStop;

	private Empresa empresa;

	private EmailConfigurationTestVO voTestConfig = new EmailConfigurationTestVO();
	private EmailConfigurationTestVO voTestSendEmail = new EmailConfigurationTestVO();

	private boolean success = false;

	private Thread testThread;
	private Executor executor;

	@Override
	public void doAfterCompose(Component comp) throws Exception {

		super.doAfterCompose(comp);

		tarefasList.setItemRenderer(new RenderTestEmail());
		errosList.setItemRenderer(new RenderTestErrorEmail());

		empresa = (Empresa) Executions.getCurrent().getArg().get("empresa");
		boolean isAutenticacao = (Boolean) Executions.getCurrent().getArg().get("isAutenticacao");
		String emailSMTP = (String) Executions.getCurrent().getArg().get("emailSMTP");
		String senhaEmail = (String) Executions.getCurrent().getArg().get("senhaEmail");
		String SMTPHost = (String) Executions.getCurrent().getArg().get("SMTPHost");
		String SMTPPorta = (String) Executions.getCurrent().getArg().get("SMTPPorta");
		String emailDe = (String) Executions.getCurrent().getArg().get("emailDe");
		String emailCopiaOculta = (String) Executions.getCurrent().getArg().get("emailCopiaOculta");
		String destinatario = (String) Executions.getCurrent().getArg().get("destinatario");
		String tipoAutorizacao = (String) Executions.getCurrent().getArg().get("tipoAutorizacao");

		List<EmailConfigurationTestVO> data = new ArrayList<EmailConfigurationTestVO>();

		voTestConfig.setTarefa(Labels.getLabel("viewTestEmailController.testEmailMsgTarefa"));
		voTestConfig.setStatus(Labels.getLabel("viewTestEmailController.msgStatusAndamento"));
		voTestConfig.setCodStatus("EA");

		voTestSendEmail.setTarefa(Labels.getLabel("viewTestEmailController.sendEmailMsgTarefa"));
		voTestSendEmail.setStatus(Labels.getLabel("viewTestEmailController.msgStatusAndamento"));
		voTestSendEmail.setCodStatus("EA");

		data.add(voTestConfig);
		data.add(voTestSendEmail);

		tarefasList.setData(data);
		errosList.setData(new ArrayList<String>());

		executor = RJExecutorHolder.getExecutor();
		
		btnFechar.setDisabled(true);

		desktop.enableServerPush(true);
		
		testThread = new Thread(new TestConfig(isAutenticacao, emailSMTP, senhaEmail, SMTPHost, SMTPPorta, emailDe, emailCopiaOculta, destinatario, tipoAutorizacao, desktop, this));
		executor.execute(testThread);

	}

	@SuppressWarnings("unchecked")
	public void onClick$btnStop(Event ev) {
		try {
			testThread.interrupt();
		} catch (Exception e) {
		}
		btnFechar.setDisabled(false);
		btnStop.setDisabled(true);
		lblStatusInfo.setValue(Labels.getLabel("viewTestEmailController.lblStatusInfo.msgCancelado"));
		
		voTestConfig.setStatus(Labels.getLabel("viewTestEmailController.msgStatusCancelado"));
		voTestConfig.setCodStatus("F");
		
		voTestSendEmail.setStatus(Labels.getLabel("viewTestEmailController.msgStatusCancelado"));
		voTestSendEmail.setCodStatus("F");
		
		tarefasList.getListData().set(0, voTestConfig);
		tarefasList.getListData().set(1, voTestSendEmail);
	}

	public class EmailConfigurationTestVO {
		private String tarefa;
		private String status;
		private String codStatus;

		public String getTarefa() {
			return tarefa;
		}

		public void setTarefa(String tarefa) {
			this.tarefa = tarefa;
		}

		public String getStatus() {
			return status;
		}

		public void setStatus(String status) {
			this.status = status;
		}

		public String getCodStatus() {
			return codStatus;
		}

		public void setCodStatus(String codStatus) {
			this.codStatus = codStatus;
		}
	}

	public enum ExceptionTestCodes {
		UNKNOWN_HOST(new UnknownHostException(), Labels.getLabel("viewTestEmailController.msgExceptionErroServidor") ), 
		AUTHENTICATION_FAILED(new AuthenticationFailedException(), Labels.getLabel("viewTestEmailController.msgExceptionErroUsuarioSenha")), 
		MAIL_ERROR(new MessagingException(), Labels.getLabel("viewTestEmailController.msgExceptionErroGeneric")), 
		GENERIC_ERROR(new Exception(), Labels.getLabel("viewTestEmailController.msgExceptionErroContacteAdm"));

		private final Exception exception;
		private final String solucao;

		ExceptionTestCodes(Exception exception, String solucao) {
			this.exception = exception;
			this.solucao = solucao;
		}

		public Exception getException() {
			return exception;
		}

		public String getSolucao() {
			return solucao;
		}

		public static String findException(Exception exception) {
			for (ExceptionTestCodes ex : ExceptionTestCodes.values()) {
				if (ex.getException().getClass().equals(exception.getClass())) {
					return ex.getSolucao();
				}
			}

			return null;
		}

	}

	public class TestConfig implements Runnable {

		private final boolean isAutenticacao;
		private final String emailSMTP;
		private final String senhaEmail;
		private final String SMTPHost;
		private final String SMTPPorta;
		private final String emailDe;
		private final String emailCopiaOculta;
		private final String destinatario;
		private final String tipoAutorizacao;
		
		private final Desktop desktop;
		private final EventListener eventListener;

		public TestConfig(boolean isAutenticacao, String emailSMTP, String senhaEmail, String SMTPHost, String SMTPPorta, String emailDe, String emailCopiaOculta, String destinatario, String tipoAutorizacao, Desktop desktop, EventListener eventListener) {
			this.isAutenticacao = isAutenticacao;
			this.emailSMTP = emailSMTP;
			this.senhaEmail = senhaEmail;
			this.SMTPHost = SMTPHost;
			this.SMTPPorta = SMTPPorta;
			this.emailDe = emailDe;
			this.emailCopiaOculta = emailCopiaOculta;
			this.destinatario = destinatario;
			this.tipoAutorizacao = tipoAutorizacao;
			this.desktop = desktop;
			this.eventListener = eventListener;
		}

		public void run() {

			try {
				
				if (Thread.interrupted()) {
					return;
				}
				
				Thread.sleep(3000);
				Executions.schedule(desktop, eventListener, new TestEmailEvent(isAutenticacao, emailSMTP, senhaEmail, SMTPHost, SMTPPorta, emailDe, tipoAutorizacao));

				Thread.sleep(3000);
				Executions.schedule(desktop, eventListener, new SendEmailTestEvent(isAutenticacao, emailSMTP, senhaEmail, SMTPHost, SMTPPorta, emailDe, emailCopiaOculta, destinatario, tipoAutorizacao));
			} catch (DesktopUnavailableException e) {
				log.error("Desktop is no longer available: " + desktop, e);
			} catch (InterruptedException e) {
			}

		}
	}

	@SuppressWarnings("unchecked")
	public void onTestAuthenticationStepCompleted(TestEmailEvent event) {

		if (btnStop.isDisabled()) {
			btnFechar.setDisabled(false);
			btnStop.setDisabled(true);
			return;
		}
		
		Boolean isAuthentincationOK = event.isAuthentincationOK;

		if (isAuthentincationOK != null && isAuthentincationOK) {
			voTestConfig.setStatus(Labels.getLabel("viewTestEmailController.msgStatusConcluido"));
			voTestConfig.setCodStatus("C");
		} else {
			voTestConfig.setStatus(Labels.getLabel("viewTestEmailController.msgStatusFalha"));
			voTestConfig.setCodStatus("F");
		}
		tarefasList.getListData().set(0, voTestConfig);

		if (voTestConfig.getCodStatus().equals("F")) {
			String solucao = StringUtils.defaultString(ExceptionTestCodes.findException(event.exception));
			String erro = voTestConfig.getTarefa() + " : " + event.msgError + ". " + solucao;
			errosList.addItemNovo(erro);
		}

	}

	@SuppressWarnings("unchecked")
	public void onSendEmailTestStepCompleted(SendEmailTestEvent event) {
		
		if (btnStop.isDisabled()) {
			btnFechar.setDisabled(false);
			btnStop.setDisabled(true);
			return;
		}

		Boolean isAuthentincationOK = event.isAuthentincationOK;
		btnFechar.setDisabled(false);
		btnStop.setDisabled(true);

		if (isAuthentincationOK != null && isAuthentincationOK) {
			voTestSendEmail.setStatus(Labels.getLabel("viewTestEmailController.msgStatusConcluido"));
			voTestSendEmail.setCodStatus("C");
			success = true;
		} else {
			voTestSendEmail.setStatus(Labels.getLabel("viewTestEmailController.msgStatusFalha"));
			voTestSendEmail.setCodStatus("F");
		}
		tarefasList.getListData().set(1, voTestSendEmail);

		if (voTestSendEmail.getCodStatus().equals("F")) {
			String solucao = StringUtils.defaultString(ExceptionTestCodes.findException(event.exception));
			String erro = voTestSendEmail.getTarefa() + " : " + event.msgError + ". " + solucao;
			errosList.addItemNovo(erro);
		}

		if (success) {
			lblStatusInfo.setValue(Labels.getLabel("viewTestEmailController.lblStatusInfo.sucesso"));
		} else {
			lblStatusInfo.setValue(Labels.getLabel("viewTestEmailController.lblStatusInfo.erro"));
		}
	}

	public class TestEmailEvent extends Event {

		private static final long serialVersionUID = 1L;

		public String msgError;
		public Exception exception;
		public boolean isAuthentincationOK;
		private boolean isAutenticacao;
		private String emailSMTP;
		private String senhaEmail;
		private String SMTPHost;
		private String SMTPPorta;
		private String emailDe;
		private String tipoAutorizacao;

		public TestEmailEvent(boolean isAutenticacao, String emailSMTP, String senhaEmail, String SMTPHost, String SMTPPorta, String emailDe, String tipoAutorizacao) {
			super("onTestAuthenticationStepCompleted", null);
			this.isAutenticacao = isAutenticacao;
			this.emailSMTP = emailSMTP;
			this.senhaEmail = senhaEmail;
			this.SMTPHost = SMTPHost;
			this.SMTPPorta = SMTPPorta;
			this.emailDe = emailDe;
			this.tipoAutorizacao = tipoAutorizacao;
			testEmailAuthentication();
		}

		private void testEmailAuthentication() {

			try {
				SendMail mail = new SendMail();
				mail.setAuth(isAutenticacao);
				mail.setEmailFrom(emailDe);
				mail.setSmtpHost(SMTPHost);
				mail.setSmtpPassword(senhaEmail);
				mail.setSmtpPort(SMTPPorta);
				mail.setSmtpUser(emailSMTP);
				
				if (StringUtils.isNotEmpty(tipoAutorizacao)) {
					mail.setAuthType(AuthType.valueOf(tipoAutorizacao));
				}

				this.isAuthentincationOK = mail.testConfiguration();

			} catch (AuthenticationFailedException e) {
				exception = (e.getNextException() != null) ? e.getNextException() : e;
				msgError = e.getMessage();
			} catch (MessagingException e) {
				exception = (e.getNextException() != null) ? e.getNextException() : e;
				msgError = e.getMessage();
			} catch (Exception e) {
				log.error("", e);
				exception = e;
				msgError = e.getMessage();
			}
		}

	}

	public class SendEmailTestEvent extends Event {

		private static final long serialVersionUID = 1L;

		public String msgError;
		public Exception exception;
		public boolean isAuthentincationOK;
		private boolean isAutenticacao;
		private String emailSMTP;
		private String senhaEmail;
		private String SMTPHost;
		private String SMTPPorta;
		private String emailDe;
		private String emailCopiaOculta;
		private String destinatario;
		private String tipoAutorizacao;

		public SendEmailTestEvent(boolean isAutenticacao, String emailSMTP, String senhaEmail, String SMTPHost, String SMTPPorta, String emailDe, String emailCopiaOculta, String destinatario, String tipoAutorizacao) {
			super("onSendEmailTestStepCompleted", null);
			this.isAutenticacao = isAutenticacao;
			this.emailSMTP = emailSMTP;
			this.senhaEmail = senhaEmail;
			this.SMTPHost = SMTPHost;
			this.SMTPPorta = SMTPPorta;
			this.emailDe = emailDe;
			this.emailCopiaOculta = emailCopiaOculta;
			this.destinatario = destinatario;
			this.tipoAutorizacao = tipoAutorizacao;
			testEmailSend();
		}

		private void testEmailSend() {
			this.isAuthentincationOK = false;
			try {
				if (StringUtils.isEmpty(destinatario)) {
					msgError = Labels.getLabel("viewTestEmailController.semDestinatario");
					exception = new NullArgumentException(Labels.getLabel("viewTestEmailController.destinatario"));
				} else {
					SendMail mail = new SendMail();
					mail.setAuth(isAutenticacao);
					
					if (StringUtils.isNotEmpty(tipoAutorizacao)) {
						mail.setAuthType(AuthType.valueOf(tipoAutorizacao));
					}
					
					mail.setEmailFrom(emailDe);
					mail.setSmtpHost(SMTPHost);
					mail.setSmtpPassword(senhaEmail);
					mail.setSmtpPort(SMTPPorta);
					mail.setSmtpUser(emailSMTP);
					mail.setSubject(Labels.getLabel("viewTestEmailController.emailSubject", new Object[] { empresa.getNombempresa() }));
					mail.setText(Labels.getLabel("viewTestEmailController.emailText"));
					mail.setEmailTo(destinatario);
					mail.setEmailToCO(emailCopiaOculta);
					mail.sendEmail(null);

					this.isAuthentincationOK = true;
				}

			} catch (AuthenticationFailedException e) {
				exception = (e.getNextException() != null) ? e.getNextException() : e;
				msgError = e.getMessage();
			} catch (MessagingException e) {
				exception = (e.getNextException() != null) ? e.getNextException() : e;
				msgError = e.getMessage();
			} catch (Exception e) {
				exception = e;
				msgError = e.getMessage();
			}
		}

	}

	public MyListbox getTarefasList() {
		return tarefasList;
	}

	public void setTarefasList(MyListbox tarefasList) {
		this.tarefasList = tarefasList;
	}

	public MyListbox getErrosList() {
		return errosList;
	}

	public void setErrosList(MyListbox errosList) {
		this.errosList = errosList;
	}

	public Empresa getEmpresa() {
		return empresa;
	}

	public void setEmpresa(Empresa empresa) {
		this.empresa = empresa;
	}

	public Label getLblStatusInfo() {
		return lblStatusInfo;
	}

	public void setLblStatusInfo(Label lblStatusInfo) {
		this.lblStatusInfo = lblStatusInfo;
	}

	public Button getBtnFechar() {
		return btnFechar;
	}

	public void setBtnFechar(Button btnFechar) {
		this.btnFechar = btnFechar;
	}

	public Button getBtnStop() {
		return btnStop;
	}

	public void setBtnStop(Button btnStop) {
		this.btnStop = btnStop;
	}

}
