var blob = use('blob')
var utf8 = use('utf8')

var INT = new blob(8, false)
stone(INT)

var FP_HEADER = new blob(64)
FP_HEADER.write_fit(0,56)
FP_HEADER.write_fit(1,8)
stone(FP_HEADER)

var ARRAY = new blob(8)
ARRAY.write_fit(2,8)
stone(ARRAY)

var RECORD = new blob(8)
RECORD.write_fit(3,8)
stone(RECORD)

var BLOB = new blob(8)
BLOB.write_fit(4,8)
stone(BLOB)

var TEXT = new blob(8)
TEXT.write_fit(5,8)
stone(TEXT)

var NULL_SYMBOL = new blob(64)
NULL_SYMBOL.write_fit(0,56)
NULL_SYMBOL.write_fit(7,8)
stone(NULL_SYMBOL)

var FALSE_SYMBOL = new blob(64)
FALSE_SYMBOL.write_fit(2,56)
FALSE_SYMBOL.write_fit(7,8)
stone(FALSE_SYMBOL)

var TRUE_SYMBOL = new blob(64)
TRUE_SYMBOL.write_fit(3,56)
TRUE_SYMBOL.write_fit(7,8)
stone(TRUE_SYMBOL)

var PRIVATE_SYMBOL = new blob(64)
PRIVATE_SYMBOL.write_fit(8,56)
PRIVATE_SYMBOL.write_fit(7,8)
stone(PRIVATE_SYMBOL)

var SYSTEM_SYMBOL = new blob(64)
SYSTEM_SYMBOL.write_fit(9,56)
SYSTEM_SYMBOL.write_fit(7,8)
stone(SYSTEM_SYMBOL)

var key_cache = {}

function encode_key(key)
{
  if (key_cache[key])
    return key_cache[key]
  
  var encoded_key = utf8.encode(key)
  var cached_blob = new blob(64 + encoded_key.length)
  cached_blob.write_fit(utf8.byte_length(key), 56)
  cached_blob.write_blob(TEXT)
  cached_blob.write_blob(encoded_key)
  stone(cached_blob)
  
  key_cache[key] = cached_blob
  return cached_blob
}

function encode_val(b, val)
{
  var type = typeof val
  if (type == 'number') {
    b.write_blob(FP_HEADER)
    b.write_number(val)
  } else if (type == 'string') {
    b.write_fit(utf8.byte_length(val), 56)
    b.write_blob(TEXT)
    b.write_blob(utf8.encode(val))
  } else if (type == 'boolean') {
    if (val)
      b.write_blob(TRUE_SYMBOL)
    else
      b.write_blob(FALSE_SYMBOL)
  } else if (type == 'null') {
    b.write_blob(NULL_SYMBOL)
  } else if (type == 'object') {
    if (Array.isArray(val)) {
      b.write_fit(val.length, 56)
      b.write_blob(ARRAY)
      for (var v of val)
        encode_val(b, v)
    } else if (val instanceof blob) {
      b.write_fit(val.length, 56)
      b.write_blob(BLOB)
      b.write_blob(val)
    } else {
      var keys = Object.keys(val)
      b.write_fit(keys.length, 56)
      b.write_blob(RECORD)
      for (var key of keys) {
        if (typeof val[key] == 'function') continue
        b.write_blob(encode_key(key))
        encode_val(b, val[key])
      }
    }
  }
}

function encode(val)
{
  var b = new blob(8*256)// guess a good length
  encode_val(b,val)

  return stone(b)
}

function decode(b)
{
  return null
}

return { INT, FP_HEADER, ARRAY, RECORD, BLOB, TEXT, NULL_SYMBOL, FALSE_SYMBOL, TRUE_SYMBOL, PRIVATE_SYMBOL, SYSTEM_SYMBOL, encode, decode }