/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package hu.nir.nmail.services;

import hu.nir.nmail.dbm.DataManager;
import hu.nir.nmail.ejb.entity.EmailAddress;
import hu.nir.nmail.ejb.entity.EmailSendingProces;
import hu.nir.nmail.ejb.entity.NmailUser;
import hu.nir.nmail.ejb.entity.SmtpSettings;
import hu.nir.nmail.ejb.entity.UserRestriction;
import hu.nir.nmail.ejb.stateless.NmailUserManager;
import hu.nir.nmail.ejb.stateless.SmtpSettingsManager;
import hu.nir.nmail.ejb.stateless.UserProcesManager;
import hu.nir.nmail.spring.beans.MailsData;
import hu.nir.nmail.spring.beans.NmailErrors;
import hu.nir.nmail.threads.SenderThread;
import hu.nir.nmail.utils.NmailUtility;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.mail.Address;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;

/**
 *
 * @author attila
 */
public class SendMessageService implements NmailService{
    private DataManager dataManager;
    private Logger logger = Logger.getLogger(SendMessageService.class.getName());

    @SuppressWarnings("unchecked")
    public Map<String, Object> processCommand(Object... commands) throws MessagingException, UnsupportedEncodingException {
        NmailUser nmailUser = null;
        MailsData mailsData = null;
        Boolean test = new Boolean(false);
        NmailErrors nmailErrors = new NmailErrors();
        
        for (Object command : commands) {
            if (command instanceof NmailUser) {
                nmailUser = (NmailUser) command;
            }
            
            if (command instanceof MailsData) {
                mailsData = (MailsData) command;
            }
            
            if (command instanceof Boolean) {
                test = (Boolean) command;
            }
        }
        
        if (nmailUser == null || mailsData == null) {
            return null;
        }
        
        Message message = prepareMessage(mailsData, nmailUser);
        List<Address> addressList = getAddressList(nmailUser, mailsData, test);
        SmtpSettingsManager smtpSettingsManager = dataManager.getSmtpSettingsManager();
        SmtpSettings smtpSettings = smtpSettingsManager.getSmtpSettings();
        
        if (test) {
            SenderThread senderThread = new SenderThread(nmailUser, message, addressList, dataManager, null);
            senderThread.start();
        }
        else {
            
            if (NmailUtility.hasSendingRight(nmailUser, dataManager.getUserProcesManager())) {
                sendMessages(nmailUser, message, addressList, smtpSettings);
            }
            else {
                nmailErrors.addErrorCode("email.nosendingright");
            }
        }
        return NmailUtility.toMap("mailsData", mailsData, "nmailErrors", nmailErrors);
    }
    
    /**
     * Sending non test emails
     * @param nmailUser
     * @param message
     * @param addressList
     * @param smtpSettings
     */
    private void sendMessages(NmailUser nmailUser, Message message, List<Address> addressList, SmtpSettings smtpSettings) {
        try {
            EmailSendingProces emailSendingProces = new EmailSendingProces();
            emailSendingProces.setEmailCount(addressList.size());
            emailSendingProces.setFailedEmail(0L);
            emailSendingProces.setSentEmail(0L);
            emailSendingProces.setStartProces(new Date());
            emailSendingProces.setProcesType("NMAIL.EMAILSENDING");
            emailSendingProces.setUserId(nmailUser);
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            message.writeTo(byteArrayOutputStream);
            byte[] b = byteArrayOutputStream.toByteArray();
            emailSendingProces.setEmail(b);
            byteArrayOutputStream.close();

            UserProcesManager userProcesManager = dataManager.getUserProcesManager();
            emailSendingProces = (EmailSendingProces) userProcesManager.merge(emailSendingProces);

            SenderThread senderThread = new SenderThread(nmailUser, message, addressList, dataManager, emailSendingProces);
            senderThread.start();
        } catch(Exception ex) {
            logger.log(Level.SEVERE, ex.getLocalizedMessage(), ex);
        }
    }
    
    private Message prepareMessage(MailsData mailsData, NmailUser nmailUser) throws MessagingException, UnsupportedEncodingException {
        List<Message> messageList = mailsData.getMessages();
        Message message = messageList.get(mailsData.getMessageIndex());
        message.setSubject(mailsData.getEncodedSubject());
        message.setSentDate(new Date());
        UserRestriction userRestriction = nmailUser.getUserRestriction();
        String senderName = mailsData.getSenderName();
        
        if (userRestriction.getAbleToSetSender()) {
            senderName = mailsData.getEncodedSenderName();
        }
        
        Address address = new InternetAddress(mailsData.getSenderAddress(), senderName);
        message.setFrom(address);
        mailsData.setSubject(NmailUtility.toUTF8(mailsData.getSubject()));
        return message;
    }
    
    private List<Address> getAddressList(NmailUser nmailUser, MailsData mailsData, boolean test) {
        List<Address> addressList = new ArrayList<Address>();
        
        if (test) {
            StringTokenizer tokenizer = new StringTokenizer(mailsData.getTestAddresses(),",");
            
            while (tokenizer.hasMoreTokens()) {
                String addressStr = tokenizer.nextToken();
                addressStr = addressStr.trim();
                Address address = null; 
                try {
                    address = new InternetAddress(addressStr);
                } catch (AddressException ex) {
                    continue;
                }
                addressList.add(address);
            }
        } else {
            NmailUserManager nmailUserManager = dataManager.getNmailUserManager();
            Collection<EmailAddress> emailAddresses = nmailUserManager.getEmailAddresses(nmailUser);
            Set<String> emailSet = new TreeSet<String>();
            
            for (EmailAddress emailAddress : emailAddresses) {
                String addressStr = emailAddress.getEmailAddress();
                Address address = null;
                if (emailSet.add(addressStr)) {
                    try {
                        address = new InternetAddress(addressStr);
                        addressList.add(address);
                    } catch (AddressException ex) {
                        emailAddress.setWrong(true);
                    }
                }
                else {
                    emailAddress.setDuplicated(true);
                }
            }
            
            nmailUser.setEmailAddressCollection(emailAddresses);
            nmailUserManager.update(nmailUser);
        }
        
        return addressList;
    }
    
    

    public DataManager getDataManager() {
        return dataManager;
    }

    public void setDataManager(DataManager dataManager) {
        this.dataManager = dataManager;
    }

}
