/**
 * Copyright (c) 2003-2005, David A. Czarnecki
 * All rights reserved.
 *
 * Portions Copyright (c) 2003-2005 by Mark Lussier
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 *      this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice,
 *      this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
 * Neither the name of the "David A. Czarnecki" and "blojsom" nor the names of
 * its contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Products derived from this software may not be called "blojsom",
 * nor may "blojsom" appear in their name, without prior written permission of
 * David A. Czarnecki.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 * EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package org.blojsom.plugin.postmailer;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import javax.servlet.ServletConfig;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.blojsom.blog.Blog;
import org.blojsom.blog.BlogEntry;
import org.blojsom.blog.BlogUser;
import org.blojsom.blog.BlojsomConfiguration;
import org.blojsom.event.BlojsomEvent;
import org.blojsom.event.BlojsomListener;
import org.blojsom.plugin.BlojsomPlugin;
import org.blojsom.plugin.BlojsomPluginException;
import org.blojsom.plugin.admin.event.AddBlogEntryEvent;
import org.blojsom.plugin.admin.event.BlogEntryEvent;
import org.blojsom.plugin.admin.event.UpdatedBlogEntryEvent;
import org.blojsom.plugin.common.VelocityPlugin;
import org.blojsom.plugin.email.EmailUtils;
import org.blojsom.plugin.email.SendEmailPlugin;
import org.blojsom.util.BlojsomMetaDataConstants;
import org.blojsom.util.BlojsomProperties;

public class PostMailerPlugin extends VelocityPlugin implements BlojsomPlugin, BlojsomListener
{
    
    private Log _logger = LogFactory.getLog(PostMailerPlugin.class);

    /**
     * PostMailer Plugin configuration parameter for web.xml
     */
    public static final String PLUGIN_POSTMAILER_CONFIGURATION_IP = "plugin-postmailer";
    
    public static final String DEFAULT_CONFIGURATION = "postmailer.properties";

    
    /**
     * Template for post e-mails
     */
    private static final String POSTMAILER_PLUGIN_EMAIL_TEMPLATE = "org/blojsom/plugin/postmailer/postmailer-plugin-email-template.vm";

    /**
     * Key under which the blog entry will be placed for merging the post e-mail
     */
    public static final String BLOJSOM_POSTMAILER_PLUGIN_BLOG_ENTRY = "BLOJSOM_POSTMAILER_PLUGIN_BLOG_ENTRY";

    /**
     * Default prefix for post e-mail notification
     */
    private static final String DEFAULT_ENTRY_MAIL_PREFIX = "[blojsom] ";

    /**
     * Configuration property for TO addresses
     */
    public static final String MAIL_RECIPIENTS_IP = "plugin-postmailer-email-recipients";

    /**
     * Configuration property for e-mail prefix
     */
    public static final String ENTRY_MAIL_PREFIX_IP = "plugin-postmailer-email-prefix";

    /**
     * Configuration property for whether or not postmailer is enabled for added entry
     */
    private static final String POSTMAILER_PLUGIN_ON_ADD_ENABLED = "plugin-postmailer-on-add-enabled";


    /**
     * Configuration property for whether or not postmailer is enabled for updated entry
     */
    private static final String POSTMAILER_PLUGIN_ON_UPDATE_ENABLED = "plugin-postmailer-on-update-enabled";

    private ServletConfig _servletConfig;
    private BlojsomConfiguration _blojsomConfiguration;

    /** 
     * Plugin instance that sends the emails.
     */
    private SendEmailPlugin _sendEmailPlugin;
    
    /**
     * Initialize this plugin. This method only called when the plugin is instantiated.
     *
     * @param servletConfig        Servlet config object for the plugin to retrieve any initialization parameters
     * @param blojsomConfiguration {@link org.blojsom.blog.BlojsomConfiguration} information
     * @throws org.blojsom.plugin.BlojsomPluginException
     *          If there is an error initializing the plugin
     */
    public void init(ServletConfig servletConfig, BlojsomConfiguration blojsomConfiguration) throws BlojsomPluginException {
        super.init(servletConfig, blojsomConfiguration);
        _servletConfig = servletConfig;
        _blojsomConfiguration = blojsomConfiguration;
        _blojsomConfiguration.getEventBroadcaster().addListener(this);

        _sendEmailPlugin = new SendEmailPlugin();
        try
        {
            _sendEmailPlugin.init(_servletConfig, _blojsomConfiguration);
            _logger.debug("Initialized postmailer plugin.");
        }
        catch (BlojsomPluginException e)
        {
            _logger.debug(e);
        }

    }
    
    /**
     * Process the blog entries
     *
     * @param httpServletRequest  Request
     * @param httpServletResponse Response
     * @param user                {@link org.blojsom.blog.BlogUser} instance
     * @param context             Context
     * @param entries             Blog entries retrieved for the particular request
     * @return Modified set of blog entries
     * @throws org.blojsom.plugin.BlojsomPluginException
     *          If there is an error processing the blog entries
     */
    public BlogEntry[] process(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlogUser user, Map context, BlogEntry[] entries) throws BlojsomPluginException {
        return entries;
    }

    /**
     * Perform any cleanup for the plugin. Called after {@link #process}.
     *
     * @throws org.blojsom.plugin.BlojsomPluginException
     *          If there is an error performing cleanup for this plugin
     */
    public void cleanup() throws BlojsomPluginException {
    }

    /**
     * Called when BlojsomServlet is taken out of service
     *
     * @throws org.blojsom.plugin.BlojsomPluginException
     *          If there is an error in finalizing this plugin
     */
    public void destroy() throws BlojsomPluginException {
    }

    /**
     * Handle an event broadcast from another component
     *
     * @param event {@link org.blojsom.event.BlojsomEvent} to be handled
     */
    public void handleEvent(BlojsomEvent event) {
        _logger.debug("Event detected");
        if (event instanceof BlogEntryEvent) {
            BlogEntryEvent entryEvent = (BlogEntryEvent) event;

            _logger.debug("It is a BlogEntryEvent");
            if (entryEvent instanceof AddBlogEntryEvent || entryEvent instanceof UpdatedBlogEntryEvent) 
            {
  
                _logger.debug("It is an AddBlogEntryEvent or an UpdateBlogEntryEvent");
                
                BlogUser blogUser = entryEvent.getBlogUser();
                Properties configuration = processConfiguration(blogUser);
                
                Boolean onAddEnabled = Boolean.valueOf(configuration.getProperty(POSTMAILER_PLUGIN_ON_ADD_ENABLED, "false"));
                Boolean onUpdateEnabled = Boolean.valueOf(configuration.getProperty(POSTMAILER_PLUGIN_ON_UPDATE_ENABLED, "false"));
                
                if (
                    (entryEvent instanceof AddBlogEntryEvent && onAddEnabled.booleanValue()) 
                    ||
                    (entryEvent instanceof UpdatedBlogEntryEvent && onUpdateEnabled.booleanValue())
                   )
                    
                {
                    _logger.debug("PostMailerPlugin is enabled for this type of event");

                    Blog blog = blogUser.getBlog();
                    BlogEntry blogEntry = entryEvent.getBlogEntry();  
                 
                    String author = (String) blogEntry.getMetaData().get(BlojsomMetaDataConstants.BLOG_ENTRY_METADATA_AUTHOR);

                    String[] recipients;
                    String recipientsProperty = (String) configuration.get(MAIL_RECIPIENTS_IP);
                    if (null == recipientsProperty)
                        recipients = new String[]{blog.getAuthorizedUserEmail(author)};   
                    else 
                        recipients = recipientsProperty.split(",");
         
                    String prefix = (String) configuration.get(ENTRY_MAIL_PREFIX_IP);
                    if (null == prefix)
                        prefix = DEFAULT_ENTRY_MAIL_PREFIX;   
                    Map context = new HashMap();
                    
                    // Merge the template e-mail
                    Map emailTemplateContext = new HashMap();
                    emailTemplateContext.put(BLOJSOM_POSTMAILER_PLUGIN_BLOG_ENTRY, blogEntry);
                    String emailBody = mergeTemplate(POSTMAILER_PLUGIN_EMAIL_TEMPLATE, blogUser, emailTemplateContext);
                    
                    // The category name is different dependig on the event:
                    // if it is an AddEvent it has a starting /, otherwise it has not it.
                    // I have to adjust it to allow correct threading based on the subject line.
                    String category = blogEntry.getCategory();
                    if (!category.startsWith("/"))
                        category = "/" + category;

                    sendEntryEmails(
                        prefix,
                        category + " : " + blogEntry.getTitle(), 
                        emailBody, 
                        context,
                        recipients, 
                        blog
                        );
                    try
                    {
                        _sendEmailPlugin.process(null, null, blogUser, context, null);  
                    }
                    catch (BlojsomPluginException e)
                    {
                        _logger.debug(e);
                    }
                   
                    
                }
                else
                    _logger.debug("PostMailerPlugin is not enabled for this type of event, ignored");
            }
            else
                _logger.debug("It is neither an AddBlogEntryEvent nor an UpdateBlogEntryEvent, ignored");
        }
        else 
            _logger.debug("It is not a BlogEntryEvent, ignored");
    }
    
    /**
     * Retrieve a properties map from configuration file.
     *
     * @param blogUser {@link BlogUser}
     * @return The configuration map
     */
    private Properties processConfiguration(BlogUser blogUser) {
        String postMailerConfiguration = _servletConfig.getInitParameter(PLUGIN_POSTMAILER_CONFIGURATION_IP);
        if (null == postMailerConfiguration)
            postMailerConfiguration = DEFAULT_CONFIGURATION;
        String configurationFile = _blojsomConfiguration.getBaseConfigurationDirectory() + blogUser.getId() + "/" + postMailerConfiguration;
        Properties userProperties = new BlojsomProperties();

        try {
            InputStream is = _servletConfig.getServletContext().getResourceAsStream(configurationFile);

            if (is != null) {
                userProperties.load(is);
                is.close();
            } else {
                _logger.info("No PostMailer configuration file for blog: " + blogUser.getId() + ", " + configurationFile);

                return new Properties();
            }
        } catch (IOException e) {
            _logger.error(e);

            return new Properties();
        }

        return userProperties;
    }
    
    /**
     * Send the entry e-mail to the blog author
     *
     * @param emailPrefix E-mail prefix
     * @param title       Entry title
     * @param entry       Entry text
     * @param context     Context
     * @param recipients      Author of entry
     * @param blog        {@link Blog} information
     */
    public void sendEntryEmails(String emailPrefix, String title, String entry, Map context, String[] recipients, Blog blog) 
    {
        String subject = emailPrefix + title;
        for (int i = 0; i < recipients.length; i++)
            EmailUtils.notifyBlogAuthor(subject, entry, context, recipients[i]);
    }    

    /**
     * Process an event from another component
     *
     * @param event {@link BlojsomEvent} to be handled
     * @since blojsom 2.24
     */
    public void processEvent(BlojsomEvent event) {
    }
    

}

