/*
 * $Id: SendEmailAction.java,v 1.26 2006/10/04 03:15:02 marbobo Exp $
 *
 * Copyright (c) Siemens AG 2008 
 *           (c) Universität Paderborn 2008 
 * Licensed under EUPL 1.1. 
 *
 * $Log: SendEmailAction.java,v $
 * Revision 1.26  2006/10/04 03:15:02  marbobo
 * + Vollständige Unterstützung für Templates implementiert
 * + Alles von Virtoweb auf ProCoBa umgestellt
 *
 * Revision 1.25  2006/05/31 14:00:33  marbobo
 * + Zeilenumbrüche bei Beschreibungsfelder anzeigen
 *
 * Revision 1.24  2006/05/24 17:59:33  marbobo
 * + Toolbar des Html-Editors kann optional angezeigt oder verborgen werden
 *
 * Revision 1.23  2006/05/15 19:12:37  marbobo
 * + Html-Editor eingebaut
 *
 * Revision 1.22  2006/03/06 15:11:59  jonyp
 * + Bugfix (wg. Oracle)
 *
 * Revision 1.21  2006/01/03 00:00:30  marbobo
 * + Absender kann frei gewählt werden
 *
 * Revision 1.20  2005/12/22 15:43:49  marbobo
 * + SSL-Unterstützung und Port-Auswahl für Mailsystem implementiert
 *
 * Revision 1.19  2005/12/20 14:04:15  marbobo
 * + Smtp-Auth korrigiert
 *
 * Revision 1.18  2005/12/15 15:28:50  marbobo
 * + Benutzername und Passwort für Mailserver implementiert
 *
 * Revision 1.17  2005/10/13 09:41:39  korowa
 * Administrator kann alle aktive Benutzer per Knopfdruck auswählen
 *
 * Revision 1.16  2005/02/15 18:44:53  marbobo
 * + Unicode-Konforme E-Mails
 *
 * Revision 1.15  2005/02/14 14:01:47  bigmac
 * Applikationsweites CSS konfigurierbar gemacht + Refactorings
 *
 * Revision 1.14  2005/02/10 14:45:06  marbobo
 * + Unicode-Anzeige bei Emails
 *
 * Revision 1.13  2004/11/10 15:02:50  koppy
 * Projektweite Überarbeitung von Error-Logs, Stacktraces,..
 *
 * Revision 1.12  2004/09/13 12:37:31  marbobo
 * + Eventhandling umgestellt
 *
 * Revision 1.11  2004/03/14 18:04:11  marbobo
 * Synchronisierung der Formdaten überarbeitet
 *
 * Revision 1.10  2004/03/13 18:18:24  marbobo
 * SendEmailAction und SendEmailForm auf Request-Scope umgestellt
 *
 * Revision 1.9  2004/03/11 20:17:15  bigmac
 * Anpassungen an VKCUserSerializer
 *
 * Revision 1.8  2004/03/09 18:40:36  bigmac
 * Anpassungen an VKCSysParameterSerializer
 *
 * Revision 1.7  2004/03/07 13:45:48  bigmac
 * Anpassungen an VKCDocumentTypeSerializer, VKCDocumentClassSerializer, VKCDocumentStatusSerializer
 *
 * Revision 1.6  2004/03/02 17:46:55  bigmac
 * Anpassungen an VKCGroupSerializer
 *
 * Revision 1.5  2004/02/10 13:05:57  marbobo
 * kleine Änderung
 *
 * Revision 1.4  2004/02/09 21:39:58  marbobo
 * bugfix
 *
 * Revision 1.3  2004/02/09 15:28:51  marbobo
 * +Fehlerbehandlung
 *
 * Revision 1.2  2003/12/24 10:12:09  bigmac
 * Projektweite Import-Optimierung
 *
 * Revision 1.1  2003/11/05 01:36:48  marbobo
 * Initiale Version
 *
 */
package vkc.administration.action;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Properties;

import javax.mail.Address;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.SendFailedException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.Globals;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.util.MessageResources;

import vkc.administration.form.SendEmailForm;
import vkc.db.entities.VKCUser;
import vkc.db.serializer.VKCGroupSerializer;
import vkc.db.serializer.VKCSysParameterSerializer;
import vkc.db.serializer.VKCUserSerializer;
import vkc.exception.DBException;
import vkc.misc.VKCLogManager;
import vkc.util.VKCStringUtils;
import vkc.view.WebShare;
import vkc.view.bean.GroupInfo;
import vkc.view.bean.UserInfo;


/**
 * Action-Klasse zum Versenden von Emails
 *
 * @author marbobo
 * @version $Revision: 1.26 $
 */
public final class SendEmailAction extends Action {
	private ActionForward DEFAULT_FORWARD = new ActionForward("/templates/${template.name}/administration/sendEmail.jsp");

	private ActionForward INFO_FORWARD = new ActionForward("/templates/${template.name}/common/InfoPage.jsp");

	public ActionForward execute(ActionMapping mapping, 
	        					 ActionForm f,
	        					 HttpServletRequest request, 
	        					 HttpServletResponse response)
	throws Exception {
		SendEmailForm form = (SendEmailForm) f;
		VKCUser user = form.getUser();

		if (!user.hasAdminPrivileges()) {
			request.setAttribute(WebShare.INFO_KEY, "vkc.info.access_denied");

			return INFO_FORWARD;
		}

		if (request.getParameter("action.send.email") != null) {
			return handleSendEmailAction(mapping, form, request);
		} else if (request.getParameter("action.add.groups") != null) {
			return handleAddGroupsAction(form, request);
		} else if (request.getParameter("action.remove.groups") != null) {
			return handleRemoveGroupsAction(form, request);
		} else if (request.getParameter("action.add.users") != null) {
			return handleAddUsersAction(form, request);
		} else if (request.getParameter("action.remove.users") != null) {
			return handleRemoveUsersAction(form, request);
		} else if (request.getParameter("action.add.activUsers") != null) {
			return handleAddActivUsersAction(form, request);
		} else if (request.getParameter("action.toggle.tinymcetoolbar") != null) {
			synchronizeForm(form);

			return DEFAULT_FORWARD;
		} else {
			return handleInitializeAction(form, request);
		}
	}

	private void synchronizeForm(SendEmailForm form) {
		form.synchronizeForm();
	}

	private ActionForward handleRemoveUsersAction(SendEmailForm form, HttpServletRequest request) throws Exception {
		Integer[] removeIds = form.getSelectedRemoveUserIds();
		List sendUserIds = new ArrayList(Arrays.asList(form.getSendUserIds()));
		
		for (int i = 0; i < removeIds.length; i++) {
			if (sendUserIds.contains(removeIds[i])) {
				sendUserIds.remove(removeIds[i]);
			}
		}
		
		form.setSendUserIds((Integer[])sendUserIds.toArray(new Integer[0]));
		
		synchronizeForm(form);

		return DEFAULT_FORWARD;
	}

	private ActionForward handleAddUsersAction(SendEmailForm form, HttpServletRequest request) throws Exception {
		Integer[] addIds = form.getSelectedAddUserIds();
		List sendUserIds = new ArrayList(Arrays.asList(form.getSendUserIds()));
		
		for (int i = 0; i < addIds.length; i++) {
			if (!sendUserIds.contains(addIds[i])) {
				sendUserIds.add(addIds[i]);
			}
		}
		
		form.setSendUserIds((Integer[])sendUserIds.toArray(new Integer[0]));
		
		synchronizeForm(form);
		
		return DEFAULT_FORWARD;
	}
	
	private ActionForward handleAddActivUsersAction(SendEmailForm form,HttpServletRequest request) throws DBException{
	    List sendUserIds = new ArrayList(Arrays.asList(form.getSendUserIds()));
		
	    Object[] selectedAllValidUserInfos = VKCUserSerializer.retrieveValidUserInfos().toArray();
        Integer[] selectedAllValidUserIds = new Integer[selectedAllValidUserInfos.length];
        
        for(int i = 0; i < selectedAllValidUserInfos.length; i++) {
            selectedAllValidUserIds[i] = ((UserInfo)selectedAllValidUserInfos[i]).getUserId();
        }

		for (int i = 0; i < selectedAllValidUserIds.length; i++) {
			if (!sendUserIds.contains(selectedAllValidUserIds[i])) {
				sendUserIds.add(selectedAllValidUserIds[i]);
			}
		}
		
		form.setSendUserIds((Integer[])sendUserIds.toArray(new Integer[0]));
		
		synchronizeForm(form);
	    
		return DEFAULT_FORWARD;
	}
	
	private ActionForward handleRemoveGroupsAction(SendEmailForm form, HttpServletRequest request) throws Exception {
		Integer[] removeIds = form.getSelectedRemoveGroupIds();
		List sendGroupIds = new ArrayList(Arrays.asList(form.getSendGroupIds()));
		
		for (int i = 0; i < removeIds.length; i++) {
			if (sendGroupIds.contains(removeIds[i])) {
				sendGroupIds.remove(removeIds[i]);
			}
		}
		
		form.setSendGroupIds((Integer[])sendGroupIds.toArray(new Integer[0]));
		
		synchronizeForm(form);
		
		return DEFAULT_FORWARD;
	}

	private ActionForward handleAddGroupsAction(SendEmailForm form, HttpServletRequest request) throws Exception {
		Integer[] addIds = form.getSelectedAddGroupIds();
		List sendGroupIds = new ArrayList(Arrays.asList(form.getSendGroupIds()));
		
		for (int i = 0; i < addIds.length; i++) {
			if (!sendGroupIds.contains(addIds[i])) {
				sendGroupIds.add(addIds[i]);
			}
		}
		
		form.setSendGroupIds((Integer[])sendGroupIds.toArray(new Integer[0]));
		
		synchronizeForm(form);
		
		return DEFAULT_FORWARD;
	}

	private ActionForward handleSendEmailAction(ActionMapping mapping, SendEmailForm form, HttpServletRequest request) throws Exception {
		VKCUser user = form.getUser();
		String sender = VKCStringUtils.decodeXmlEntities(VKCStringUtils.filterUnicodeChars(form.getSender()));
		String subject = VKCStringUtils.decodeXmlEntities(VKCStringUtils.filterUnicodeChars(form.getSubject()));
		String htmlContent = VKCStringUtils.filterUnicodeChars(form.getContent());
		htmlContent = VKCStringUtils.htmlFormatedText(htmlContent);
		htmlContent = VKCStringUtils.decodeXmlEntities(htmlContent);
		String textContent = VKCStringUtils.filterUnicodeChars(form.getContent());
		textContent = VKCStringUtils.htmlFormatedText(textContent);
		textContent = VKCStringUtils.decodeXmlEntities(textContent);
		textContent = VKCStringUtils.decodeNamedXmlEntitiesNotInSwing(textContent);
		textContent = VKCStringUtils.encodeNewLine(textContent);
		textContent = VKCStringUtils.removeHtmlTags(textContent);
		textContent = VKCStringUtils.decodeNewLine(textContent);
		List addUsers = form.getAddUsers();
		List addGroups = form.getAddGroups();
		HashMap recepients = new HashMap();
		
		for (int i = 0; i < addUsers.size(); i++) {
			UserInfo u = (UserInfo)addUsers.get(i);
			recepients.put(u.getUserId(), new InternetAddress(VKCStringUtils.decodeXmlEntities(u.getEmail())));
		}
		
		for (int i = 0; i < addGroups.size(); i++) {
			GroupInfo g = (GroupInfo)addGroups.get(i);
			Integer[] ids = (Integer[])VKCGroupSerializer.getGroupUserIds(g.getGroupId()).toArray(new Integer[0]);
			
			for (int j = 0; j < ids.length; j++) {
				if (!recepients.containsKey(ids[j])) {
					recepients.put(ids[j], new InternetAddress(VKCStringUtils.decodeXmlEntities(VKCUserSerializer.retrieveUserInfo(ids[j]).getEmail())));
				}
			}
		}
		
		InternetAddress[] receivers = (InternetAddress[])recepients.values().toArray(new InternetAddress[0]);
		
		String smtpServer  = VKCSysParameterSerializer.retrieveValue("MAIL", "MailServer", "");
		String smtpUsername  = VKCSysParameterSerializer.retrieveValue("MAIL", "MailUsername", "");
		String smtpPassword  = VKCSysParameterSerializer.retrieveValue("MAIL", "MailPassword", "");
		int smtpPort  = VKCSysParameterSerializer.retrieveIntValue("MAIL", "MailPort", 25);
		boolean smtpSSL = VKCSysParameterSerializer.retrieveIntValue("MAIL", "MailSsl", 0) != 0 ? true : false;
		boolean smtpUntrustedCert = VKCSysParameterSerializer.retrieveIntValue("MAIL", "MailUntrustedCertificate", 0) != 0 ? true : false;

		try {
			// Mail Senden
			final String username = smtpUsername;
			final String password = smtpPassword;

			Authenticator auth = new Authenticator() {
				protected PasswordAuthentication getPasswordAuthentication() {
					return new PasswordAuthentication(username, password);
				}
			};
			
			Properties props = new Properties();
			props = new Properties();
			
			if (smtpSSL) {
				props.put("mail.transport.protocol", "smtps");
				
				if (smtpUntrustedCert) {
					props.put("mail.smtps.socketFactory.class", "vkc.messenger.mail.VKCSSLSocketFactory");
					props.put("mail.smtps.socketFactory.fallback", "false");
				}

				props.put("mail.smtps.host", smtpServer);
				props.put("mail.smtps.auth", "true");
				props.put("mail.smtps.port", String.valueOf(smtpPort));
			} else {
				props.put("mail.transport.protocol", "smtp");
				props.put("mail.smtp.host", smtpServer);
				props.put("mail.smtp.auth", "true");
				props.put("mail.smtp.port", String.valueOf(smtpPort));
			}
			
			Session session = Session.getInstance(props, auth);
			MimeMessage message = new MimeMessage(session);
			message.setSubject(subject, "UTF8");
			message.setFrom(new InternetAddress(sender));

			if (receivers.length == 1) {
				message.addRecipient(Message.RecipientType.BCC, receivers[0]);
			} else {
				message.addRecipients(Message.RecipientType.BCC, receivers);
			}

			MimeBodyPart plainPart = new MimeBodyPart();
			plainPart.setContent(textContent, "text/plain; charset=utf-8");
			MimeBodyPart htmlPart = new MimeBodyPart();
			htmlPart.setContent(htmlContent, "text/html; charset=utf-8");
			MimeMultipart textPart = new MimeMultipart("alternative");
			textPart.addBodyPart(plainPart);
			textPart.addBodyPart(htmlPart);
			MimeMultipart multiPart = new MimeMultipart("related");
			MimeBodyPart wrapper = new MimeBodyPart();
			wrapper.setContent(textPart);
			multiPart.addBodyPart(wrapper);
			message.setContent(multiPart);
			Transport transport = session.getTransport();
			transport.connect(smtpServer, smtpPort, smtpUsername, smtpPassword);
			transport.sendMessage(message, message.getAllRecipients());
			transport.close();
			form.setSendGroupIds(new Integer[0]);
			form.setSendUserIds(new Integer[0]);

			request.setAttribute(WebShare.INFO_KEY, "vkc.administration.sendEmail.success");			
			
			return handleInitializeAction(form, request);
		} catch (SendFailedException e) {
			VKCLogManager.errorLog(this, "", e.getMessage(), e);
			Locale locale = user.getLanguage().getLocale();
			MessageResources mRes = form.getResources();
			String msg = "<br>" + mRes.getMessage(locale, "vkc.administration.sendEmail.invalidAddress");
			Address[] address = e.getInvalidAddresses();
				
			for (int i = 0; i < address.length; i++) {
				if (i == (address.length - 1)) {
					msg = msg + address[i].toString();
				} else {
					msg = msg + address[i].toString() + ", ";
				}
			}

			ActionErrors errors = new ActionErrors();
			errors.add("mailmessage.failure", new ActionError("vkc.administration.sendEmail.mailfailure", msg));
			request.setAttribute(Globals.ERROR_KEY, errors);
			
			return new ActionForward(mapping.getInput(), false);
		} catch (MessagingException e) {
			VKCLogManager.errorLog(this, "", e.getMessage(), e);
			String msg = "<br>" + e.getMessage();
				
			ActionErrors errors = new ActionErrors();
			errors.add("mailmessage.failure", new ActionError("vkc.administration.sendEmail.mailfailure", msg));
			request.setAttribute(Globals.ERROR_KEY, errors);
			
			return new ActionForward(mapping.getInput(), false);
		}
	}

	private ActionForward handleInitializeAction(SendEmailForm form, HttpServletRequest request) throws Exception {
		synchronizeForm(form);

		form.setSender(form.getUser().getEmail());
		form.setSubject("");
		form.setContent("");
		
		return DEFAULT_FORWARD;
	}
}