/* 
 | 
 * Copyright (C) 2011 Google Inc. 
 | 
 * 
 | 
 * 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 cn.emay.sdk.util.json.gson.internal.bind; 
 | 
  
 | 
import java.io.IOException; 
 | 
import java.io.Writer; 
 | 
import java.util.ArrayList; 
 | 
import java.util.List; 
 | 
  
 | 
import cn.emay.sdk.util.json.gson.JsonArray; 
 | 
import cn.emay.sdk.util.json.gson.JsonElement; 
 | 
import cn.emay.sdk.util.json.gson.JsonNull; 
 | 
import cn.emay.sdk.util.json.gson.JsonObject; 
 | 
import cn.emay.sdk.util.json.gson.JsonPrimitive; 
 | 
import cn.emay.sdk.util.json.gson.stream.JsonWriter; 
 | 
  
 | 
/** 
 | 
 * This writer creates a JsonElement. 
 | 
 */ 
 | 
public final class JsonTreeWriter extends JsonWriter { 
 | 
    private static final Writer UNWRITABLE_WRITER = new Writer() { 
 | 
        @Override 
 | 
        public void write(char[] buffer, int offset, int counter) { 
 | 
            throw new AssertionError(); 
 | 
        } 
 | 
  
 | 
        @Override 
 | 
        public void flush() throws IOException { 
 | 
            throw new AssertionError(); 
 | 
        } 
 | 
  
 | 
        @Override 
 | 
        public void close() throws IOException { 
 | 
            throw new AssertionError(); 
 | 
        } 
 | 
    }; 
 | 
    /** 
 | 
     * Added to the top of the stack when this writer is closed to cause following 
 | 
     * ops to fail. 
 | 
     */ 
 | 
    private static final JsonPrimitive SENTINEL_CLOSED = new JsonPrimitive("closed"); 
 | 
  
 | 
    /** 
 | 
     * The JsonElements and JsonArrays under modification, outermost to innermost. 
 | 
     */ 
 | 
    private final List<JsonElement> stack = new ArrayList<JsonElement>(); 
 | 
  
 | 
    /** 
 | 
     * The name for the next JSON object value. If non-null, the top of the stack is 
 | 
     * a JsonObject. 
 | 
     */ 
 | 
    private String pendingName; 
 | 
  
 | 
    /** the JSON element constructed by this writer. */ 
 | 
    private JsonElement product = JsonNull.INSTANCE; // TODO: is this really what we want?; 
 | 
  
 | 
    public JsonTreeWriter() { 
 | 
        super(UNWRITABLE_WRITER); 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * Returns the top level object produced by this writer. 
 | 
     */ 
 | 
    public JsonElement get() { 
 | 
        if (!stack.isEmpty()) { 
 | 
            throw new IllegalStateException("Expected one JSON element but was " + stack); 
 | 
        } 
 | 
        return product; 
 | 
    } 
 | 
  
 | 
    private JsonElement peek() { 
 | 
        return stack.get(stack.size() - 1); 
 | 
    } 
 | 
  
 | 
    private void put(JsonElement value) { 
 | 
        if (pendingName != null) { 
 | 
            if (!value.isJsonNull() || getSerializeNulls()) { 
 | 
                JsonObject object = (JsonObject) peek(); 
 | 
                object.add(pendingName, value); 
 | 
            } 
 | 
            pendingName = null; 
 | 
        } else if (stack.isEmpty()) { 
 | 
            product = value; 
 | 
        } else { 
 | 
            JsonElement element = peek(); 
 | 
            if (element instanceof JsonArray) { 
 | 
                ((JsonArray) element).add(value); 
 | 
            } else { 
 | 
                throw new IllegalStateException(); 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public JsonWriter beginArray() throws IOException { 
 | 
        JsonArray array = new JsonArray(); 
 | 
        put(array); 
 | 
        stack.add(array); 
 | 
        return this; 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public JsonWriter endArray() throws IOException { 
 | 
        if (stack.isEmpty() || pendingName != null) { 
 | 
            throw new IllegalStateException(); 
 | 
        } 
 | 
        JsonElement element = peek(); 
 | 
        if (element instanceof JsonArray) { 
 | 
            stack.remove(stack.size() - 1); 
 | 
            return this; 
 | 
        } 
 | 
        throw new IllegalStateException(); 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public JsonWriter beginObject() throws IOException { 
 | 
        JsonObject object = new JsonObject(); 
 | 
        put(object); 
 | 
        stack.add(object); 
 | 
        return this; 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public JsonWriter endObject() throws IOException { 
 | 
        if (stack.isEmpty() || pendingName != null) { 
 | 
            throw new IllegalStateException(); 
 | 
        } 
 | 
        JsonElement element = peek(); 
 | 
        if (element instanceof JsonObject) { 
 | 
            stack.remove(stack.size() - 1); 
 | 
            return this; 
 | 
        } 
 | 
        throw new IllegalStateException(); 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public JsonWriter name(String name) throws IOException { 
 | 
        if (stack.isEmpty() || pendingName != null) { 
 | 
            throw new IllegalStateException(); 
 | 
        } 
 | 
        JsonElement element = peek(); 
 | 
        if (element instanceof JsonObject) { 
 | 
            pendingName = name; 
 | 
            return this; 
 | 
        } 
 | 
        throw new IllegalStateException(); 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public JsonWriter value(String value) throws IOException { 
 | 
        if (value == null) { 
 | 
            return nullValue(); 
 | 
        } 
 | 
        put(new JsonPrimitive(value)); 
 | 
        return this; 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public JsonWriter nullValue() throws IOException { 
 | 
        put(JsonNull.INSTANCE); 
 | 
        return this; 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public JsonWriter value(boolean value) throws IOException { 
 | 
        put(new JsonPrimitive(value)); 
 | 
        return this; 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public JsonWriter value(double value) throws IOException { 
 | 
        if (!isLenient() && (Double.isNaN(value) || Double.isInfinite(value))) { 
 | 
            throw new IllegalArgumentException("JSON forbids NaN and infinities: " + value); 
 | 
        } 
 | 
        put(new JsonPrimitive(value)); 
 | 
        return this; 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public JsonWriter value(long value) throws IOException { 
 | 
        put(new JsonPrimitive(value)); 
 | 
        return this; 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public JsonWriter value(Number value) throws IOException { 
 | 
        if (value == null) { 
 | 
            return nullValue(); 
 | 
        } 
 | 
  
 | 
        if (!isLenient()) { 
 | 
            double d = value.doubleValue(); 
 | 
            if (Double.isNaN(d) || Double.isInfinite(d)) { 
 | 
                throw new IllegalArgumentException("JSON forbids NaN and infinities: " + value); 
 | 
            } 
 | 
        } 
 | 
  
 | 
        put(new JsonPrimitive(value)); 
 | 
        return this; 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public void flush() throws IOException { 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public void close() throws IOException { 
 | 
        if (!stack.isEmpty()) { 
 | 
            throw new IOException("Incomplete document"); 
 | 
        } 
 | 
        stack.add(SENTINEL_CLOSED); 
 | 
    } 
 | 
} 
 |