/*
 * ICESOFT COMMERCIAL SOURCE CODE LICENSE V 1.1
 *
 * The contents of this file are subject to the ICEsoft Commercial Source
 * Code License Agreement V1.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.icesoft.com/license/commercial-source-v1.1.html
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations under
 * the License.
 *
 * Copyright 2009-2015 ICEsoft Technologies Canada, Corp. All Rights Reserved.
 */

package com.icesoft.servlet;

import java.io.File;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Collections;
import java.util.Map;
import java.util.HashMap;
import java.util.List;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileUpload;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;

import java.util.logging.Level;
import java.util.logging.Logger;

public class MultipartFilter implements Filter  {
    static Logger logger = Logger.getLogger(MultipartFilter.class.getName());
    FilterConfig filterConfig = null;
    FileUpload fileUpload = new FileUpload();

    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;

        fileUpload.setFileItemFactory(new DiskFileItemFactory());
        String fileSizeMax = filterConfig.getInitParameter("fileSizeMax");
        if (null != fileSizeMax)  {
            fileUpload.setFileSizeMax(Integer.parseInt(fileSizeMax));
        }

    }

    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws ServletException, IOException  {
        HttpServletRequest httpRequest = (HttpServletRequest) request;

        if (FileUpload.isMultipartContent(httpRequest))  {
            try {
                httpRequest = new MultipartWrapper( httpRequest, 
                        fileUpload.parseRequest(httpRequest) );
            } catch (Exception e) {
                throw new ServletException("Multipart wrap failed ", e);
            }
        }

        chain.doFilter(httpRequest, response);

    }

    public void destroy() {
    }

}


class MultipartWrapper extends HttpServletRequestWrapper {
    List<FileItem> parts = null;
    HashMap params = new HashMap();

    MultipartWrapper(final HttpServletRequest request, final List items) {
        super(request);
        this.parts = (List<FileItem>) items;

        for(FileItem item : parts) {
            if (item.isFormField()) {
                addValue(item.getFieldName(), item.getString());
            } else {
                try {
                    HashMap fileMeta = new HashMap();
                    fileMeta.put("stream", item.getInputStream());
                    fileMeta.put("contentType", item.getContentType());
                    request.setAttribute(
                        "org.icemobile.file." + item.getFieldName(), fileMeta);
                } catch (Exception e)  {
                   MultipartFilter.logger.log(Level.WARNING, 
                        "Cannot extract part " + item.getFieldName(), e);
                }
            }
        }
    }

    public String getParameter(String name)  {
        String[] values = (String[]) params.get(name);
        if (null == values)  {
            return null;
        }
        return values[0];
    }

    public Map getParameterMap() {
        return params;
    }

    public Enumeration getParameterNames()  {
        return Collections.enumeration(params.keySet());
    }


    public String[] getParameterValues(String name) {
        return (String[]) params.get(name);
    }

    private void addValue(String name, String value) {
        String[] param = (String[]) params.get(name);
        if (null == param)  {
            params.put(name, new String[] {value});
        } else {
           String[] larger = new String[param.length + 1];
           System.arraycopy(param, 0, larger, 0, param.length);
           larger[param.length] = value;
           params.put(name, larger);
        }
    }

}
