/* Node.js Buffer, "full slice" */
static duk_ret_t test_nodejs_buffer_indexed_1a(duk_context *ctx) {
	duk_push_dynamic_buffer(ctx, 100);
	setup_nodejs_buffer(ctx, -1);
	shared_read_write_index(ctx, 95);

	printf("final top: %ld\n", (long) duk_get_top(ctx));
	return 0;
}
static duk_ret_t test_json_serialize_1(duk_context *ctx, void *udata) {
	unsigned char *data;
	int i;
	duk_uarridx_t arridx = 0;

	(void) udata;

	data = (unsigned char *) duk_push_dynamic_buffer(ctx, 20);
	for (i = 0; i < 20; i++) {
		data[i] = 0x40 + i;
	}

	duk_push_array(ctx);  /* index 1 */
	setup_duktape_buffer(ctx, 0);
	duk_put_prop_index(ctx, 1, arridx++);
	setup_nodejs_buffer(ctx, 0);
	duk_put_prop_index(ctx, 1, arridx++);
	setup_nodejs_buffer_slice(ctx, 0, 3, 5);
	duk_put_prop_index(ctx, 1, arridx++);
	setup_arraybuffer(ctx, 0);
	duk_put_prop_index(ctx, 1, arridx++);
	setup_typedarray(ctx, 0, "Uint8Array");
	duk_put_prop_index(ctx, 1, arridx++);
	setup_typedarray_slice(ctx, 0, "Uint8Array", 2, 6);
	duk_put_prop_index(ctx, 1, arridx++);
	setup_typedarray(ctx, 0, "Uint32Array");
	duk_put_prop_index(ctx, 1, arridx++);
	setup_typedarray_slice(ctx, 0, "Uint32Array", 4, 1);
	duk_put_prop_index(ctx, 1, arridx++);

	/* Serialize with a full backing buffer first. */

	for (i = 20; i >= 0; i--) {
		printf("resize to %d\n", i);
		duk_resize_buffer(ctx, 0, i);

		duk_dup(ctx, 1);
		duk_json_encode(ctx, -1);
		printf("%s\n", duk_to_string(ctx, -1));
		duk_pop(ctx);
		duk_eval_string(ctx, "(function (v) { print(Duktape.enc('jx', v)); })");
		duk_dup(ctx, 1);
		duk_call(ctx, 1);
		duk_pop(ctx);
	}

	printf("final top: %ld\n", (long) duk_get_top(ctx));
	return 0;
}
static duk_ret_t test_nodejs_buffer_write_1(duk_context *ctx, void *udata) {
	int i, dst, src;
	unsigned char *data;

	(void) udata;

	data = (unsigned char *) duk_push_dynamic_buffer(ctx, 10);  /* index 0 */
	for (i = 0; i < 10; i++) {
		data[i] = 0x40 + i;
	}

	setup_nodejs_buffer(ctx, 0);              /* index 1 */
	setup_nodejs_buffer_slice(ctx, 0, 1, 4);  /* index 2 */
	setup_nodejs_buffer_slice(ctx, 0, 3, 7);  /* index 3 */
	setup_nodejs_buffer_slice(ctx, 0, 6, 9);  /* index 4 */
	duk_push_string(ctx, "");                 /* index 5 */
	duk_push_string(ctx, "fo");               /* index 6 */
	duk_push_string(ctx, "bar");              /* index 7 */
	duk_push_string(ctx, "quux");             /* index 8 */

	for (i = 10; i >= 0; i--) {
		duk_resize_buffer(ctx, 0, i);

		/* The resulting buffers are not printed here; they're not very
		 * intuitive because both the source and the destination share
		 * the same underlying buffer.
		 */

		for (dst = 1; dst <= 4; dst++) {
			for (src = 5; src <= 8; src++) {
				printf("%d %d %d\n", i, dst, src);
				duk_eval_string(ctx,
					"(function (dst, src) {\n"
					"    for (var i = 0; i < dst.length; i++) { dst[i] = 0x11; }\n"
					"    dst.write(src);\n"
					"    for (var i = 0; i < dst.length; i++) { dst[i] = 0x11; }\n"
					"    dst.write(src, 1);\n"
					"})");
				duk_dup(ctx, dst);
				duk_dup(ctx, src);
				duk_call(ctx, 2);
				duk_pop(ctx);
			}
		}
	}

	printf("final top: %ld\n", (long) duk_get_top(ctx));
	return 0;
}
static int test_nodejs_buffer_copy_1(duk_context *ctx) {
	int i, dst, src;
	unsigned char *data;

	data = (unsigned char *) duk_push_dynamic_buffer(ctx, 10);  /* index 0 */
	for (i = 0; i < 10; i++) {
		data[i] = 0x40 + i;
	}

	setup_nodejs_buffer(ctx, 0);
	setup_nodejs_buffer_slice(ctx, 0, 1, 4);
	setup_nodejs_buffer_slice(ctx, 0, 3, 7);
	setup_nodejs_buffer_slice(ctx, 0, 6, 9);

	for (i = 10; i >= 0; i--) {
		duk_resize_buffer(ctx, 0, i);

		/* The resulting buffers are not printed here; they're not very
		 * intuitive because both the source and the destination share
		 * the same underlying buffer.
		 */

		for (dst = 1; dst <= 4; dst++) {
			for (src = 1; src <= 4; src++) {
				printf("%d %d %d\n", i, dst, src);
				duk_eval_string(ctx,
					"(function (dst, src) {\n"
					"    for (var i = 0; i < dst.length; i++) { dst[i] = 0x11; }\n"
					"    for (var i = 0; i < src.length; i++) { src[i] = 0x22; }\n"
					"    src.copy(dst);\n"
					"    for (var i = 0; i < dst.length; i++) { dst[i] = 0x11; }\n"
					"    for (var i = 0; i < src.length; i++) { src[i] = 0x22; }\n"
					"    src.copy(dst, 4, 1);\n"
					"})");
				duk_dup(ctx, dst);
				duk_dup(ctx, src);
				duk_call(ctx, 2);
				duk_pop(ctx);
			}
		}
	}

	printf("final top: %ld\n", (long) duk_get_top(ctx));
	return 0;
}
static duk_ret_t test_nodejs_buffer_compare_1(duk_context *ctx, void *udata) {
	int i, dst, src;
	unsigned char *data;

	(void) udata;

	/* There are two relevant methods: Buffer.compare and Buffer.prototype.compare() */

	data = (unsigned char *) duk_push_dynamic_buffer(ctx, 10);  /* index 0 */
	for (i = 0; i < 10; i++) {
		data[i] = 0x40 + i;
	}

	setup_nodejs_buffer(ctx, 0);
	setup_nodejs_buffer_slice(ctx, 0, 1, 4);
	setup_nodejs_buffer_slice(ctx, 0, 3, 7);
	setup_nodejs_buffer_slice(ctx, 0, 6, 9);

	for (i = 10; i >= 0; i--) {
		duk_resize_buffer(ctx, 0, i);

		for (dst = 1; dst <= 4; dst++) {
			for (src = 1; src <= 4; src++) {
				printf("%d %d %d\n", i, dst, src);
				duk_eval_string(ctx,
					"(function (dst, src) {\n"
					"    print(Buffer.compare(dst, src), dst.compare(src));\n"
					"})");
				duk_dup(ctx, dst);
				duk_dup(ctx, src);
				duk_call(ctx, 2);
				duk_pop(ctx);
			}
		}
	}

	printf("final top: %ld\n", (long) duk_get_top(ctx));
	return 0;
}
static duk_ret_t test_nodejs_buffer_concat_1(duk_context *ctx, void *udata) {
	int i;
	unsigned char *data;

	(void) udata;

	data = (unsigned char *) duk_push_dynamic_buffer(ctx, 10);  /* index 0 */
	for (i = 0; i < 10; i++) {
		data[i] = 0x40 + i;
	}

	setup_nodejs_buffer(ctx, 0);
	setup_nodejs_buffer_slice(ctx, 0, 1, 6);
	setup_nodejs_buffer_slice(ctx, 0, 3, 7);
	setup_nodejs_buffer_slice(ctx, 0, 6, 9);
	setup_nodejs_buffer_slice(ctx, 0, 1, 8);

	for (i = 10; i >= 0; i--) {
		duk_resize_buffer(ctx, 0, i);

		printf("%d\n", i);
		duk_eval_string(ctx,
			"(function (arg1, arg2, arg3, arg4, arg5) {\n"
			"    var res = Buffer.concat([ arg1, arg2, arg3, arg4, arg5 ]);\n"
			"    print(Duktape.enc('jx', res));\n"
			"})");
		duk_dup(ctx, 1);
		duk_dup(ctx, 2);
		duk_dup(ctx, 3);
		duk_dup(ctx, 4);
		duk_dup(ctx, 5);
		duk_call(ctx, 5);
		duk_pop(ctx);
	}

	printf("final top: %ld\n", (long) duk_get_top(ctx));
	return 0;
}