package com.publiccms.common.handler;

import java.io.IOException;
import java.io.Writer;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.Date;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.web.servlet.support.RequestContextUtils;

import com.publiccms.common.base.BaseHandler;
import com.publiccms.common.constants.Constants;
import com.publiccms.common.tools.CommonUtils;
import com.publiccms.common.tools.DateFormatUtils;

/**
 *
 * HttpParameterHandler
 * 
 */
public class HttpParameterHandler extends BaseHandler {

    private MediaType mediaType;
    private HttpMessageConverter<Object> httpMessageConverter;
    private HttpServletRequest request;
    private HttpServletResponse response;

    /**
     * @param httpMessageConverter
     * @param mediaType
     * @param request
     * @param response
     */
    public HttpParameterHandler(HttpMessageConverter<Object> httpMessageConverter, MediaType mediaType,
            HttpServletRequest request, HttpServletResponse response) {
        this.httpMessageConverter = httpMessageConverter;
        this.request = request;
        this.response = response;
        this.mediaType = mediaType;
        regristerParameters();
    }

    @Override
    public void render() throws HttpMessageNotWritableException, IOException {
        httpMessageConverter.write(map, mediaType, new ServletServerHttpResponse(response));
        renderd = true;
    }

    @Override
    public void print(String value) throws IOException {
        response.getWriter().print(value);
    }

    @Override
    public Writer getWriter() throws IOException {
        return response.getWriter();
    }

    @Override
    protected String getStringWithoutRegister(String name) {
        return request.getParameter(name);
    }

    @Override
    protected Integer getIntegerWithoutRegister(String name) {
        String result = getStringWithoutRegister(name);
        if (CommonUtils.notEmpty(result)) {
            try {
                return Integer.valueOf(result);
            } catch (NumberFormatException e) {
                return null;
            }
        }
        return null;
    }

    @Override
    public Byte getByteWithoutRegister(String name) {
        String result = getStringWithoutRegister(name);
        if (CommonUtils.notEmpty(result)) {
            try {
                return Byte.valueOf(result);
            } catch (NumberFormatException e) {
                return null;
            }
        }
        return null;
    }

    @Override
    public Short getShort(String name) {
        regristerParameter(PARAMETER_TYPE_SHORT, name);
        String result = getStringWithoutRegister(name);
        if (CommonUtils.notEmpty(result)) {
            try {
                return Short.valueOf(result);
            } catch (NumberFormatException e) {
                return null;
            }
        }
        return null;
    }

    @Override
    public Long getLong(String name) {
        regristerParameter(PARAMETER_TYPE_LONG, name);
        String result = getStringWithoutRegister(name);
        if (CommonUtils.notEmpty(result)) {
            try {
                return Long.valueOf(result);
            } catch (NumberFormatException e) {
                return null;
            }
        }
        return null;
    }

    @Override
    public Double getDouble(String name) {
        regristerParameter(PARAMETER_TYPE_DOUBLE, name);
        String result = getStringWithoutRegister(name);
        if (CommonUtils.notEmpty(result)) {
            try {
                return Double.valueOf(result);
            } catch (NumberFormatException e) {
                return null;
            }
        }
        return null;
    }

    @Override
    public BigDecimal getBigDecimal(String name) {
        regristerParameter(PARAMETER_TYPE_BIGDECIMAL, name);
        String result = getStringWithoutRegister(name);
        if (CommonUtils.notEmpty(result)) {
            try {
                return new BigDecimal(result);
            } catch (NumberFormatException e) {
                return null;
            }
        }
        return null;
    }

    @Override
    protected String[] getStringArrayWithoutRegister(String name) {
        String[] values = request.getParameterValues(name);
        if (CommonUtils.notEmpty(values) && 1 == values.length && values[0].contains(Constants.COMMA_DELIMITED)) {
            return StringUtils.split(values[0], Constants.COMMA_DELIMITED);
        }
        return values;
    }

    @Override
    protected Boolean getBooleanWithoutRegister(String name) {
        String result = getStringWithoutRegister(name);
        if (CommonUtils.notEmpty(result)) {
            return Boolean.valueOf(result);
        }
        return null;
    }

    @Override
    public Date getDateWithoutRegister(String name) {
        String result = getStringWithoutRegister(name);
        if (CommonUtils.notEmpty(result)) {
            String temp = StringUtils.trimToEmpty(result);
            try {
                if (DateFormatUtils.FULL_DATE_LENGTH == temp.length()) {
                    return DateFormatUtils.getDateFormat(DateFormatUtils.FULL_DATE_FORMAT_STRING).parse(temp);
                } else if (DateFormatUtils.SHORT_DATE_LENGTH == temp.length()) {
                    return DateFormatUtils.getDateFormat(DateFormatUtils.SHORT_DATE_FORMAT_STRING).parse(temp);
                } else {
                    return new Date(Long.parseLong(temp));
                }
            } catch (ParseException | NumberFormatException e) {
                return null;
            }
        }
        return null;
    }

    @Override
    public Map<String, String> getMap(String name) {
        String mapNamePrefix = CommonUtils.joinString(name, Constants.DOT);
        Enumeration<String> names = request.getParameterNames();
        Map<String, String> map = new LinkedHashMap<>();
        while (names.hasMoreElements()) {
            String temp = names.nextElement();
            if (temp.startsWith(mapNamePrefix)) {
                map.put(temp.substring(name.length() + 1), request.getParameter(temp));
            }
        }
        return map;
    }

    @Override
    public Locale getLocale() {
        return RequestContextUtils.getLocale(request);
    }

    @Override
    public HttpServletRequest getRequest() {
        return request;
    }

    @Override
    public Object getAttribute(String name) {
        return request.getAttribute(name);
    }

    @Override
    public String getStringAttribute(String name) {
        return request.getHeader(name);
    }

    @Override
    public boolean inHttp() {
        return true;
    }
}
