/*
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999-2005 Bull S.A.
 * Contact: jonas-team@objectweb.org
 *
 * This 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 any later version.
 *
 * This 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 library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * Initial developer(s): Brice Ruzand
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */
package emb.sample.servlet;

import java.io.Serializable;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;

import javax.emb.MediaEntityLocal;
import javax.emb.MediaEntityLocalHome;
import javax.emb.MediaException;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import emb.sample.MediaSampleException;
import emb.sample.session.MediaSampleSessionLocal;
import emb.sample.session.MediaSampleSessionLocalHome;

/**
 * Base classes for all sample
 *
 * @author Brice Ruzand
 */
public class BaseSampleServlet extends HttpServlet {

    /**
     * serialVersionUID
     */
    private static final long serialVersionUID = 428471464384262530L;

    /*
     * =======================================================================
     * Sample apps
     * =======================================================================
     */

    /**
     * Retrive servlet URI
     */
    protected static final String RETRIEVE_SERVLET = "/RetrieveSampleMedia";

    /**
     * Retrive servlet URI
     */
    protected static final String ACTION_DISPATCHER_SERVLET = "/ActionDispatcher";

    /**
     * template jsp URI
     */
    protected static final String TEMPLATE_JSP = "/jsps/templatePage.jsp";

    /**
     * tranforme Byte in KB
     */
    public static final double BYTE_IN_KB = 1024D;

    /**
     * Random seed
     */
    protected static final Random RANDOM = new Random();

    /**
     * Default format for time stamp
     */
    public static final SimpleDateFormat TIME_STAMP_FORMAT = new SimpleDateFormat("yy-MM-dd HH:mm:ss.SSS");

    /**
     * Default format for size
     */
    public static final DecimalFormat SIZE_FORMAT = new DecimalFormat("0.0");

    /**
     * Display medi info in XHTML
     *
     * @param sp StringPrinter
     * @param meb The media entity
     */
    protected void displayInfo(StringPrinter sp, MediaEntityLocal meb) {

        try {
            sp.println("Name : " + meb.getName() + "<br/>");
            sp.println("MimeType : " + meb.getMimeType() + "<br/>");
            sp.println("Size : " + SIZE_FORMAT.format(meb.getSize() / BYTE_IN_KB) + "&nbsp;KB<br/>");
            String desc = meb.getDescription();
            if (desc == null) {
                desc = "";
            }
            sp.println("Description : <div>" + meb.getDescription() + "</div><br/>");
            sp.println("LastModified : <div>" + TIME_STAMP_FORMAT.format(new Date(meb.getLastModified()))
                    + "</div><br/>");
        } catch (MediaException e) {
            sp.println("<span class=error>Error while retriving medi info</span>");
        }
    }

    /**
     * Get a session bean to manage Media creation
     *
     * @param request the HttpServlet request
     * @return the MediaSampleSessionLocal
     * @throws MediaSampleException if session cannot be created
     */
    protected static MediaSampleSessionLocal getSession(HttpServletRequest request) throws MediaSampleException {
        try {
            MediaSampleSessionLocal sessionBean = (MediaSampleSessionLocal) request.getSession().getAttribute(
                    "sessionBean");

            if (sessionBean == null) {
                sessionBean = getSessionHome().create();
                request.getSession().setAttribute("sessionBean", sessionBean);
                throw new MediaSampleException("Your session has exprired, please reload some medias");
            }
            return sessionBean;
        } catch (MediaSampleException e) {
            throw e;
        } catch (Exception e) {
            // e.printStackTrace();
            throw new MediaSampleException("Unable to create a new session", e);

        }
    }

    /*
     * =======================================================================
     * Errors
     * =======================================================================
     */

    /**
     * Method to handle all exceptions of all Music Application Servlets in a
     * uniform way using the specified error JSP (/jps/templatePage.jsp).
     * <p>
     * In case of error a ServletException will be thrown.
     *
     * @param exception java.lang.Exception
     * @param errorClass class where the error locate
     * @param request com.sun.server.http.HttpServletRequest
     * @param response com.sun.server.http.HttpServletResponse
     * @throws ServletException This exception will be thrown if the
     *             errorhandling fails
     */
    protected void exceptionHandler(Throwable exception, Class errorClass, HttpServletRequest request,
            HttpServletResponse response) throws ServletException {

        StringPrinter errorMessage = new StringPrinter();

        try {

            if (exception instanceof MediaSampleException) {

                errorMessage.println("<h2>There was an error</h2>");
                errorMessage.println(exception.getLocalizedMessage());
                request.setAttribute("workspaceContent", errorMessage);
                getServletConfig().getServletContext().getRequestDispatcher(TEMPLATE_JSP).forward(request, response);

            } else {

                errorMessage.println(errorClass.getName() + ":");
                errorMessage.println("");
                errorMessage.println(exception.toString());
                errorMessage.println("");
                errorLog(errorClass.getName() + ": " + exception);

                StackTraceElement[] ste;
                if (exception.getCause() != null) {
                    ste = exception.getCause().getStackTrace();
                } else {
                    ste = exception.getStackTrace();
                }

                for (int i = 0; i < ste.length; i++) {

                    errorMessage.println(ste[i].toString());
                    // when the source cause is found stop stack
                    if (ste[i].getClassName().startsWith("emb.sample")) {
                        break;
                    }
                }

                request.setAttribute("errorMessage", errorMessage);
                getServletConfig().getServletContext().getRequestDispatcher(TEMPLATE_JSP).forward(request, response);

            }

        } catch (Exception e) {
            // if standard error reporter fails throw exception
            throw new ServletException(errorMessage.toString(), e);
        }
    }

    /**
     * Method to print error messages to stderr and for syschronisation purpose
     * to stdout too.
     *
     * @param msg java.lang.String
     */
    protected static void errorLog(String msg) {
        final int defBuffer = 1024;
        StringBuffer bfr = new StringBuffer(defBuffer);

        bfr.append("[");
        bfr.append(TIME_STAMP_FORMAT.format(new Date(System.currentTimeMillis())));
        bfr.append("] EMB SAMPLE ERROR ");
        bfr.append(msg);

        System.err.println(bfr.toString());
    }

    /**
     * Class to use printer
     *
     * @author Brice Ruzand
     */
    protected class StringPrinter implements Serializable {

        /**
         * serialVersionUID
         */
        private static final long serialVersionUID = -2865716341020911272L;

        /**
         * The String Buffer
         */
        private StringBuffer buffer;

        /**
         * Default Constructor
         */
        public StringPrinter() {

            final int newbuffsize = 128;
            buffer = new StringBuffer(newbuffsize);
        }

        /**
         * Print a line in the printer
         *
         * @param str the string to print
         */
        public void println(String str) {
            buffer.append(str);
            buffer.append("\r\n");
        }

        /**
         * @see java.lang.Object#toString()
         */
        public String toString() {
            return buffer.toString();
        }
    }

    /*
     * =======================================================================
     * EJB TOOLS
     * =======================================================================
     */

    /**
     * Media Enotity Bean Home reference
     */
    private static final String SESSION_HOME_REF = "java:comp/env/ejb/embSample/MediaSampleSession";

    /**
     * Media Entity Bean Home reference
     */
    private static final String MEB_HOME_REF = "java:comp/env/ejb/emb/MediaEntity";

    /**
     * cached Home
     */
    private static MediaSampleSessionLocalHome mebSessionHome = null;

    /**
     * cached Home
     */
    private static MediaEntityLocalHome mebHome = null;

    /**
     * Provide a cached Home access
     *
     * @return MediaEntityLocalHome
     * @throws NamingException in case MediaEntityLocalHome is not found
     */
    protected static MediaSampleSessionLocalHome getSessionHome() throws NamingException {
        if (mebSessionHome == null) {
            mebSessionHome = (MediaSampleSessionLocalHome) new InitialContext().lookup(SESSION_HOME_REF);
        }
        return mebSessionHome;
    }

    /**
     * Provide a cached Home access
     *
     * @return MediaEntityLocalHome
     * @throws NamingException in case MediaEntityLocalHome is not found
     */
    protected static MediaEntityLocalHome getMebHome() throws NamingException {
        if (mebHome == null) {
            mebHome = (MediaEntityLocalHome) new InitialContext().lookup(MEB_HOME_REF);
        }
        return mebHome;
    }

}
