/**
 * Copyright (c) 2006-2012 EBM WebSourcing, 2012-2024 Linagora
 * 
 * This program/library is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 2.1 of the License, or (at your
 * option) any later version.
 * 
 * This program/library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
 * for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program/library; If not, see http://www.gnu.org/licenses/
 * for the GNU Lesser General Public License version 2.1.
 */
package org.ow2.petals.bc.mail;

import static org.ow2.petals.bc.mail.MailConstants.NativeService.OP_SENDMAIL;
import static org.ow2.petals.bc.mail.MailConstants.NativeService.PORT_TYPE_NAME;

import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;

import javax.jbi.JBIException;
import javax.xml.namespace.QName;

import org.ow2.easywsdl.wsdl.api.Endpoint;
import org.ow2.easywsdl.wsdl.api.WSDLException;
import org.ow2.petals.bc.mail.listeners.ExternalListener;
import org.ow2.petals.bc.mail.listeners.JBIListener;
import org.ow2.petals.bc.mail.service.provide.AbstractSendService;
import org.ow2.petals.bc.mail.service.provide.natif.SendMailOperation;
import org.ow2.petals.component.framework.bc.AbstractBindingComponent;
import org.ow2.petals.component.framework.su.AbstractServiceUnitManager;
import org.ow2.petals.component.framework.util.ServiceEndpointOperationKey;
import org.ow2.petals.component.framework.util.WSDLUtilImpl;

/**
 * The Mail Binding Component.
 * <p>
 * It creates some sub components like :
 * </p>
 * <ul>
 * <li>
 * the <b>{@link MailSessionManager}</b> used to manage session with mail servers : create and open sessions, send and
 * receive mails,</li>
 * <li>
 * the <b>{@link MimeMessageManager}</b> used to process (reading or creating) mail messages,</li>
 * <li>
 * the <b>{@link ExternalListener}</b> used to manage listeners for external mail addresses registered during SU
 * deployment,</li>
 * <li>
 * the <b>{@link JBIListener}</b> used to process incoming JBI messages.</li>
 * </ul>
 * <p>
 * This class defines some Default Value for mail features like:</p>
 * <ul>
 * <li><b>SMTP</b> (25), <b>IMAP</b> (143) and <b>POP3</b> (110) default ports,</li>
 * <li>default mail folder (INBOX),</li>
 * <li>default mail checking period (60 seconds).</li>
 * </ul>
 * 
 * @author Olivier Fabre - EBM WebSourcing
 */
public class MailComponent extends AbstractBindingComponent {

    protected MailSessionManager mailSessionManager;

    protected MimeMessageManager mimeMessageManager;

    /**
     * A map used to get the mail operations associated with (end-point name + operation)
     */
    private final Map<ServiceEndpointOperationKey, AbstractSendService> mailOperations = new ConcurrentHashMap<>();

    @Override
    protected void doInit() throws JBIException {
        this.mimeMessageManager = new MimeMessageManager(this.getLogger());
        this.mailSessionManager = new MailSessionManager(this.getLogger());

        this.registersNativeOperations();
    }

    public MailSessionManager getMailSessionManager() {
        return this.mailSessionManager;
    }

    public MimeMessageManager getMimeMessageManager() {
        return this.mimeMessageManager;
    }

    @Override
    protected AbstractServiceUnitManager createServiceUnitManager() {
        return new MailSuManager(this);
    }

    /**
     * @param eptAndOperation
     *            the end-point Name and operation Name
     * @param mailOperation
     *            a mail operation
     */
    public void registerMailOperation(final ServiceEndpointOperationKey eptAndOperation,
            final AbstractSendService mailOperation) {
        this.mailOperations.put(eptAndOperation, mailOperation);
    }

    /**
     * @param eptName
     *            the end-point name
     */
    public void removeMailOperations(final String eptName) {

        final Iterator<Entry<ServiceEndpointOperationKey, AbstractSendService>> itEptOperationToMailOperation = this.mailOperations
                .entrySet().iterator();
        while (itEptOperationToMailOperation.hasNext()) {
            final Entry<ServiceEndpointOperationKey, AbstractSendService> entry = itEptOperationToMailOperation.next();
            if (entry.getKey().getEndpointName().equals(eptName)) {
                itEptOperationToMailOperation.remove();
            }
        }
    }

    /**
     * @param eptAndOperation
     *            the end-point name and operation name
     * @return the mail operation associated with this end-point name and operation name
     */
    public AbstractSendService getMailOperation(final ServiceEndpointOperationKey eptAndOperation) {
        return this.mailOperations.get(eptAndOperation);
    }

    /**
     * Registers native operations
     */
    private void registersNativeOperations() {

        final List<Endpoint> genericEndpoints = WSDLUtilImpl.getEndpointList(this.getNativeWsdl().getDescription());
        if (!genericEndpoints.isEmpty()) {
            try {
                for (final Endpoint endpoint : genericEndpoints) {
                    final String genericEndpointName = endpoint.getName();
                    final QName genericServiceName = endpoint.getService().getQName();
                    final QName genericInterfaceName = endpoint.getService().getInterface().getQName();
                    if (PORT_TYPE_NAME.equals(genericInterfaceName.getLocalPart())) {
                        this.mailOperations.put(
                                new ServiceEndpointOperationKey(genericServiceName, genericEndpointName,
                                        OP_SENDMAIL),
                                new SendMailOperation(this.mailSessionManager, this.mimeMessageManager,
                                        this.getLogger()));
                    } else {
                        this.getLogger().log(Level.WARNING,
                                "Unexpected/Unknown generic interface: " + genericInterfaceName);
                    }
                }
            } catch (final WSDLException e) {
                this.getLogger().log(Level.WARNING, "Generic service are not completly initialized", e);
            }
        } else {
            this.getLogger().warning("No endpoint exists to execute generic service");
        }
    }
}
