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

import com.queplix.core.integrator.security.LogonSession;
import com.queplix.core.integrator.security.WebLoginManager;
import com.queplix.core.modules.attachment.ejb.AttachmentManagerLocal;
import com.queplix.core.modules.attachment.ejb.AttachmentManagerLocalHome;
import com.queplix.core.modules.inbox.InboxHelper;
import com.queplix.core.modules.jeo.gen.AttachmentObject;
import com.queplix.core.modules.jeo.gen.AttachmentTempObject;
import com.queplix.core.modules.mail.Attachment;
import com.queplix.core.utils.JNDINames;
import com.queplix.core.utils.StringHelper;
import com.queplix.core.utils.www.AbstractServlet;
import com.queplix.core.utils.www.ServletHelper;
import org.apache.commons.fileupload.DiskFileUpload;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadBase;
import org.apache.commons.fileupload.FileUploadException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.List;

/**
 * Manages attachments.
 * <p/>
 * <p/>
 * Usage falls into the following categories:
 * </p>
 * <p/>
 * <h4>Get a new unique process ID.</h4>
 * <p/>
 * Usage: <pre>GET /attachmentUpload/getProcessID</pre>
 * </p>
 * <p/>
 * <h4>Get the temporary attachment</h4>
 * <p/>
 * Usage: <pre>GET /attachmentUpload/getTemp?id=123</pre>
 * <br>
 * Parameters:
 * <ul>
 * <li><b>id</b> - temporary attachment ID</li>
 * </ul>
 * </p>
 * <p/>
 * <h4>Remove the temporary attachment(s)</h4>
 * <p/>
 * Usage: <pre>GET /attachmentUpload/deleteTemp?(process_id=123 | id=123)</pre>
 * <br>
 * Parameters:
 * <ul>
 * <li><b>process_id</b> - temporary attachment(s) process ID</li>
 * <li><b>id</b> - temporary attachment ID</li>
 * </ul>
 * </p>
 * <p/>
 * <h4>Save the temporary attachment</h4>
 * <p/>
 * Usage: <pre>POST /attachmentUpload/saveTemp?process_id=123[&purge=0|1]</pre>
 * <br>
 * Parameters:
 * <ul>
 * <li><b>process_id</b> - temporary attachment process ID</li>
 * <li><b>purge</b> - if 1, delete all existing attachments with the same process ID</li>
 * </ul>
 * </p>
 * <p/>
 * <h4>Get the regular attachment</h4>
 * <p/>
 * Usage: <pre>GET /attachmentUpload/get?id=123</pre>
 * <br>
 * Parameters:
 * <ul>
 * <li><b>id</b> - regular attachment ID</li>
 * </ul>
 * </p>
 *
 * @author [ALB] Baranov Andrey
 * @author [ONZ] Oleg N. Zhovtanyuk
 * @version $Revision: 1.5 $ $Date: 2006/06/09 10:44:59 $
 */
public class AttachmentUploadServlet
        extends AbstractServlet {

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

    // Initialization parameters.
    private static final String MAX_UPLOAD_SIZE_PARAM = "maxUploadSize";

    // Servlet parameters.
    private static final String ID_PARAM = "id";
    private static final String PROCESS_ID_PARAM = "process_id";
    private static final String PURGE_PARAM = "purge";
    private static final String FILE_NAME_PARAM = "filename";

    // Actions.
    private static final String GET_ID_ACTION = "getProcessID";
    private static final String GET_TEMP_ACTION = "getTemp";
    private static final String SAVE_TEMP_ACTION = "saveTemp";
    private static final String DELETE_TEMP_ACTION = "deleteTemp";
    private static final String GET_ACTION = "get";
    private static final String GETBYPROC_ACTION = "getpridf";

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

    // Initialization parameters.
    private int maxUploadSize;

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

    /* (non-Javadoc)
     * @see AbstractServlet#init(ServletConfig)
     */

    public void init(ServletConfig conf)
            throws ServletException {

        super.init(conf);

        maxUploadSize = Integer.parseInt(conf.getInitParameter(
                MAX_UPLOAD_SIZE_PARAM));

        if(logger.getLogger().isDebugEnabled()) {
            logger.DEBUG("Initialization: max. upload size = " + maxUploadSize);
        }

    }

    /* (non-Javadoc)
     * @see HttpServlet#service(HttpServletRequest, HttpServletResponse)
     */
    public void service(HttpServletRequest req, HttpServletResponse res)
            throws IOException, ServletException {

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

        // Action switch.
        try {
            if(action.equalsIgnoreCase(GET_ID_ACTION)) {
                doGetProcessIDAction(req, res);
            } else if(action.equalsIgnoreCase(GET_ACTION)) {
                doGetAction(req, res);
            } else if(action.equalsIgnoreCase(GETBYPROC_ACTION)) {
                doGetByProcessIdFNameAction(req, res);
            } else if(action.equalsIgnoreCase(GET_TEMP_ACTION)) {
                doGetTempAction(req, res);
            } else if(action.equalsIgnoreCase(SAVE_TEMP_ACTION)) {
                doSaveTempAction(req, res);
            } else if(action.equalsIgnoreCase(DELETE_TEMP_ACTION)) {
                doDeleteTempAction(req, res);
            } else {
                throw new ServletException("Unknown action: '" + action + "'");
            }
        } catch (SecurityException ex) {
            throw new ServletException(ex);
        }

    }

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

    // Gets a new process ID.

    private void doGetProcessIDAction(HttpServletRequest req,
                                      HttpServletResponse res)
            throws ServletException, SecurityException, IOException {

        AttachmentManagerLocal manager = getAttachmentManager();
        long processID = manager.getUniqueProcessID();

        res.setContentType(ServletHelper.CONTENT_TYPE_TEXT);
        res.getWriter().print(processID);

    }

    // Gets the regular attachment.
    private void doGetAction(HttpServletRequest req, HttpServletResponse res)
            throws ServletException, SecurityException, IOException {

        long attachID = ServletHelper.getParamAsLong(req, ID_PARAM);

        AttachmentManagerLocal manager = getAttachmentManager();
        LogonSession ls = WebLoginManager.getLogonSession(req);

        AttachmentObject obj = manager.getAttachment(ls, attachID);
        if(obj != null) {
            Attachment attachment = new Attachment(obj);
            writeOut(res, attachment);
        }
    }

    // Gets the regular attachment by the Processid and filename.
    private void doGetByProcessIdFNameAction(HttpServletRequest req,
                                             HttpServletResponse res)
            throws ServletException, SecurityException, IOException {

        long processID = ServletHelper.getParamAsLong(req, PROCESS_ID_PARAM);
        String fileName = ServletHelper.getParamAsString(req, FILE_NAME_PARAM);

        AttachmentManagerLocal manager = getAttachmentManager();
        LogonSession ls = WebLoginManager.getLogonSession(req);

        AttachmentObject obj = manager.getAttachment(ls, processID, fileName);
        if(obj != null) {
            Attachment attachment = new Attachment(obj);
            writeOut(res, attachment);
        }
    }

    // Gets the temporary attachment.
    private void doGetTempAction(HttpServletRequest req,
                                 HttpServletResponse res)
            throws ServletException, SecurityException, IOException {

        long tempAttachID = ServletHelper.getParamAsLong(req, ID_PARAM);

        AttachmentManagerLocal manager = getAttachmentManager();
        LogonSession ls = WebLoginManager.getLogonSession(req);

        AttachmentTempObject obj = manager.getTempAttachment(ls, tempAttachID);
        if(obj != null) {
            Attachment attachment = new Attachment(obj);
            writeOut(res, attachment);
        }

    }

    // Deletes the temporary attachment(s).
    private void doDeleteTempAction(HttpServletRequest req,
                                    HttpServletResponse res)
            throws ServletException, SecurityException, IOException {

        AttachmentManagerLocal manager = getAttachmentManager();
        LogonSession ls = WebLoginManager.getLogonSession(req);

        logger.DEBUG("DeleteTemp action is called!");
        if(req.getParameter(ID_PARAM) != null) {
            long[] ids = ServletHelper.getAllParamValuesAsLong(req, ID_PARAM);
            logger.DEBUG("ID[] = " + StringHelper.toString(ids));
            if(ids.length == 1) {
                manager.deleteTempAttachment(ls, ids[0]);
            } else {
                manager.deleteTempAttachments(ls, ids);
            }
        } else {
            long processID = ServletHelper.getParamAsLong(req,
                    PROCESS_ID_PARAM);
            manager.deleteTempAttachments(ls, processID);
        }

    }

    // Saves temporary attachment.
    private void doSaveTempAction(HttpServletRequest req,
                                  HttpServletResponse response)
            throws ServletException, SecurityException, IOException {

        try {
            // Get the purge flag.
            boolean purge = ServletHelper.getParamAsBoolean(req, PURGE_PARAM);

            // Get file parameters.
            FileItem fileItem = null;
            String prID = null;

            DiskFileUpload fileUpload = new DiskFileUpload();
            fileUpload.setSizeMax(maxUploadSize);
            List items = null;
            try {
                items = fileUpload.parseRequest(req);
            } catch (FileUploadBase.SizeLimitExceededException e) {
                String message = "<html>" +
                        "<head></head>" +
                        "<body onload=\"alert('File\\'s size exceeds allowed range'); window.close();\">"
                        +
                        "</body>" +
                        "</html>";
                response.setContentType(ServletHelper.CONTENT_TYPE_HTML);
                response.getWriter().write(message);
                return;
            }
            for(Iterator it = items.iterator(); it.hasNext();) {
                FileItem item = (FileItem) it.next();
                if(!item.isFormField()) {
                    fileItem = item;
                }
            }

            prID = ServletHelper.getParamAsString(req, PROCESS_ID_PARAM);

            // Null checks.
            if(fileItem == null) {
                throw new NullPointerException("file");
            }
            if(StringHelper.isEmpty(prID)) {
                throw new NullPointerException(PROCESS_ID_PARAM);
            }
            String fileName = fileItem.getName();
            if(fileName == null) {
                throw new NullPointerException("Got NULL file name");
            }
            long processID = Long.parseLong(prID);

            // Full and short names.
            String fullName = fileName.replace('\\', '/');
            String shortName;
            int pos = fullName.lastIndexOf("/");
            if(pos >= 0) {
                shortName = fileName.substring(pos + 1);
            } else {
                shortName = fullName;
            }

            String fileType = fileItem.getContentType();
            byte[] data = fileItem.get();

            // Save file and return temporary attachment ID.
            AttachmentManagerLocal manager = getAttachmentManager();
            LogonSession ls = WebLoginManager.getLogonSession(req);
            long tempAttachID = manager.addTempAttachment(ls, processID,
                    shortName, fileType, data, purge);
            if(tempAttachID == StringHelper.EMPTY_NUMBER) {
                throw new NullPointerException(
                        "Can't save selected attachment to database.");
            }
            // Send response
            response.setContentType(ServletHelper.CONTENT_TYPE_TEXT);
            PrintWriter out = response.getWriter();
            out.println("|" + tempAttachID + "|RESULT=SUCCESS|");
        } catch (FileUploadException ex) {
            throw new ServletException(ex);
        }

    }

    // =================================================== Other private methods

    // Write <code>attachment</code> out.

    private void writeOut(HttpServletResponse res, Attachment attachment)
            throws IOException {

        String fileName = InboxHelper.normalizeAttachmentName(
                attachment.getFilename(), 1);
        String type = attachment.getFiletype();
        res.setContentType(
                (type == null) ? ServletHelper.CONTENT_TYPE_BINARY:type);

        // Set 'Content-Disposition' - browser will show "Save As" dialog
        res.setHeader("Content-Disposition",
                "attachment; filename=" + fileName);

        res.getOutputStream().write(attachment.getData());
    }

    // Attachment Manager EJB reference getter.
    private AttachmentManagerLocal getAttachmentManager()
            throws ServletException {
        return (AttachmentManagerLocal) getLocalObject(
                JNDINames.AttachmentManager, AttachmentManagerLocalHome.class);
    }

}
