/*
 * 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.security.www;

import com.queplix.core.error.GenericAppException;
import com.queplix.core.error.GenericSystemException;
import com.queplix.core.error.LocalizedAppException;
import com.queplix.core.integrator.security.LogonSession;
import com.queplix.core.jxb.error.QwException;
import com.queplix.core.modules.config.ejb.CaptionManagerLocal;
import com.queplix.core.modules.config.ejb.CaptionManagerLocalHome;
import com.queplix.core.modules.services.utils.log.impl.MailLogPublisher;
import com.queplix.core.utils.JNDINames;
import com.queplix.core.utils.StringHelper;
import com.queplix.core.utils.SystemHelper;

import javax.ejb.EJBException;
import javax.naming.InitialContext;
import javax.servlet.http.HttpServletRequest;
import java.io.PrintWriter;
import java.io.StringWriter;

/**
 * Hepler class for exception handling in servlets / JSP.
 *
 * @author [ALB] Baranov Andrey
 * @version $Revision: 1.2 $ $Date: 2006/07/31 14:45:19 $
 */
public class ErrorServletHelper {

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

    public static final String SERVLET_ERROR_MSG
            = "javax.servlet.error.message";
    public static final String SERVLET_ERROR_EXCEPTION
            = "javax.servlet.error.exception";
    public static final String SERVLET_ERROR_URI
            = "javax.servlet.error.request_uri";

    // ================================================================= Fields

    private HttpServletRequest request;
    private String referer;

    // ========================================================= Initialization

    /**
     * Constructor
     *
     * @param request HTTP request
     */
    public ErrorServletHelper(HttpServletRequest request) {
        this.request = request;
    }

    // ========================================================= Public methods

    /**
     * Gets the localized message
     *
     * @param t given exception
     * @return localized message
     */
    public String getLocalizedMessage(Throwable t) {
        // Check for non-localized message.
        if(!(t instanceof LocalizedAppException)) {
            String s = t.getMessage();
            return (s != null) ? s:t.getClass().getName();
        }

        // Get localized message.
        CaptionManagerLocal captionManager = getCaptionManagerLocal();
        LogonSession ls = com.queplix.core.integrator.security.WebLoginManager
                .getLogonSession(request);
        String langId = com.queplix.core.integrator.security.WebLoginManager
                .getLogonLanguage(ls);
        String localizedMessage = captionManager.getServerMessage(langId,
                t.getMessage());

        // Formatted localized message.
        LocalizedAppException ex = (LocalizedAppException) t;

        // Ok.
        return StringHelper.format(localizedMessage, ex.getArgs());

    }

    /**
     * Handles exception.
     *
     * @param t   user exception to handle
     * @param msg user error message
     * @param url user url
     * @return <code>QwException</code> instance.
     */
    public QwException process(Throwable t, String msg, String url) {

        // Handle exception.
        if(t != null) {

            // Get exception cause. 
            t = getCauseException(t);

            // Log message and / or stacktrace.
            if(!(t instanceof GenericAppException)) {
                System.out.println("\n\nError: ================");
                t.printStackTrace();
                System.out.println("================\n\n");
            } else if(!SystemHelper.isProductionMode()) {
                System.out.println("\n\nWarning: ================");
                System.out.println(getLocalizedMessage(t));
                System.out.println("Stack trace:");
                t.printStackTrace();
                System.out.println("================\n\n");
            }

        }

        // Handle message.
        if(msg != null) {
            System.out.println("\n\nError: ================");
            System.out.println(msg);
            System.out.println("================\n\n");
        }

        // Send error notification by e-mail.
        if(t == null || !(t instanceof GenericAppException)) {
            System.out.println("Send error mail!");
            sendErrorMail(msg, t);
        }

        // Make wrapper object.
        QwException qe = new QwException();
        qe.setCode((t != null) ? t.getClass().getName():"");
        qe.setMessage((t != null) ? getLocalizedMessage(t):msg);
        qe.setUri(url);
        if(t != null) {
            StringWriter sw = new StringWriter();
            t.printStackTrace(new PrintWriter(sw));
            qe.setDebug(sw.toString());
        }

        // Ok.
        return qe;

    }

    /**
     * Handles exception using the HTTP request attributes.
     *
     * @return exception wrapper object.
     */
    public QwException process() {

        Throwable t = null;
        String errorMsg = null;
        String url = null;

        Object value = request.getAttribute(SERVLET_ERROR_EXCEPTION);
        if(value != null && value instanceof Throwable) {
            t = (Throwable) value;
        } else {
            value = request.getAttribute(SERVLET_ERROR_MSG);
            if(value != null) {
                errorMsg = value.toString();
            }
        }

        // Get URL, where exception occured
        value = request.getAttribute(SERVLET_ERROR_URI);
        if(value != null) {
            url = value.toString();
        }

        //Get referer header
        referer = request.getHeader("referer");

        // Ok.
        return process(t, errorMsg, url);

    }

    // ======================================================== Private methods

    // Sends error message.

    private void sendErrorMail(String message, Throwable t) {
        try {
            LogonSession ls = com.queplix.core.integrator.security
                    .WebLoginManager.getLogonSession(request);
            new MailLogPublisher(ls, getClass()).ERROR(message, t, referer);
        } catch (Throwable t2) {
            System.out.println("\n\nUnknown error sending mail alert: >>>");
            t2.printStackTrace();
            System.out.println("<<< \n\n");
        }
    }

    // Returns exception cause.
    private Throwable getCauseException(Throwable t) {

        // Check for null.
        if(t == null) {
            return null;
        }

        // Check for EJB - take cause recursively.
        if((t instanceof EJBException)
                && ((EJBException) t).getCausedByException() != null) {
            return getCauseException(((EJBException) t).getCausedByException());
        } else {
            return t;
        }

    }

    // Gets Caption Manager EJB local interface.
    public static CaptionManagerLocal getCaptionManagerLocal() {
        try {
            InitialContext context = new InitialContext();
            CaptionManagerLocalHome home = (CaptionManagerLocalHome) context
                    .lookup(JNDINames.CaptionManager);
            return home.create();
        } catch (Exception ex) {
            throw new GenericSystemException(
                    "Can't get CaptionManagerLocal by the name '"
                            + JNDINames.CaptionManager
                            + "'", ex);
        }
    }

}