/*
 * Copyright 2008-2009 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 *
 * 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 net.hasor.web;
import net.hasor.core.AppContext;
import net.hasor.core.Settings;
import net.hasor.utils.StringUtils;
import net.hasor.utils.io.FilenameUtils;
import net.hasor.web.annotation.Produces;
import net.hasor.web.render.RenderInvoker;
import net.hasor.web.upload.FileUpload;
import net.hasor.web.upload.factorys.disk.DiskFileItemFactory;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.*;

/**
 * Controller <br>
 * 昨夜西风凋碧树。独上高楼，望尽天涯路。 <br>
 * 衣带渐宽终不悔，为伊消得人憔悴。 <br>
 * 众里寻她千百度，蓦然回首，那人却在灯火阑珊处。
 *
 * @version : 2013-8-14
 * @author JFinal
 * @author 赵永春 (zyc@hasor.net)
 */
public class WebController implements Controller {
    private final ThreadLocal<Invoker> invoker = new ThreadLocal<>();

    public void initController(Invoker renderData) {
        if (this.invoker.get() != null) {
            this.invoker.remove();
        }
        if (renderData != null) {
            this.invoker.set(renderData);
        }
    }

    protected Invoker getInvoker() {
        return this.invoker.get();
    }

    protected <T extends Invoker> T getInvoker(Class<T> invokerType) {
        Invoker invoker = getInvoker();
        if (invokerType.isInstance(invoker)) {
            return (T) invoker;
        } else {
            return null;
        }
    }

    /** @return Return HttpServletRequest. Do not use HttpServletRequest Object in constructor of Controller */
    public HttpServletRequest getRequest() {
        return this.getInvoker().getHttpRequest();
    }

    /** @return Return HttpServletResponse. Do not use HttpServletResponse Object in constructor of Controller */
    public HttpServletResponse getResponse() {
        return this.getInvoker().getHttpResponse();
    }

    /** @return Return AppContext. */
    public AppContext getAppContext() {
        return this.getInvoker().getAppContext();
    }
    //------------------------

    /**
     * 设置{@link HttpServletResponse}Header属性
     * @param key 参数 key
     * @param value 参数值
     * @return 返回this.
     */
    protected WebController setHeader(String key, String value) {
        this.getResponse().setHeader(key, value);
        return this;
    }

    /**
     * 设置{@link HttpServletResponse}Header属性
     * @param key 参数 key
     * @param value 参数值
     * @return 返回this.
     */
    protected WebController addHeader(String key, String value) {
        this.getResponse().addHeader(key, value);
        return this;
    }
    //------------------------

    /**
     * Returns the value of a request parameter as a String, or null if the parameter does not exist.
     * <p>
     * You should only use this method when you are sure the parameter has only one value. If the parameter might have more than one value, use getParaValues(java.lang.String).
     * <p>
     * If you use this method with a multivalued parameter, the value returned is equal to the first value in the array returned by getParameterValues.
     * @param name a String specifying the name of the parameter
     * @return a String representing the single value of the parameter
     */
    protected String getPara(String name) {
        return this.getRequest().getParameter(name);
    }

    /**
     * Returns the value of a request parameter as a String, or default value if the parameter does not exist.
     * @param name a String specifying the name of the parameter
     * @param defaultValue a String value be returned when the value of parameter is null
     * @return a String representing the single value of the parameter
     */
    protected String getPara(String name, String defaultValue) {
        String result = this.getRequest().getParameter(name);
        return result != null && !"".equals(result) ? result : defaultValue;
    }

    /**
     * Returns the values of the request parameters as a Map.
     * @return a Map contains all the parameters name and value
     */
    protected Map<String, String[]> getParaMap() {
        return this.getRequest().getParameterMap();
    }

    /**
     * Returns an Enumeration of String objects containing the names of the parameters contained in this request. If the request has no parameters, the method returns an empty Enumeration.
     * @return an Enumeration of String objects, each String containing the name of a request parameter; or an empty Enumeration if the request has no parameters
     */
    protected Enumeration<String> getParaNames() {
        return this.getRequest().getParameterNames();
    }

    /**
     * Returns an array of String objects containing all of the values the given request parameter has, or null if the parameter does not exist. If the parameter has a single value, the array has a length of 1.
     * @param name a String containing the name of the parameter whose value is requested
     * @return an array of String objects containing the parameter's values
     */
    protected String[] getParaValues(String name) {
        return this.getRequest().getParameterValues(name);
    }

    /**
     * Returns an array of Integer objects containing all of the values the given request parameter has, or null if the parameter does not exist. If the parameter has a single value, the array has a length of 1.
     * @param name a String containing the name of the parameter whose value is requested
     * @return an array of Integer objects containing the parameter's values
     */
    protected Integer[] getParaValuesToInt(String name) {
        String[] values = this.getRequest().getParameterValues(name);
        if (values == null)
            return null;
        Integer[] result = new Integer[values.length];
        for (int i = 0; i < result.length; i++)
            result[i] = Integer.parseInt(values[i]);
        return result;
    }
    //------------------------

    /**
     * Returns the value of a request parameter and convert to Integer.
     * @param name a String specifying the name of the parameter
     * @return a Integer representing the single value of the parameter
     */
    protected Integer getParaToInt(String name) {
        return toInt(this.getRequest().getParameter(name), null);
    }

    /**
     * Returns the value of a request parameter and convert to Integer with a default value if it is null.
     * @param name a String specifying the name of the parameter
     * @param defaultValue default value for the parameter
     * @return a Integer representing the single value of the parameter
     */
    protected Integer getParaToInt(String name, Integer defaultValue) {
        return toInt(this.getRequest().getParameter(name), defaultValue);
    }

    /* 字符串转换为Integer */
    private Integer toInt(String value, Integer defaultValue) {
        if (value == null) {
            return defaultValue;
        }
        if (value.startsWith("N") || value.startsWith("n")) {
            return -Integer.parseInt(value.substring(1));
        }
        return Integer.parseInt(value);
    }

    /**
     * Returns the value of a request parameter and convert to Long.
     * @param name a String specifying the name of the parameter
     * @return a Integer representing the single value of the parameter
     */
    protected Long getParaToLong(String name) {
        return toLong(this.getRequest().getParameter(name), null);
    }

    /**
     * Returns the value of a request parameter and convert to Long with a default value if it is null.
     * @param name a String specifying the name of the parameter
     * @param defaultValue default value for the parameter
     * @return a Integer representing the single value of the parameter
     */
    protected Long getParaToLong(String name, Long defaultValue) {
        return toLong(this.getRequest().getParameter(name), defaultValue);
    }

    /* 字符串转换为long */
    private long toLong(String value, Long defaultValue) {
        if (value == null) {
            return defaultValue;
        }
        if (value.startsWith("N") || value.startsWith("n")) {
            return -Long.parseLong(value.substring(1));
        }
        return Long.parseLong(value);
    }

    /**
     * Returns the value of a request parameter and convert to Boolean.
     * @param name a String specifying the name of the parameter
     * @return false if the value of the parameter is "false" or "0", true if it is "true" or "1", null if parameter is not exists
     */
    protected Boolean getParaToBoolean(String name) {
        String result = this.getRequest().getParameter(name);
        if (result != null) {
            result = result.trim().toLowerCase();
            if (result.equals("1") || result.equals("true")) {
                return Boolean.TRUE;
            } else if (result.equals("0") || result.equals("false")) {
                return Boolean.FALSE;
            }
            // return Boolean.FALSE; // if use this, delete 2 lines code under
        }
        return null;
    }

    /**
     * Returns the value of a request parameter and convert to Boolean with a default value if it is null.
     * @param name a String specifying the name of the parameter
     * @param defaultValue default value for the parameter
     * @return false if the value of the parameter is "false" or "0", true if it is "true" or "1", default value if it is null
     */
    protected Boolean getParaToBoolean(String name, Boolean defaultValue) {
        Boolean result = getParaToBoolean(name);
        return result != null ? result : defaultValue;
    }
    //------------------------

    /** @return Return HttpSession. */
    protected HttpSession getSession() {
        return getRequest().getSession();
    }

    /**
     * Return HttpSession.
     * @param create a boolean specifying create HttpSession if it not exists
     * @return Return HttpSession.
     */
    protected HttpSession getSession(boolean create) {
        return getRequest().getSession(create);
    }

    /**
     * Return a Object from session.
     * @param key a String specifying the key of the Object stored in session
     * @return return session attribute data.
     */
    protected <T> T getSessionAttr(String key) {
        HttpSession session = this.getRequest().getSession(false);
        return session != null ? (T) session.getAttribute(key) : null;
    }

    /**
     * Store Object to session.
     * @param key a String specifying the key of the Object stored in session
     * @param value a Object specifying the value stored in session
     * @return 返回this.
     */
    protected WebController setSessionAttr(String key, Object value) {
        this.getRequest().getSession(true).setAttribute(key, value);
        return this;
    }

    /**
     * Remove Object in session.
     * @param key a String specifying the key of the Object stored in session
     * @return 返回this.
     */
    protected WebController removeSessionAttr(String key) {
        HttpSession session = this.getRequest().getSession(false);
        if (session != null) {
            session.removeAttribute(key);
        }
        return this;
    }
    //------------------------

    /**
     * Get cookie value by cookie name.
     * @param name cookie name
     * @param defaultValue default value
     * @return return cookie value or default value.
     */
    protected String getCookie(String name, String defaultValue) {
        Cookie cookie = getCookieObject(name);
        return cookie != null ? cookie.getValue() : defaultValue;
    }

    /**
     * Get cookie value by cookie name.
     * @param name cookie name
     * @return return cookie value or null.
     */
    protected String getCookie(String name) {
        return getCookie(name, null);
    }

    /**
     * Get cookie value by cookie name and convert to Integer.
     * @param name cookie name
     * @return return cookie value or null.
     */
    protected Integer getCookieToInt(String name) {
        String result = getCookie(name);
        return result != null ? Integer.parseInt(result) : null;
    }

    /**
     * Get cookie value by cookie name and convert to Integer.
     * @param name cookie name
     * @param defaultValue default value
     * @return return cookie value or default value.
     */
    protected Integer getCookieToInt(String name, Integer defaultValue) {
        String result = getCookie(name);
        return result != null ? Integer.parseInt(result) : defaultValue;
    }

    /**
     * Get cookie value by cookie name and convert to Long.
     * @param name cookie name
     * @return return cookie value or null.
     */
    protected Long getCookieToLong(String name) {
        String result = getCookie(name);
        return result != null ? Long.parseLong(result) : null;
    }

    /**
     * Get cookie value by cookie name and convert to Long.
     * @param name cookie name
     * @param defaultValue default value
     * @return return cookie value or default value.
     */
    protected Long getCookieToLong(String name, Long defaultValue) {
        String result = getCookie(name);
        return result != null ? Long.parseLong(result) : defaultValue;
    }

    /**
     * Get cookie object by cookie name.
     * @param name cookie name
     * @return Cookie object
     */
    protected Cookie getCookieObject(String name) {
        Cookie[] cookies = this.getRequest().getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if (cookie.getName().equals(name)) {
                    return cookie;
                }
            }
        }
        return null;
    }

    /** @return Get all cookie objects. */
    protected Cookie[] getCookieObjects() {
        Cookie[] result = this.getRequest().getCookies();
        return result != null ? result : new Cookie[0];
    }

    /**
     * Set Cookie to response.
     * @param cookie new cookie.
     * @return 返回this.
     */
    protected WebController setCookie(Cookie cookie) {
        this.getResponse().addCookie(cookie);
        return this;
    }

    /**
     * Set Cookie to response.
     * @param name cookie name
     * @param value cookie value
     * @param maxAgeInSeconds -1: clear cookie when close browser. 0: clear cookie immediately. n &gt; 0 : max age in n seconds.
     * @param path see Cookie.setPath(String)
     * @return 返回this.
     */
    protected WebController setCookie(String name, String value, int maxAgeInSeconds, String path) {
        setCookie(name, value, maxAgeInSeconds, path, null);
        return this;
    }

    /**
     * Set Cookie to response.
     * @param name cookie name
     * @param value cookie value
     * @param maxAgeInSeconds -1: clear cookie when close browser. 0: clear cookie immediately. n &gt; 0 : max age in n seconds.
     * @param path see Cookie.setPath(String)
     * @param domain the domain name within which this cookie is visible; form is according to RFC 2109
     * @return 返回this.
     */
    protected WebController setCookie(String name, String value, int maxAgeInSeconds, String path, String domain) {
        Cookie cookie = new Cookie(name, value);
        if (domain != null) {
            cookie.setDomain(domain);
        }
        cookie.setMaxAge(maxAgeInSeconds);
        cookie.setPath(path);
        this.getResponse().addCookie(cookie);
        return this;
    }

    /**
     * Set Cookie with path = "/".
     * @param name cookie name
     * @param value cookie value
     * @param maxAgeInSeconds max age
     * @return 返回this.
     */
    protected WebController setCookie(String name, String value, int maxAgeInSeconds) {
        setCookie(name, value, maxAgeInSeconds, "/", null);
        return this;
    }

    /**
     * Remove Cookie with path = "/".
     * @param name cookie name
     * @return 返回this.
     */
    protected WebController removeCookie(String name) {
        setCookie(name, null, 0, "/", null);
        return this;
    }

    /**
     * Remove Cookie.
     * @param name cookie name
     * @param path cookie with path = "/".
     * @return 返回this.
     */
    protected WebController removeCookie(String name, String path) {
        setCookie(name, null, 0, path, null);
        return this;
    }

    /**
     * Remove Cookie.
     * @param name cookie name
     * @param path cookie with path = "/".
     * @param domain domain
     * @return 返回this.
     */
    protected WebController removeCookie(String name, String path, String domain) {
        setCookie(name, null, 0, path, domain);
        return this;
    }
    //------------------------

    /**
     * Returns the value of the named attribute as an Object, or null if no attribute of the given name exists.
     * @param name a String specifying the name of the attribute
     * @return an Object containing the value of the attribute, or null if the attribute does not exist
     */
    protected <T> T getAttr(String name) {
        return (T) this.getRequest().getAttribute(name);
    }

    /**
     * Stores an attribute in this request
     * @param name a String specifying the name of the attribute
     * @param value the Object to be stored
     * @return 返回this.
     */
    protected WebController setAttr(String name, Object value) {
        this.getRequest().setAttribute(name, value);
        return this;
    }

    /**
     * Removes an attribute from this request
     * @param name a String specifying the name of the attribute to remove
     * @return 返回this.
     */
    protected WebController removeAttr(String name) {
        this.getRequest().removeAttribute(name);
        return this;
    }

    /**
     * Stores attributes in this request, key of the map as attribute name and value of the map as attribute value
     * @param attrMap key and value as attribute of the map to be stored
     * @return 返回this.
     */
    protected WebController setAttrs(Map<String, Object> attrMap) {
        for (Map.Entry<String, Object> entry : attrMap.entrySet()) {
            this.getRequest().setAttribute(entry.getKey(), entry.getValue());
        }
        return this;
    }

    /**
     * Returns an Enumeration containing the names of the attributes available to this request. This method returns an empty Enumeration if the request has no attributes available to it.
     * @return an Enumeration of strings containing the names of the request's attributes
     */
    protected Enumeration<String> getAttrNames() {
        return this.getRequest().getAttributeNames();
    }
    //------------------------

    /**
     *  返回 Invoker 保存的数据。
     *  @return 返回数据
     */
    protected <T> T getData(String name) {
        return (T) this.getInvoker().get(name);
    }

    /**
     *  设置 Invoker 保存的数据。
     *  @return 返回 this
     */
    protected WebController putData(String name, Object value) {
        this.getInvoker().put(name, value);
        return this;
    }

    /**
     *  删除 Invoker 保存的数据。
     *  @return 返回 this
     */
    protected WebController removeData(String name) {
        this.getInvoker().remove(name);
        return this;
    }

    /**
     *  设置 Invoker 保存的数据。
     *  @return 返回 this
     */
    protected WebController setDatas(Map<String, Object> attrMap) {
        for (Map.Entry<String, Object> entry : attrMap.entrySet()) {
            this.getInvoker().put(entry.getKey(), entry.getValue());
        }
        return this;
    }

    /**
     *  返回 Invoker 保存的数据keys。
     *  @return 返回数据
     */
    protected Set<String> getDataNames() {
        return this.getInvoker().keySet();
    }
    //------------------------

    /** @return Get model from AppContext. */
    protected <T> T getInstance(Class<T> modelClass, String modelName) {
        return this.getAppContext().findBindingBean(modelName, modelClass);
    }

    /** @return Get model from AppContext. */
    protected <T> T getInstance(Class<T> modelClass) {
        return this.getAppContext().getInstance(modelClass);
    }

    /** @return Get model from AppContext. */
    protected Object getInstance(String bindID) {
        return this.getAppContext().getInstance(bindID);
    }
    //------------------------

    /** 更新渲染模版。*/
    protected void renderTo(String viewName) {
        Invoker invoker = getInvoker();
        if (invoker != null && invoker instanceof RenderInvoker) {
            RenderInvoker render = (RenderInvoker) invoker;
            render.renderTo(viewName);
        }
    }

    /**
     * 更新渲染模版。
     * @param renderType 如果注释了 {@link Produces}注解那么该参数将会失效。
     * @param viewName 模版名称
     */
    protected void renderTo(String renderType, String viewName) {
        Invoker invoker = getInvoker();
        if (invoker != null && invoker instanceof RenderInvoker) {
            RenderInvoker render = (RenderInvoker) invoker;
            render.renderTo(renderType, viewName);
        }
    }
    //------------------------

    /**
     * 返回为 Multipart 请求,通常 Multipart 请求都包含一个或多个的文件上传。
     * @return 返回为 Multipart 请求,通常 Multipart 请求都包含一个或多个的文件上传。
     * @see FileUpload#isMultipartContent(HttpServletRequest)
     */
    protected boolean isMultipart() {
        return FileUpload.isMultipartContent(this.getRequest());
    }

    /**
     * 将 multipart 请求数据缓存到一个目录下,同时返回 FileItem 列表.
     */
    protected List<FileItem> getMultipartList() throws IOException {
        return this.getMultipartList((String) null, null, null);
    }

    /**
     * 将 Multipart 请求数据缓存到一个目录下,同时返回 FileItem 列表.
     * @param maxPostSize 最大单个 body 大小
     */
    protected List<FileItem> getMultipartList(Integer maxPostSize) throws IOException {
        return this.getMultipartList((String) null, maxPostSize, null);
    }

    /**
     * 将 Multipart 请求数据缓存到一个目录下,同时返回 FileItem 列表.
     * @param cacheDirectory 缓存目录
     * @param maxPostSize 最大单个 body 大小
     */
    protected List<FileItem> getMultipartList(String cacheDirectory, Integer maxPostSize) throws IOException {
        return this.getMultipartList(cacheDirectory, maxPostSize, null);
    }

    /**
     * 将 Multipart 请求数据缓存到一个目录下,同时返回 FileItem 列表。
     * @param cacheDirectory 缓存目录(默认配置位于:"hasor.fileupload.cacheDirectory")
     * @param maxPostSize 最大单个 body 大小
     * @param encoding 字符编码。
     */
    protected List<FileItem> getMultipartList(String cacheDirectory, Integer maxPostSize, String encoding) throws IOException {
        cacheDirectory = FilenameUtils.normalizeNoEndSeparator(cacheDirectory);
        if (StringUtils.isBlank(cacheDirectory)) {
            Settings settings = this.getAppContext().getEnvironment().getSettings();
            cacheDirectory = settings.getDirectoryPath("hasor.fileupload.cacheDirectory");
        }
        return this.getMultipartList(new DiskFileItemFactory(cacheDirectory), maxPostSize, encoding);
    }

    /**
     * 将 Multipart 请求数据缓存到一个目录下,同时返回 FileItem 列表。
     * @param factory 缓存策略
     */
    protected List<FileItem> getMultipartList(FileItemFactory factory) throws IOException {
        return this.getMultipartList(factory, null, null);
    }

    /**
     * 将 Multipart 请求数据缓存到一个目录下,同时返回 FileItem 列表。
     * @param factory 缓存策略
     * @param maxPostSize 最大单个 body 大小
     */
    protected List<FileItem> getMultipartList(FileItemFactory factory, Integer maxPostSize) throws IOException {
        return this.getMultipartList(factory, maxPostSize, null);
    }

    /**
     * 将 Multipart 请求数据缓存到一个目录下,同时返回 FileItem 列表。
     * @param factory 缓存策略
     * @param maxPostSize 最大单个 body 大小
     * @param encoding 字符编码。
     */
    protected List<FileItem> getMultipartList(FileItemFactory factory, Integer maxPostSize, String encoding) throws IOException {
        FileUpload upload = this.newFileUpload(maxPostSize, encoding);
        if (upload == null) {
            return null;
        }
        return upload.parseRequest(this.getRequest(), factory);
    }

    /**
     * 将 Multipart 请求数据缓存到一个目录下,同时返回 FileItem 列表。
     * @param parameterName 要获取的制定参数表单名
     */
    protected List<FileItem> getMultipart(String parameterName) throws IOException {
        return this.getMultipart(parameterName, null, null, null);
    }

    /**
     * 将 Multipart 请求数据缓存到一个目录下,同时返回 FileItem 列表,
     * @param parameterName 要获取的制定参数表单名
     * @param maxPostSize 最大单个 body 大小
     */
    protected List<FileItem> getMultipart(String parameterName, Integer maxPostSize) throws IOException {
        return this.getMultipart(parameterName, null, maxPostSize, null);
    }

    /**
     * 将 Multipart 请求数据缓存到一个目录下,同时返回 FileItem 列表.
     * @param parameterName 要获取的制定参数表单名
     * @param cacheDirectory 缓存目录
     * @param maxPostSize 最大单个 body 大小
     */
    protected List<FileItem> getMultipart(String parameterName, String cacheDirectory, Integer maxPostSize) throws IOException {
        return this.getMultipart(parameterName, cacheDirectory, maxPostSize, null);
    }

    /**
     * 将 Multipart 请求数据缓存到一个目录下,同时返回 FileItem 列表。
     * @param parameterName 要获取的制定参数表单名
     * @param cacheDirectory 缓存目录
     * @param maxPostSize 最大单个 body 大小
     * @param encoding 字符编码。
     */
    protected List<FileItem> getMultipart(String parameterName, String cacheDirectory, Integer maxPostSize, String encoding) throws IOException {
        Objects.requireNonNull(parameterName);
        List<FileItem> itemList = this.getMultipartList(cacheDirectory, maxPostSize, encoding);
        if (itemList == null || itemList.isEmpty()) {
            return null;
        }
        List<FileItem> resultData = new ArrayList<>();
        for (FileItem item : itemList) {
            if (parameterName.equals(item.getFieldName())) {
                resultData.add(item);
            } else {
                item.deleteOrSkip();
            }
        }
        return resultData;
    }

    /**
     * 返回流式处理文件上传的迭代器。
     */
    protected Iterator<FileItemStream> getMultipartIterator() throws IOException {
        return this.getMultipartIterator(null, null);
    }

    /**
     * 返回流式处理文件上传的迭代器。
     * @param maxPostSize 最大单个 body 大小
     */
    protected Iterator<FileItemStream> getMultipartIterator(Integer maxPostSize) throws IOException {
        return this.getMultipartIterator(maxPostSize, null);
    }

    /**
     * 返回流式处理文件上传的迭代器。
     * @param maxPostSize 最大单个 body 大小
     * @param encoding 字符编码。
     */
    protected Iterator<FileItemStream> getMultipartIterator(Integer maxPostSize, String encoding) throws IOException {
        FileUpload upload = this.newFileUpload(maxPostSize, encoding);
        if (upload == null) {
            return null;
        }
        return upload.getItemIterator(this.getRequest());
    }

    /**
     * 创建原始的FileUpload对象。
     * @param maxPostSize 最大单个 body 大小
     * @param encoding 字符编码。
     */
    protected FileUpload newFileUpload(Integer maxPostSize, String encoding) {
        if (!this.isMultipart()) {
            return null;
        }
        //
        FileUpload upload = new FileUpload(this.getAppContext().getEnvironment().getSettings());
        if (maxPostSize != null) {
            upload.setSizeMax(maxPostSize);
        }
        if (encoding != null) {
            upload.setHeaderEncoding(encoding);
        }
        return upload;
    }
}