/*
* Copyright 2008-2016 the original author or authors.
*
* 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.nominanuda.zen.obj;
import static com.nominanuda.zen.common.Ex.EX;
import static com.nominanuda.zen.common.Str.STR;
import static com.nominanuda.zen.obj.JsonSerializer.COLON_ON_WIRE;
import static com.nominanuda.zen.obj.JsonSerializer.COMMA_ON_WIRE;
import static com.nominanuda.zen.obj.JsonSerializer.LCURLY_ON_WIRE;
import static com.nominanuda.zen.obj.JsonSerializer.LSQUARE_ON_WIRE;
import static com.nominanuda.zen.obj.JsonSerializer.NEWLINE_ON_WIRE;
import static com.nominanuda.zen.obj.JsonSerializer.RCURLY_ON_WIRE;
import static com.nominanuda.zen.obj.JsonSerializer.RSQUARE_ON_WIRE;
import static com.nominanuda.zen.obj.JsonType.arr;
import static com.nominanuda.zen.obj.JsonType.obj;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.io.Writer;
import java.util.Stack;
import com.nominanuda.zen.common.Check;
public class JsonOioPrinter implements JixHandler {
private final Writer w;
private final boolean binary;
private final OutputStream os;
private final CommaInsCtx commas = new CommaInsCtx();
private final boolean pretty;
private boolean escapeSlash = false;
private JsonSerializer jsonSerializer = new JsonSerializer();
public JsonOioPrinter(Writer writer) {
this(writer, false, false);
}
public JsonOioPrinter(Writer writer, boolean pretty) {
this(writer, pretty, false);
}
public JsonOioPrinter(OutputStream os) {
this(os, false, false);
}
public JsonOioPrinter(OutputStream os, boolean pretty) {
this(os, pretty, false);
}
public JsonOioPrinter(Writer writer, boolean pretty, boolean escapeSlash) {
this.w = Check.notNull(writer);
this.os = null;
this.binary = false;
this.pretty = pretty;
this.escapeSlash = escapeSlash;
}
public JsonOioPrinter(OutputStream os, boolean pretty, boolean escapeSlash) {
this.os = Check.notNull(os);
this.w = null;
this.binary = true;
this.pretty = pretty;
this.escapeSlash = escapeSlash;
}
@Override
public void startObj() throws RuntimeException {
try {
commas.startObj();
writeLCurly();
indent++;
indent();
} catch (IOException e) {
throw EX.uncheckedIO(e);
}
}
@Override
public void endObj() throws RuntimeException {
try {
commas.endObj();
indent--;
indent();
writeRCurly();
} catch (IOException e) {
throw EX.uncheckedIO(e);
}
}
@Override
public void key(Key key) throws RuntimeException {
try {
commas.key(key);
writeString(key.toString());
writeColon();
} catch (IOException e) {
throw EX.uncheckedIO(e);
}
}
@Override
public void startArr() throws RuntimeException {
try {
commas.startArr();
writeLSquare();
indent++;
indent();
} catch (IOException e) {
throw EX.uncheckedIO(e);
}
}
@Override
public void endArr() throws RuntimeException {
try {
commas.endArr();
indent--;
indent();
writeRSquare();
} catch (IOException e) {
throw EX.uncheckedIO(e);
}
}
@Override
public void val(Val o) throws RuntimeException {
commas.val(o);
if(binary) {
jsonSerializer.serializeAndQuotePrimitiveTo(o.toJavaObjModel(), os, escapeSlash, false);
} else {
jsonSerializer.serializeAndQuotePrimitiveTo(o.toJavaObjModel(), w, escapeSlash, false);
}
}
private int indent = 0;
private final static String[] INDENTS = new String[] {
""," "," "," "," "," "," "
};
private void indent() throws UncheckedIOException {
try {
if(pretty) {
writeNewLine();
writeIndentSpaces(indent);
}
} catch (IOException e) {
throw EX.uncheckedIO(e);
}
}
private class CommaInsCtx implements JixHandler {
Stack<Cx> stack = new Stack<Cx>();
@Override
public void startObj() throws RuntimeException {
startValue();
stack.push(new Cx(obj));
}
@Override
public void endObj() throws RuntimeException {
stack.pop();
}
@Override
public void key(Key key) throws RuntimeException {
Cx cx = stack.peek();
if(cx.firstGone) {
try {
writeComma();
indent();
} catch (IOException e) {
}
} else {
cx.firstGone = true;
}
}
@Override
public void startArr() throws RuntimeException {
startValue();
stack.push(new Cx(arr));
}
@Override
public void endArr() throws RuntimeException {
stack.pop();
}
@Override
public void val(Val value) throws RuntimeException {
startValue();
}
private void startValue() throws RuntimeException {
if(stack.isEmpty()) {
return;
}
Cx cx = stack.peek();
if(cx.t == arr) {
if(cx.firstGone) {
try {
writeComma();
indent();
} catch (IOException e) {
throw EX.uncheckedIO(e);
}
} else {
cx.firstGone = true;
}
}
}
}
private final static byte[][] INDENTS_BYTE = new byte[INDENTS.length][];
static {
for(int i = 0; i < INDENTS.length; i++) {
INDENTS_BYTE[i] = STR.getBytesUtf8(INDENTS[i]);
}
};
private String indentSpaces(int size) {
if(size < INDENTS.length) {
return INDENTS[size];
} else {
return new String(indentSpaceBytes(size));
}
}
private byte[] indentSpaceBytes(int size) {
if(size < INDENTS_BYTE.length) {
return INDENTS_BYTE[size];
} else {
byte[] barr = new byte[size];
for(int i = 0; i < size; i++) {
barr[i] = ' ';
}
return barr;
}
}
private void writeIndentSpaces(int _indent) throws IOException {
if(binary) {
os.write(indentSpaceBytes(_indent));
} else {
w.write(indentSpaces(_indent));
}
}
private void writeNewLine() throws IOException {
if(binary) {
os.write(NEWLINE_ON_WIRE);
} else {
w.write("\n");
}
}
private void writeComma() throws IOException {
if(binary) {
os.write(COMMA_ON_WIRE);
} else {
w.write(",");
}
}
private void writeLSquare() throws IOException {
if(binary) {
os.write(LSQUARE_ON_WIRE);
} else {
w.write("[");
}
}
private void writeRSquare() throws IOException {
if(binary) {
os.write(RSQUARE_ON_WIRE);
} else {
w.write("]");
}
}
private void writeRCurly() throws IOException {
if(binary) {
os.write(RCURLY_ON_WIRE);
} else {
w.write("}");
}
}
private void writeLCurly() throws IOException {
if(binary) {
os.write(LCURLY_ON_WIRE);
} else {
w.write("{");
}
}
private void writeColon() throws IOException {
if(binary) {
os.write(COLON_ON_WIRE);
} else {
w.write(":");
}
}
private void writeString(String key) {
if(binary) {
jsonSerializer.serializeAndQuotePrimitiveTo(key, os, escapeSlash, false);
} else {
jsonSerializer.serializeAndQuotePrimitiveTo(key, w, escapeSlash, false);
}
}
private class Cx {
public JsonType t;
public boolean firstGone;
public Cx(JsonType t) {
this.t = t;
this.firstGone = false;
}
}
public void flush() throws IOException {
if(binary) {
os.flush();
} else {
w.flush();
}
}
}