content: /**
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to You 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 org.apache.noggit;
  
  import java.util.*;
  
  /**
   * @author yonik
   * @version $Id: JSONWriter.java 1211150 2011-12-06 21:10:01Z yonik $
   */
  public class JSONWriter {
  
    /** Implement this interface on your class to support serialization */
    public static interface Writable {
      public void write(JSONWriter writer);
    }
  
    protected int level;
    protected int indent;
    protected final CharArr out;
  
    /**
     * @param out the CharArr to write the output to.
     * @param indentSize  The number of space characters to use as an indent (default 2). 0=newlines but no spaces, -1=no indent at all.
     */
    public JSONWriter(CharArr out, int indentSize) {
      this.out = out;
      this.indent = indentSize;
    }
  
    public JSONWriter(CharArr out) {
      this(out, 2);
    }
  
    public void setIndentSize(int indentSize) {
      this.indent = indentSize;
    }
  
    public void indent() {
      if (indent >= 0) {
        out.write('\n');
        if (indent > 0) {
          int spaces = level*indent;
          out.reserve(spaces);
          for (int i=0; i<spaces; i++) {
            out.unsafeWrite(' ');
          }
        }
      }
    }
  
    public void write(Object o) {
      if (o == null) {
        writeNull();
      } else if (o instanceof CharSequence) {
        writeString((CharSequence)o);
      } else if (o instanceof Number) {
        if (o instanceof Integer || o instanceof Long) {
          write(((Number)o).longValue());
        } else if (o instanceof Float || o instanceof Double) {
          write(((Number)o).doubleValue());
        } else {
          CharArr arr = new CharArr();
          arr.write(o.toString());
          writeNumber(arr);
        }
      } else if (o instanceof Map) {
        write((Map)o);
      } else if (o instanceof Collection) {
        write((Collection)o);
      } else if (o instanceof Object[]) {
        write(Arrays.asList((Object[])o));
      } else if (o instanceof Boolean) {
        write(((Boolean)o).booleanValue());
      } else if (o instanceof Writable) {
        ((Writable) o).write(this);
      }
      else if (o instanceof int[]) {
        write((int[])o);
      } else if (o instanceof float[]) {
        write((float[])o);
      } else if (o instanceof long[]) {
        write((long[])o);
      } else if (o instanceof double[]) {
        write((double[])o);
      } else if (o instanceof short[]) {
        write((short[])o);
      } else if (o instanceof boolean[]) {
        write((boolean[])o);
      } else if (o instanceof char[]) {
        write((char[])o);
      } else if (o instanceof byte[]) {
        write((byte[])o);
      } else {
        handleUnknownClass(o);
      }
    }
  
    /** Override this method for custom handling of unknown classes.  Also see the Writable interface. */
    public void handleUnknownClass(Object o) {
      writeString(out.toString());
    }
  
    public void write(Map val) {
      startObject();
      int sz = val.size();
      boolean first = true;
      for (Map.Entry entry : (Set<Map.Entry>)val.entrySet()) {
        if (first) {
          first = false;
        } else {
          writeValueSeparator();
        }
        if (sz>1) indent();
        writeString(entry.getKey().toString());
        writeNameSeparator();
        write(entry.getValue());
      }
      endObject();
    }
  
    public void write(Collection val) {
      startArray();
      int sz = val.size();
      boolean first = true;
      for (Object o : val) {
        if (first) {
          first = false;
        } else {
          writeValueSeparator();
        }
        if (sz>1) indent();
        write(o);
      }
      endArray();
    }
  
    /** A byte[] may be either a single logical value, or a list of small integers.
     * It's up to the implementation to decide.
     */
    public void write(byte[] val) {
      startArray();
      boolean first = true;
      for (short v : val) {
        if (first) {
          first = false;
        } else {
          writeValueSeparator();
        }
        write(v);
      }
      endArray();
    }
  
    public void write(short[] val) {
      startArray();
      boolean first = true;
      for (short v : val) {
        if (first) {
          first = false;
        } else {
          writeValueSeparator();
        }
        write(v);
      }
      endArray();
    }
  
    public void write(int[] val) {
      startArray();
      boolean first = true;
      for (int v : val) {
        if (first) {
          first = false;
        } else {
          writeValueSeparator();
        }
        write(v);
      }
      endArray();
    }
  
    public void write(long[] val) {
      startArray();
      boolean first = true;
      for (long v : val) {
        if (first) {
          first = false;
        } else {
          writeValueSeparator();
        }
        write(v);
      }
      endArray();
    }
  
    public void write(float[] val) {
      startArray();
      boolean first = true;
      for (float v : val) {
        if (first) {
          first = false;
        } else {
          writeValueSeparator();
        }
        write(v);
      }
      endArray();
    }
  
    public void write(double[] val) {
      startArray();
      boolean first = true;
      for (double v : val) {
        if (first) {
          first = false;
        } else {
          writeValueSeparator();
        }
        write(v);
      }
      endArray();
    }
  
    public void write(boolean[] val) {
      startArray();
      boolean first = true;
      for (boolean v : val) {
        if (first) {
          first = false;
        } else {
          writeValueSeparator();
        }
        write(v);
      }
      endArray();
    }
  
  
    public void write(short number) { write ((int)number); }
    public void write(byte number) { write((int)number); }
  
  
    public void writeNull() {
      JSONUtil.writeNull(out);
    }
  
    public void writeString(CharSequence str) {
      JSONUtil.writeString(str,0,str.length(),out);
    }
  
    public void writeString(CharArr str) {
      JSONUtil.writeString(str,out);
    }
  
    public void writeStringStart() {
      out.write('"');
    }
  
    public void writeStringChars(CharArr partialStr) {
      JSONUtil.writeStringPart(partialStr.getArray(), partialStr.getStart(), partialStr.getEnd(), out);
    }
  
    public void writeStringEnd() {
      out.write('"');
    }
  
    public void write(long number) {
      JSONUtil.writeNumber(number,out);
    }
  
    public void write(int number) {
      JSONUtil.writeNumber(number,out);
    }
  
    public void write(double number) {
      JSONUtil.writeNumber(number,out);
    }
  
    public void write(float number) {
      JSONUtil.writeNumber(number,out);
    }
  
    public void write(boolean bool) {
      JSONUtil.writeBoolean(bool,out);
    }
  
    public void write(char[] val) {
      JSONUtil.writeString(val, 0, val.length, out);
    }
  
    public void writeNumber(CharArr digits) {
      out.write(digits);
    }
  
    public void writePartialNumber(CharArr digits) {
      out.write(digits);
    }
  
    public void startObject() {
      out.write('{');
      level++;
    }
  
    public void endObject() {
      out.write('}');
      level--;
    }
  
    public void startArray() {
      out.write('[');
      level++;
    }
  
    public void endArray() {
      out.write(']');
      level--;
    }
  
    public void writeValueSeparator() {
      out.write(',');
    }
  
    public void writeNameSeparator() {
      out.write(':');
    }
  
  }
  
  