#include "src/bookmarks/kz-bookmark-folder.h"

#include <gcutter.h>

void test_new (void);
void test_current_position (void);
void test_lock (void);
void test_auto_refresh (void);
void test_javascript (void);
void test_folded (void);
void test_append (void);
void test_prepend (void);
void test_insert_before (void);
void test_remove (void);
void test_remove_all (void);
void test_next (void);
void test_prev (void);
void test_get_parent (void);
void test_get_current_bookmark (void);
void test_find_bookmark_from_uri (void);
void test_child_index (void);

static KzBookmarkFolder *folder;
static KzBookmark *child;
static KzBookmark *another_child;
static KzBookmark *actual_child;
static KzBookmark *actual_sibling;

static GList *children;

static gint n_insert_child_received;
static gint n_remove_child_received;

static void 
cb_insert_child (KzBookmarkFolder *folder,
                 KzBookmark *child,
                 KzBookmark *sibling,
                 gpointer data)
{
    n_insert_child_received++;

    if (actual_child)
        g_object_unref(actual_child);
        
    actual_child = g_object_ref(child);

    if (actual_sibling) {
        g_object_unref(actual_sibling);
        actual_sibling = NULL;
    }
    if (sibling)
        actual_sibling = g_object_ref(sibling);
}

static void 
cb_remove_child (KzBookmarkFolder *folder,
                 KzBookmark *child,
                 gpointer data)
{
    n_remove_child_received++;

    if (actual_child) {
        g_object_unref(actual_child);
        actual_child = NULL;
    }
    actual_child = g_object_ref(child);
}

static void
connect_signals (void)
{
    g_signal_connect(folder, "insert-child",
                     G_CALLBACK(cb_insert_child), NULL);
    g_signal_connect(folder, "remove-child",
                     G_CALLBACK(cb_remove_child), NULL);
}

static gboolean
cb_check_emitted (gpointer data)
{
    gboolean *emitted = data;

    *emitted = TRUE;
    return FALSE;
}

static void
wait_signal (gint *n_signals, gint count)
{
    gboolean timeout_emitted = FALSE;
    guint timeout_id;

    timeout_id = g_timeout_add_seconds(1, cb_check_emitted, &timeout_emitted);
    while (!timeout_emitted && *n_signals < count)
        g_main_context_iteration(NULL, TRUE);

    g_source_remove(timeout_id);

    cut_assert_false(timeout_emitted, "timeout");
}

void
setup (void)
{
    folder =  NULL;
    child = NULL;
    another_child = NULL;
    actual_child = NULL;
    actual_sibling = NULL;
    children = NULL;

    n_insert_child_received = 0;
    n_remove_child_received = 0;
}

void
teardown (void)
{
    if (folder)
        g_object_unref(folder);
    if (child)
        g_object_unref(child);
    if (children)
        g_list_free(children);
    if (another_child)
        g_object_unref(another_child);
    if (actual_child)
        g_object_unref(actual_child);
    if (actual_sibling)
        g_object_unref(actual_sibling);
}

void
test_new (void)
{
    folder = KZ_BOOKMARK_FOLDER(kz_bookmark_folder_new("Test Folder"));
    cut_assert(folder);

    connect_signals();
    cut_assert_true(kz_bookmark_is_folder(folder));
}

void
test_current_position (void)
{
    cut_trace(test_new());
    kz_bookmark_folder_set_current_position(folder, 21);
    cut_assert_equal_uint(21, kz_bookmark_folder_get_current_position(folder));
}

void
test_lock (void)
{
    cut_trace(test_new());
    cut_assert_false(kz_bookmark_folder_get_lock(folder));
    kz_bookmark_folder_set_lock(folder, TRUE);
    cut_assert_true(kz_bookmark_folder_get_lock(folder));
}

void
test_javascript (void)
{
    cut_trace(test_new());
    cut_assert_true(kz_bookmark_folder_get_javascript(folder));
    kz_bookmark_folder_set_javascript(folder, FALSE);
    cut_assert_false(kz_bookmark_folder_get_javascript(folder));
}

void
test_auto_refresh (void)
{
    cut_trace(test_new());
    cut_assert_false(kz_bookmark_folder_get_auto_refresh(folder));
    kz_bookmark_folder_set_auto_refresh(folder, TRUE);
    cut_assert_true(kz_bookmark_folder_get_auto_refresh(folder));
}

void
test_append (void)
{
    cut_trace(test_new());

    cut_assert_false(kz_bookmark_folder_has_children(folder));
    child = kz_bookmark_new_with_attrs("Title", "URI", "Description");
    kz_bookmark_folder_append(folder, child);

    wait_signal(&n_insert_child_received, 1);
    cut_assert_true(kz_bookmark_folder_has_children(folder));

    children = kz_bookmark_folder_get_children(folder);
    cut_assert_equal_int(1, g_list_length(children));

    cut_assert_equal_pointer(children->data, child);
    cut_assert_equal_pointer(child, actual_child);
    cut_assert_null(actual_sibling);
}

void
test_prepend (void)
{
    cut_trace(test_append());

    another_child = kz_bookmark_new_with_attrs("Title", "Another URI", "Description");
    kz_bookmark_folder_prepend(folder, another_child);

    wait_signal(&n_insert_child_received, 1);
    children = kz_bookmark_folder_get_children(folder);
    cut_assert_equal_int(2, g_list_length(children));

    cut_assert_equal_pointer(children->data, another_child);
    cut_assert_equal_pointer(another_child, actual_child);
    cut_assert_null(actual_sibling);
}

void
test_insert_before (void)
{
    KzBookmark *another_child;

    cut_trace(test_append());

    another_child = kz_bookmark_new_with_attrs("Title", "URI", "Description");
    kz_bookmark_folder_insert_before(folder, another_child, child);

    wait_signal(&n_insert_child_received, 1);
    children = kz_bookmark_folder_get_children(folder);
    cut_assert_equal_int(2, g_list_length(children));

    cut_assert_equal_pointer(children->data, another_child);

    cut_assert_equal_pointer(another_child, actual_child);
    cut_assert_equal_pointer(child, actual_sibling);
}

void
test_remove (void)
{
    cut_trace(test_append());

    kz_bookmark_folder_remove(folder, child);
    wait_signal(&n_remove_child_received, 1);

    cut_assert_false(kz_bookmark_folder_has_children(folder));
    cut_assert_equal_pointer(child, actual_child);
}

void
test_remove_all (void)
{
    cut_trace(test_prepend());

    kz_bookmark_folder_remove_all(folder);
    wait_signal(&n_remove_child_received, 2);

    cut_assert_false(kz_bookmark_folder_has_children(folder));
    cut_assert_equal_pointer(another_child, actual_child);
}

void
test_next (void)
{
    cut_trace(test_prepend());

    cut_assert_equal_pointer(child, kz_bookmark_next(another_child));
    cut_assert_null(kz_bookmark_next(child));
}

void
test_prev (void)
{
    cut_trace(test_prepend());

    cut_assert_equal_pointer(another_child, kz_bookmark_prev(child));
    cut_assert_null(kz_bookmark_prev(another_child));
}

void
test_get_parent (void)
{
    cut_trace(test_prepend());

    cut_assert_equal_pointer(folder, kz_bookmark_get_parent(child));
    cut_assert_equal_pointer(folder, kz_bookmark_get_parent(another_child));
    cut_assert_null(kz_bookmark_get_parent(KZ_BOOKMARK(folder)));
}

void
test_get_current_bookmark (void)
{
    cut_trace(test_prepend());

    kz_bookmark_folder_set_current_position(folder, 0);
    cut_assert_equal_pointer(another_child, kz_bookmark_folder_get_current_bookmark(folder));
    kz_bookmark_folder_set_current_position(folder, 1);
    cut_assert_equal_pointer(child, kz_bookmark_folder_get_current_bookmark(folder));
}

void
test_find_bookmark_from_uri (void)
{
    cut_trace(test_prepend());

    cut_assert_equal_pointer(another_child,
                             kz_bookmark_folder_find_bookmark_from_uri(folder, "Another URI"));
}

void
test_folded (void)
{
    cut_trace(test_new());

    cut_assert_true(kz_bookmark_folder_get_folded(folder));

    kz_bookmark_folder_set_folded(folder, FALSE);
    cut_assert_false(kz_bookmark_folder_get_folded(folder));

    kz_bookmark_folder_set_folded(folder, TRUE);
    cut_assert_true(kz_bookmark_folder_get_folded(folder));

}

void
test_child_index (void)
{
    cut_trace(test_prepend());

    cut_assert_equal_int(0, kz_bookmark_folder_get_child_index(folder, another_child));
    cut_assert_equal_int(1, kz_bookmark_folder_get_child_index(folder, child));
}

/*
vi:ts=4:nowrap:ai:expandtab:sw=4
*/
