/* DOMTokenList binding for browser using duktape and libdom
 *
 * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
 *
 * This file is part of NetSurf, http://www.netsurf-browser.org/
 *
 * Released under the terms of the MIT License,
 *         http://www.opensource.org/licenses/mit-license
 */

class DOMTokenList {
	private struct dom_tokenlist *tokens;
};

init DOMTokenList(struct dom_tokenlist *tokens)
%{
	priv->tokens = tokens;
	dom_tokenlist_ref(tokens);
%}

fini DOMTokenList()
%{
	dom_tokenlist_unref(priv->tokens);
%}

getter DOMTokenList::length()
%{
	dom_exception err;
	uint32_t len;

	err = dom_tokenlist_get_length(priv->tokens, &len);

	if (err != DOM_NO_ERR) return 0; /* coerced to undefined */

	duk_push_uint(ctx, (duk_uint_t)len);

	return 1;
%}

method DOMTokenList::item()
%{
	unsigned long i = duk_to_uint(ctx, 0);
	dom_exception err;
	dom_string *value;

	err = dom_tokenlist_item(priv->tokens, i, &value);

	if (err != DOM_NO_ERR) return 0; /* coerced to undefined */

    if (value == NULL) {
        duk_push_null(ctx);
        return 1;
    }

    duk_push_lstring(ctx, dom_string_data(value), dom_string_length(value));
	dom_string_unref(value);

	return 1;
%}

method DOMTokenList::add()
%{
	dom_exception exc;
	dom_string *value;
	duk_size_t slen;
	const char *s;
	duk_idx_t spos;

	for (spos = 0; spos < duk_get_top(ctx); ++spos) {
		s = duk_safe_to_lstring(ctx, spos, &slen);

		duk_safe_to_lstring(ctx, 0, &slen);

		exc = dom_string_create_interned((const uint8_t *)s, slen, &value);
		if (exc != DOM_NO_ERR) return 0;

		exc = dom_tokenlist_add(priv->tokens, value);
		dom_string_unref(value);
	}
	
	return 0;
%}

method DOMTokenList::remove()
%{
	dom_exception exc;
	dom_string *value;
	duk_size_t slen;
	const char *s;
	duk_idx_t spos;

	for (spos = 0; spos < duk_get_top(ctx); ++spos) {
		s = duk_safe_to_lstring(ctx, spos, &slen);

		duk_safe_to_lstring(ctx, 0, &slen);

		exc = dom_string_create_interned((const uint8_t *)s, slen, &value);
		if (exc != DOM_NO_ERR) return 0;

		exc = dom_tokenlist_remove(priv->tokens, value);
		dom_string_unref(value);
	}
	
	return 0;
%}

method DOMTokenList::contains()
%{
	dom_exception exc;
	dom_string *value;
	duk_size_t slen;
	const char *s = duk_safe_to_lstring(ctx, 0, &slen);
	bool present = false;

	exc = dom_string_create_interned((const uint8_t *)s, slen, &value);
	if (exc != DOM_NO_ERR) return 0;

	exc = dom_tokenlist_contains(priv->tokens, value, &present);
	dom_string_unref(value);
	if (exc != DOM_NO_ERR) return 0;

	duk_push_boolean(ctx, present);
	
	return 1;
%}

method DOMTokenList::toggle()
%{
	dom_exception exc;
	dom_string *value;
	duk_size_t slen;
	const char *s = duk_require_lstring(ctx, 0, &slen);
	bool toggle_set = duk_get_top(ctx) > 1;
	bool toggle = duk_opt_boolean(ctx, 1, 0);
	bool present;

	exc = dom_string_create_interned((const uint8_t *)s, slen, &value);
	if (exc != DOM_NO_ERR) return 0;

	exc = dom_tokenlist_contains(priv->tokens, value, &present);
	if (exc != DOM_NO_ERR) {
		dom_string_unref(value);
		return 0;
	}

	/* Decision matrix is based on present, toggle_set, and toggle */
	if (toggle_set) {
		if (toggle) {
			exc = dom_tokenlist_add(priv->tokens, value);
		} else {
			exc = dom_tokenlist_remove(priv->tokens, value);
		}
	} else {
		if (present) {
			exc = dom_tokenlist_add(priv->tokens, value);
		} else {
			exc = dom_tokenlist_remove(priv->tokens, value);
		}
	}
	dom_string_unref(value);

	return 0;
%}