package me.chyxion.tigon.webmvc;

import java.util.Map;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.alibaba.fastjson.support.spring.FastJsonJsonView;

/**
 * JSON View
 * @author Donghuang <br>
 * donghuang@wacai.com <br>
 * Mar 14, 2017 12:00:55
 */
@Slf4j
public class JSONView extends FastJsonJsonView {
    public static final String MAP_DATA = "__MAP_DATA__";
    public static final String DATA_KEY = "__DATA__";

    private JSONViewDataModel dataModel;
    private String requestURI;
    private final JSONViewConfig config;

    /**
     * @param dataModel data model
     * @param config json view config
     */
    public JSONView(final JSONViewDataModel dataModel, final JSONViewConfig config) {
        this.dataModel = dataModel;
        this.config = config;
    }

    /**
     * @param viewName view name
     * @param config json view config
     */
    public JSONView(final String viewName, final JSONViewConfig config) {
        this((JSONViewDataModel) null, config);
        setBeanName(viewName);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void renderMergedOutputModel(
        Map<String, Object> model,
        HttpServletRequest request,
        HttpServletResponse response) throws Exception {
        requestURI = request.getRequestURI()
            .substring(request.getContextPath().length());
        super.renderMergedOutputModel(model, request, response);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected Object filterModel(Map<String, Object> model) {
        if (dataModel == null) {
            dataModel = buildDataModel(model);
        }
        Object dataResp = null;
        final JSONViewDataModelAssembler dataModelAssembler =
            config.getDataModelAssembler();
        if (dataModelAssembler != null) {
            dataResp = dataModelAssembler.assemble(dataModel);
            if (dataResp instanceof JSONViewDataModel) {
                dataResp = ((JSONViewDataModel) dataResp).toMap(
                    config.getSuccessKey(), config.getDataKey(),
                    config.getCodeKey(), config.getMessageKey());
            }
        }
        else {
            dataResp = dataModel.toMap(config.getSuccessKey(),
                config.getDataKey(), config.getCodeKey(), config.getMessageKey());
        }
        if (log.isDebugEnabled()) {
            log.debug("Render JSON response [{}].", JSON.toJSONString(dataResp, true));
        }
        return dataResp;
    }

    /**
     * Response json for any client accepts media
     * @return content type
     */
    @Override
    public String getContentType() {
        return "*/*";
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void setResponseContentType(HttpServletRequest request, HttpServletResponse response) {
        response.setContentType(DEFAULT_CONTENT_TYPE);
    }

    private JSONViewDataModel buildDataModel(Map<String, Object> model) {
        log.debug("Build data model from map model.");
        Object objData = null;
        if (Boolean.TRUE.equals(model.get(MAP_DATA))) {
            objData = model.get(DATA_KEY);
            log.debug("Render map data [{}].", objData);
        }
        else {
            // default bean name
            String beanName = getBeanName();
            if (!requestURI.equals("/" + beanName)) {
                objData = beanName;
                log.debug("Could not find any resource, render as string data [{}].", objData);
            }
            else {
                log.debug("View name is request URI, no data to response.");
            }
        }
        return new JSONViewDataModel(objData);
    }
}
