001/*******************************************************************************
002 * Copyright (c) 2015 EclipseSource.
003 *
004 * Permission is hereby granted, free of charge, to any person obtaining a copy
005 * of this software and associated documentation files (the "Software"), to deal
006 * in the Software without restriction, including without limitation the rights
007 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
008 * copies of the Software, and to permit persons to whom the Software is
009 * furnished to do so, subject to the following conditions:
010 *
011 * The above copyright notice and this permission notice shall be included in all
012 * copies or substantial portions of the Software.
013 *
014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
015 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
016 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
017 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
018 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
019 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
020 * SOFTWARE.
021 ******************************************************************************/
022package com.restfb.json;
023
024import java.io.IOException;
025import java.io.Writer;
026import java.util.Arrays;
027
028/**
029 * Enables human readable JSON output by inserting whitespace between values.after commas and colons. Example:
030 *
031 * <pre>
032 * jsonValue.writeTo(writer, PrettyPrint.singleLine());
033 * </pre>
034 */
035public class PrettyPrint extends WriterConfig {
036
037  private final char[] indentChars;
038
039  protected PrettyPrint(char[] indentChars) {
040    this.indentChars = indentChars;
041  }
042
043  /**
044   * Print every value on a separate line. Use tabs (<code>\t</code>) for indentation.
045   *
046   * @return A PrettyPrint instance for wrapped mode with tab indentation
047   */
048  public static PrettyPrint singleLine() {
049    return new PrettyPrint(null);
050  }
051
052  /**
053   * Print every value on a separate line. Use the given number of spaces for indentation.
054   *
055   * @param number
056   *          the number of spaces to use
057   * @return A PrettyPrint instance for wrapped mode with spaces indentation
058   */
059  public static PrettyPrint indentWithSpaces(int number) {
060    if (number < 0) {
061      throw new IllegalArgumentException("number is negative");
062    }
063    char[] chars = new char[number];
064    Arrays.fill(chars, ' ');
065    return new PrettyPrint(chars);
066  }
067
068  /**
069   * Do not break lines, but still insert whitespace between values.
070   *
071   * @return A PrettyPrint instance for single-line mode
072   */
073  public static PrettyPrint indentWithTabs() {
074    return new PrettyPrint(new char[] { '\t' });
075  }
076
077  @Override
078  protected JsonWriter createWriter(Writer writer) {
079    return new PrettyPrintWriter(writer, indentChars);
080  }
081
082  private static class PrettyPrintWriter extends JsonWriter {
083
084    private final char[] indentChars;
085    private int indent;
086
087    private PrettyPrintWriter(Writer writer, char[] indentChars) {
088      super(writer);
089      this.indentChars = indentChars;
090    }
091
092    @Override
093    protected void writeArrayOpen() throws IOException {
094      indent++;
095      writer.write('[');
096      writeNewLine();
097    }
098
099    @Override
100    protected void writeArrayClose() throws IOException {
101      indent--;
102      writeNewLine();
103      writer.write(']');
104    }
105
106    @Override
107    protected void writeArraySeparator() throws IOException {
108      writeCommaSeparator();
109    }
110
111    @Override
112    protected void writeObjectOpen() throws IOException {
113      indent++;
114      writer.write('{');
115      writeNewLine();
116    }
117
118    @Override
119    protected void writeObjectClose() throws IOException {
120      indent--;
121      writeNewLine();
122      writer.write('}');
123    }
124
125    @Override
126    protected void writeMemberSeparator() throws IOException {
127      writer.write(':');
128      writer.write(' ');
129    }
130
131    @Override
132    protected void writeObjectSeparator() throws IOException {
133      writeCommaSeparator();
134    }
135
136    protected void writeCommaSeparator() throws IOException {
137      writer.write(',');
138      if (!writeNewLine()) {
139        writer.write(' ');
140      }
141    }
142
143    private boolean writeNewLine() throws IOException {
144      if (indentChars == null) {
145        return false;
146      }
147      writer.write('\n');
148      for (int i = 0; i < indent; i++) {
149        writer.write(indentChars);
150      }
151      return true;
152    }
153
154  }
155
156}