//
// Copyright (c) 2013, Brian Frank
// Licensed under the Academic Free License version 3.0
//
// History:
// 18 Apr 2013 Brian Frank Creation
//
package org.haystack.io;
import java.io.OutputStream;
import java.io.Writer;
import java.util.Iterator;
import java.util.Map.Entry;
import org.haystack.HCol;
import org.haystack.HDict;
import org.haystack.HGridBuilder;
import org.haystack.HRow;
import org.haystack.tagval.HBool;
import org.haystack.tagval.HMarker;
import org.haystack.tagval.HNum;
import org.haystack.tagval.HRef;
import org.haystack.tagval.HStr;
import org.haystack.tagval.HVal;
/**
* HJsonWriter is used to write grids in JavaScript Object Notation.
* It is a plain text format commonly used for serialization of data.
** It is specified in RFC 4627.
*
* @see <a href='http://project-haystack.org/doc/Json'>Project Haystack</a>
*/
public class HJsonWriter extends HGridWriter {
private final HGridBuilder builder = new HGridBuilder();
//////////////////////////////////////////////////////////////////////////
// Construction
//////////////////////////////////////////////////////////////////////////
/** Write using UTF-8 */
public HJsonWriter(OutputStream out) {
super(out);
}
public HJsonWriter(Writer out) {
super(out);
}
//////////////////////////////////////////////////////////////////////////
// HGridWriter
//////////////////////////////////////////////////////////////////////////
@Override
public void writeMeta(HDict meta) {
// grid begin
out.print("{\n");
// meta
out.print("\"meta\": {\"ver\":\"2.0\"");
writeDictTags(meta, false);
out.print("},\n");
}
@Override
public void writeCols(HCol[] cols) {
// cols
out.print("\"cols\":[\n");
for (int i = 0; i < cols.length; ++i) {
if (i > 0)
out.print(",\n");
out.print("{\"name\":");
out.print(HStr.toCode(cols[i].name()));
writeDictTags(cols[i].meta(), false);
out.print("}");
}
out.print("\n],\n");
// row start
out.print("\"rows\":[\n");
}
@Override
public void writeRow(HCol[] cols, HRow row, int index) {
if (index > 0)
out.print(",\n");
out.print("{");
boolean first = true;
for (int i = 0; i < cols.length; ++i) {
if (first)
first = false;
else
out.print(", ");
String name = cols[i].name();
out.print(HStr.toCode(name));
out.print(":");
writeVal(row.get(cols[i], false));
}
out.print("}");
}
private void writeDictTags(HDict dict, boolean first) {
for (Iterator<Entry<String, HVal>> it = dict.iterator(); it.hasNext();) {
if (first)
first = false;
else
out.print(", ");
Entry<String, HVal> entry = it.next();
String name = entry.getKey();
HVal val = entry.getValue();
out.print(HStr.toCode(name));
out.print(":");
writeVal(val);
}
}
private void writeVal(HVal val) {
if (val == null)
out.print("null");
else if (val instanceof HMarker)
out.print("\"\u2713\"");
else if (val instanceof HBool)
out.print(val);
else if (val instanceof HNum)
out.print(((HNum) val).val);
else if (val instanceof HRef) {
HRef ref = (HRef) val;
StringBuilder s = new StringBuilder();
s.append("@").append(ref.val);
if (ref.dis != null)
s.append(" ").append(ref.dis);
out.print(HStr.toCode(s.toString()));
}
else
out.print(HStr.toCode(val.toString()));
}
/** Flush underlying output stream */
@Override
public void flush() {
// rows end
out.print("\n]\n");
// grid end
out.print("}\n");
super.flush();
}
}