/*
 * Copyright 2006-2007 Queplix Corp.
 *
 * Licensed under the Queplix Public License, Version 1.1.1 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.queplix.com/solutions/commercial-open-source/queplix-public-license/
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 *
 */
package com.queplix.core.modules.inbox.www;

import com.queplix.core.integrator.security.AccessRightsManager;
import com.queplix.core.integrator.security.LogonSession;
import com.queplix.core.integrator.security.SecurityException;
import com.queplix.core.modules.inbox.Account;
import com.queplix.core.modules.inbox.InboxMessage;
import com.queplix.core.modules.inbox.actions.InboxAction;
import com.queplix.core.modules.inbox.error.InvalidAccountException;
import com.queplix.core.modules.inbox.utils.AccountDAO;
import com.queplix.core.modules.inbox.utils.DefaultMessageFilter;
import com.queplix.core.modules.inbox.utils.InboxMsgBuilder;
import com.queplix.core.modules.inbox.utils.InboxPropertyFactory;
import com.queplix.core.modules.inbox.utils.InboxProvider;
import com.queplix.core.modules.inbox.utils.ResultSet;
import com.queplix.core.modules.inbox.utils.log.SystemLogPublisher;
import com.queplix.core.modules.services.ActionRunner;
import com.queplix.core.modules.services.XAActionContext;
import com.queplix.core.utils.DateHelper;
import com.queplix.core.utils.StringHelper;
import com.queplix.core.utils.www.AbstractServlet;
import com.queplix.core.utils.www.ServletHelper;

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.servlet.ServletException;
import javax.servlet.SingleThreadModel;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Inbox manager servlet.
 * The following actions are available:
 * <p/>
 * Get the list of all available mail accounts.
 * <br>
 * Usage: <pre>/inboxManager/accList</pre>
 * </p>
 * <p/>
 * <p/>
 * Get the list of all mails belong to selected account.
 * <br>
 * Usage: <pre>/inboxManager/mails?...</pre>
 * <br>
 * Parameters:
 * <ul>
 * <li><b>accId</b> - the account id</li>
 * </ul>
 * </p>
 * <p/>
 * <p/>
 * Get mail body for selected mail message.
 * <br>
 * Usage: <pre>/inboxManager/mailInfo?...</pre>
 * <br>
 * Parameters:
 * <ul>
 * <li><b>pos</b> - position in the list</li>
 * </ul>
 * </p>
 * <p/>
 * <p/>
 * Test account.
 * <br>
 * Usage: <pre>/inboxManager/testAcc?...</pre>
 * <br>
 * Parameters:
 * <ul>
 * <li><b>accId</b> - the account id</li>
 * </ul>
 * </p>
 * <p/>
 * <p/>
 * Process selected mail message.
 * <br>
 * Usage: <pre>/inboxManager/process?...</pre>
 * <br>
 * Parameters:
 * <ul>
 * <li><b>pos</b> - position in the list</li>
 * </ul>
 * </p>
 *
 * @author [ALB] Baranov Andrey
 * @version $Revision: 1.2 $ $Date: 2006/01/24 20:30:20 $
 */

public class InboxManagerServlet
        extends AbstractServlet implements SingleThreadModel {

    // ===================================================== Constants

    public static final String ACC_LIST_NAME = "acc_list_name";
    public static final String MAILS_NAME = "mails_name";
    public static final String MAIL_NAME = "mail_name";

    // ===================================================== Servlet API methods

    /* (non-Javadoc)
     * @see HttpServlet#service(HttpServletRequest, HttpServletResponse)
     */

    public void service(HttpServletRequest request,
                        HttpServletResponse response)
            throws IOException, ServletException {

        // Check permissions.
        //if( SystemHelper.isProductionMode() ) {
        //    throw new ServletException( "Cannot use this servlet in production mode" );
        //}

        // Get action.
        String action = request.getPathInfo();
        if(action != null) {
            action = action.substring(1);
        } else {
            action = StringHelper.EMPTY_VALUE;
        }

        // Action switch.
        try {
            if(action.equalsIgnoreCase("accList")) {
                doAccListAction(request, response);
            } else if(action.equalsIgnoreCase("mails")) {
                doMailsAction(request, response);
            } else if(action.equalsIgnoreCase("mailInfo")) {
                doMailInfoAction(request, response);
            } else if(action.equalsIgnoreCase("testAcc")) {
                doTestAction(request, response);
            } else if(action.equalsIgnoreCase("process")) {
                doProcessAction(request, response);
            } else {
                throw new IllegalStateException("Unknown action: " + action);
            }
        } catch (SecurityException ex) {
            throw new ServletException(ex);
        }
    }

    // ========================================================== Action handlers

    //
    // Collection of Account objects.
    //

    private void doAccListAction(HttpServletRequest request,
                                 HttpServletResponse response)
            throws ServletException, SecurityException, IOException {

        AccountDAO dao = InboxPropertyFactory.getInstance().getAccountDAO();
        Collection ret = dao.loadAllAccountVO();

        // put in request
        request.setAttribute(ACC_LIST_NAME, ret);

        // make redirect
        request.getRequestDispatcher("/tools/inbox/showAccList.jsp").forward(
                request, response);
    }

    //
    // List of Message objects.
    //
    private void doMailsAction(HttpServletRequest request,
                               HttpServletResponse response)
            throws ServletException, SecurityException, IOException {

        long accoundId = ServletHelper.getParamAsLong(request, "id");
        request.setAttribute("id", "" + accoundId);

        List ret = new ArrayList();

        // Load account.
        AccountDAO dao = InboxPropertyFactory.getInstance().getAccountDAO();
        Account account = dao.loadAccountVO(accoundId);
        if(account == null) {
            throw new NullPointerException(
                    "Account #" + accoundId + " not found!");
        }

        // Init sys log publisher.
        SystemLogPublisher publisher = getSysLog();

        // Init Inbox provider.
        Class providerClazz = InboxPropertyFactory.getInstance()
                .getInboxProviderClass(account.getProviderName());
        InboxProvider provider = (InboxProvider) InboxPropertyFactory
                .getInstance().
                getInstance(providerClazz, account, "<*>", publisher);

        // Init Message Builder class.
        Class msgBuilderClazz = InboxPropertyFactory.getInstance()
                .getMessageBuilderClass();

        try {
            // Opening mail session...
            provider.open();

            /** @todo forbid to see more than 50 messages */
            // Get mail ResultSet
            DefaultMessageFilter filter = new DefaultMessageFilter(
                    DateHelper.parseDate("08/08/1976", "dd/MM/yyyy"),
                    // -- just use fake date
                    null, null, false, provider);

            ResultSet rs = provider.getResultSet(filter);

            //
            // Messages processing...
            //

            Message message;
            while((message = rs.next()) != null) {

                // Init Inbox message builder.
                InboxMsgBuilder builder = (InboxMsgBuilder) InboxPropertyFactory
                        .getInstance().
                        getInstance(msgBuilderClazz, account, "<*>", publisher);
                builder.setInboxProvider(provider);

                // Build InboxMessage.
                InboxMessage im;
                try {
                    im = builder.build(message);
                } catch (MessagingException me) {
                    // just report problem
                    logger.ERROR(me);
                    continue;
                }

                logger.DEBUG("Read next message: " + im);

                ret.add(im);
            }

        } catch (ParseException ex) {
            throw new ServletException(ex);

        } catch (MessagingException ex) {
            throw new ServletException(ex);

        } finally {
            try {
                provider.close(false);
            } catch (Exception ex) {
            }
        }

        // store in the session
        request.getSession().setAttribute(MAILS_NAME, ret);

        // put in request
        request.setAttribute(MAILS_NAME, ret);

        // make redirect
        request.getRequestDispatcher("/tools/inbox/showMails.jsp").forward(
                request, response);
    }

    //
    // Show mail body.
    //
    private void doMailInfoAction(HttpServletRequest request,
                                  HttpServletResponse response)
            throws ServletException, SecurityException, IOException {

        int pos = ServletHelper.getParamAsInt(request, "pos");

        // Retrive mail from session.
        List mailList = (List) request.getSession().getAttribute(MAILS_NAME);
        if(mailList == null) {
            response.sendRedirect("/tools/inbox/index.jsp");
            return;
        }

        InboxMessage im = (InboxMessage) mailList.get(pos);
        if(im == null) {
            throw new NullPointerException(
                    "Mail message (pos = " + pos + ") not found in the list!");
        }

        // put in request
        request.setAttribute(MAIL_NAME, im);

        // make redirect
        request.getRequestDispatcher("/tools/inbox/showMailBody.jsp").forward(
                request, response);
    }

    //
    // Test account.
    //
    private void doTestAction(HttpServletRequest request,
                              HttpServletResponse response)
            throws ServletException, SecurityException, IOException {

        long accoundId = ServletHelper.getParamAsLong(request, "id");
        request.setAttribute("id", "" + accoundId);

        // Load account.
        AccountDAO dao = InboxPropertyFactory.getInstance().getAccountDAO();
        Account account = dao.loadAccountVO(accoundId);
        if(account == null) {
            throw new NullPointerException(
                    "Account #" + accoundId + " not found!");
        }

        // Init Inbox provider.
        Class clazz = InboxPropertyFactory.getInstance().getInboxProviderClass(
                account.getProviderName());
        InboxProvider provider = (InboxProvider) InboxPropertyFactory
                .getInstance().
                getInstance(clazz, account, "<*>", getSysLog());

        try {
            // Do check account.
            provider.checkAccount();

            // Print Out.
            response.setContentType(ServletHelper.CONTENT_TYPE_HTML);
            response.getWriter().print(
                    "<p style='font-size: 16px; color: green'>Account #"
                            + accoundId + " is valid!</p>");

        } catch (InvalidAccountException ex) {

            // Print Out.
            response.setContentType(ServletHelper.CONTENT_TYPE_HTML);
            response.getWriter().print(
                    "<p style='font-size: 16px; color: red'>Account #"
                            + accoundId +
                            " is invalid!</p><br><br>Error: " + ex
                            .getMessage());
        }
    }

    //
    // Process mail.
    //
    private void doProcessAction(HttpServletRequest request,
                                 HttpServletResponse response)
            throws ServletException,
            com.queplix.core.integrator.security.SecurityException,
            IOException {

        int pos = ServletHelper.getParamAsInt(request, "pos");

        // Retrive mail from session.
        List mailList = (List) request.getSession().getAttribute(MAILS_NAME);
        if(mailList == null) {
            response.sendRedirect("/tools/inbox/index.jsp");
            return;
        }

        InboxMessage im = (InboxMessage) mailList.get(pos);
        if(im == null) {
            throw new NullPointerException(
                    "Mail message (pos = " + pos + ") not found in the list!");
        }

        // Load account.
        long accountId = im.getAccountId().longValue();
        AccountDAO dao = InboxPropertyFactory.getInstance().getAccountDAO();
        Account account = dao.loadAccountVO(accountId);
        if(account == null) {
            throw new NullPointerException(
                    "Account #" + accountId + " not found!");
        }

        // Preparing the Inbox action parameters.
        Map params = new HashMap();
        params.put("im", im);
        params.put("account", account);

        // Init sys log publisher.
        SystemLogPublisher publisher = getSysLog();

        // Init action context.
        XAActionContext xa = new XAActionContext(publisher.getLogonSession(),
                publisher);

        // Call InboxAction.
        InboxAction inboxAction = new InboxAction();
        xa.addParameters(params);
        try {
            ActionRunner.runAsXA(inboxAction, xa);

            // Print Out.
            response.setContentType(ServletHelper.CONTENT_TYPE_HTML);
            response.getWriter().print(
                    "<p style='font-size: 16px; color: green'>Message #" +
                            im.getMessageUid()
                            + " went to process routine.</p>");
        } catch (Throwable t) {
            logger.ERROR(t);

            // Print Out.
            response.setContentType(ServletHelper.CONTENT_TYPE_HTML);
            response.getWriter().print(
                    "<p style='font-size: 16px; color: red'>Message #" +
                            im.getMessageUid() + " processing failed.</p>" +
                            "<br><br>Error: " + t.getMessage());
        }
    }

    //
    // Constructs SystemLogPublisher.
    //
    protected SystemLogPublisher getSysLog()
            throws ServletException {

        LogonSession ls;
        ls = AccessRightsManager.getSystemLogonSession();
        return new SystemLogPublisher(ls);
    }
}
