/*
 * call-seq: new(source, opts => {})
 *
 * Creates a new JSON::Ext::Parser instance for the string _source_.
 *
 * Creates a new JSON::Ext::Parser instance for the string _source_.
 *
 * It will be configured by the _opts_ hash. _opts_ can have the following
 * keys:
 *
 * _opts_ can have the following keys:
 * * *max_nesting*: The maximum depth of nesting allowed in the parsed data
 *   structures. Disable depth checking with :max_nesting => false|nil|0, it
 *   defaults to 19.
 * * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in
 *   defiance of RFC 4627 to be parsed by the Parser. This option defaults to
 *   false.
 * * *create_additions*: If set to false, the Parser doesn't create
 *   additions even if a matchin class and create_id was found. This option
 *   defaults to true.
 * * *object_class*: Defaults to Hash
 * * *array_class*: Defaults to Array
 */
static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
{
    char *ptr;
    long len;
    VALUE source, opts;
    GET_STRUCT;
    rb_scan_args(argc, argv, "11", &source, &opts);
    source = StringValue(source);
    ptr = RSTRING_PTR(source);
    len = RSTRING_LEN(source);
    if (len < 2) {
        rb_raise(eParserError, "A JSON text must at least contain two octets!");
    }
    if (!NIL_P(opts)) {
        opts = rb_convert_type(opts, T_HASH, "Hash", "to_hash");
        if (NIL_P(opts)) {
            rb_raise(rb_eArgError, "opts needs to be like a hash");
        } else {
            VALUE tmp = ID2SYM(i_max_nesting);
            if (st_lookup(RHASH_TBL(opts), tmp, 0)) {
                VALUE max_nesting = rb_hash_aref(opts, tmp);
                if (RTEST(max_nesting)) {
                    Check_Type(max_nesting, T_FIXNUM);
                    json->max_nesting = FIX2INT(max_nesting);
                } else {
                    json->max_nesting = 0;
                }
            } else {
                json->max_nesting = 19;
            }
            tmp = ID2SYM(i_allow_nan);
            if (st_lookup(RHASH_TBL(opts), tmp, 0)) {
                VALUE allow_nan = rb_hash_aref(opts, tmp);
                json->allow_nan = RTEST(allow_nan) ? 1 : 0;
            } else {
                json->allow_nan = 0;
            }
            tmp = ID2SYM(i_create_additions);
            if (st_lookup(RHASH_TBL(opts), tmp, 0)) {
                VALUE create_additions = rb_hash_aref(opts, tmp);
                if (RTEST(create_additions)) {
                    json->create_id = rb_funcall(mJSON, i_create_id, 0);
                } else {
                    json->create_id = Qnil;
                }
            } else {
                json->create_id = rb_funcall(mJSON, i_create_id, 0);
            }
            tmp = ID2SYM(i_object_class);
            if (st_lookup(RHASH_TBL(opts), tmp, 0)) {
                json->object_class = rb_hash_aref(opts, tmp);
            } else {
                json->object_class = Qnil;
            }
            tmp = ID2SYM(i_array_class);
            if (st_lookup(RHASH_TBL(opts), tmp, 0)) {
                json->array_class = rb_hash_aref(opts, tmp);
            } else {
                json->array_class = Qnil;
            }
        }
    } else {
        json->max_nesting = 19;
        json->allow_nan = 0;
        json->create_id = rb_funcall(mJSON, i_create_id, 0);
        json->object_class = Qnil;
        json->array_class = Qnil;
    }
    json->current_nesting = 0;
    /*
       Convert these?
    if (len >= 4 &&  ptr[0] == 0 && ptr[1] == 0 && ptr[2] == 0) {
        rb_raise(eParserError, "Only UTF8 octet streams are supported atm!");
    } else if (len >= 4 && ptr[0] == 0 && ptr[2] == 0) {
        rb_raise(eParserError, "Only UTF8 octet streams are supported atm!");
    } else if (len >= 4 && ptr[1] == 0 && ptr[2] == 0 && ptr[3] == 0) {
        rb_raise(eParserError, "Only UTF8 octet streams are supported atm!");
    } else if (len >= 4 && ptr[1] == 0 && ptr[3] == 0) {
        rb_raise(eParserError, "Only UTF8 octet streams are supported atm!");
    }
    */
    json->len = len;
    json->source = ptr;
    json->Vsource = source;
    return self;
}