/**
 * Copyright (c) 2011-2013, James Zhan 詹波 (jfinal@126.com).
 *
 * 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 com.jfinal.render;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import java.util.Map;

/**
 * JsonRender.
 * <p/>
 * IE 不支持content type 为 application/json, 在 ajax 上传文件完成后返回 json时 IE 提示下载文件,<br>
 * 解决办法是使用： render(new JsonRender(params).forIE());
 */
public class JsonRender extends Render {

    private static final long serialVersionUID = 3606364198859021837L;

    /**
     * http://zh.wikipedia.org/zh/MIME
     * 在wiki中查到: 尚未被接受为正式数据类型的subtype，可以使用x-开始的独立名称（例如application/x-gzip）
     * 所以以下可能要改成 application/x-json
     * <p/>
     * 通过使用firefox测试,struts2-json-plugin返回的是 application/json, 所以暂不改为 application/x-json
     * 1: 官方的 MIME type为application/json, 见 http://en.wikipedia.org/wiki/MIME_type
     * 2: IE 不支持 application/json, 在 ajax 上传文件完成后返回 json时 IE 提示下载文件
     */
    private static final String contentType = "application/json;charset=" + getEncoding();
    private static final String contentTypeForIE = "text/html;charset=" + getEncoding();
    private boolean forIE = false;

    public JsonRender forIE() {
        forIE = true;
        return this;
    }

    private String jsonText;
    private String[] attrs;

    public JsonRender() {

    }

    @SuppressWarnings("serial")
    public JsonRender(final String key, final Object value) {
        if (key == null)
            throw new IllegalArgumentException("The parameter key can not be null.");
        this.jsonText = JSON.toJSONString(Maps.newHashMap().put(key, value));
    }

    public JsonRender(String[] attrs) {
        if (attrs == null)
            throw new IllegalArgumentException("The parameter attrs can not be null.");
        this.attrs = attrs;
    }

    public JsonRender(String jsonText) {
        if (jsonText == null)
            throw new IllegalArgumentException("The parameter jsonString can not be null.");
        this.jsonText = jsonText;
    }

    public JsonRender(Object object) {
        if (object == null)
            throw new IllegalArgumentException("The parameter object can not be null.");
        this.jsonText = JSON.toJSONString(object);
    }

    public void render() {
        if (jsonText == null)
            buildJsonText();

        PrintWriter writer = null;
        try {
            response.setHeader("Pragma", "no-cache");    // HTTP/1.0 caches might not implement Cache-Control and might only implement Pragma: no-cache
            response.setHeader("Cache-Control", "no-cache");
            response.setDateHeader("Expires", 0);

            response.setContentType(forIE ? contentTypeForIE : contentType);
            writer = response.getWriter();
            writer.write(jsonText);
            writer.flush();
        } catch (IOException e) {
            throw new RenderException(e);
        } finally {
            if (writer != null)
                writer.close();
        }
    }

    private void buildJsonText() {
        Map<String, Object> map = Maps.newHashMap();
        if (attrs != null) {
            for (String key : attrs)
                map.put(key, request.getAttribute(key));
        } else {
            Enumeration<String> attrs = request.getAttributeNames();
            while (attrs.hasMoreElements()) {
                String key = attrs.nextElement();
                Object value = request.getAttribute(key);
                map.put(key, value);
            }
        }

        this.jsonText = JSON.toJSONString(map);
    }
}




@@ -653,82 +653,8 @@
 r;%0A%0A
-import com.alibaba.fastjson.JSON;%0Aimport com.google.common.collect.Maps;%0A%0A
 impo
@@ -752,19 +752,76 @@
 va.util.
-Map
+HashMap;%0Aimport java.util.Map;%0Aimport com.jfinal.kit.JsonKit
 ;%0A%0A/**%0A 
@@ -839,17 +839,16 @@
 r.%0A * %3Cp
-/
 %3E%0A * IE 
@@ -1258,13 +1258,8 @@
    *
- %3Cp/%3E
 %0A   
@@ -1717,16 +1717,57 @@
 = false;
+%0A    private static int convertDepth = 8;
 %0A%0A    pu
@@ -2168,58 +2168,88 @@
  = J
-SON.toJSONString(Maps.
+sonKit.mapToJson(
 new
+ 
 HashMap
-().put(key, value)
+%3CString, Object%3E()%7B%7Bput(key, value);%7D%7D, convertDepth
 );%0A 
@@ -2834,32 +2834,273 @@
  = J
-SON.toJSONString(object)
+sonKit.toJson(object, convertDepth);%0A    %7D%0A%0A    public static void setConvertDepth(int convertDepth) %7B%0A        if (convertDepth %3C 2)%0A            throw new IllegalArgumentException(%22convert depth can not less than 2.%22);%0A        JsonRender.convertDepth = convertDepth
 ;%0A  
@@ -3293,20 +3293,17 @@
 cache%22);
-    
+%09
 // HTTP/
@@ -3770,16 +3770,24 @@
        %7D
+%0A       
  finally
@@ -3862,32 +3862,81 @@
        %7D%0A    %7D%0A%0A
+    @SuppressWarnings(%7B%22rawtypes%22, %22unchecked%22%7D)%0A
     private void
@@ -3969,39 +3969,19 @@
  Map
-%3CString, Object%3E
  map = 
-Maps.
 new
+ 
 Hash
@@ -4119,16 +4119,24 @@
        %7D
+%0A       
  else %7B%0A
@@ -4449,28 +4449,42 @@
  = J
-SON.toJSONString(map
+sonKit.mapToJson(map, convertDepth
 );%0A 

还原jfinal的 JSON Reader类