/* ====================================================================
 * FTD4Linux Software License, Version 1.0
 *
 * Copyright (c) 2000-2004 The FTD4Linux Development Team.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        FTD4Linux Development Team (http://www.ftd4linux.2y.net/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "FTD" and "FTD4Linux" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact alguno@ftd4linux.2y.net.
 *
 * 5. Products derived from this software may not be called "FTD4Linux",
 *    nor may "FTD4Linux" appear in their name, without prior written
 *    permission of the FTD4Linux Development Team.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE FTD4LINUX DEVELOPMENT TEAM OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <glib-object.h>
#include "ftd4linux.h"
#include "ftd_app_core.h"
#include "ftd_filter.h"

static void          ftd_filterlist_init_default(FTDFilterlist *obj);
static FtdFilter    *ftd_filter_parse_filter(xmlDocPtr doc, xmlNodePtr cur);
static FtdList      *ftd_filter_parse(FtdString *buffer);
static xmlNodePtr    ftd_filter_xml_add(FtdFilter *, xmlDocPtr);
static void          ftd_filterlist_clear(FTDFilterlist *obj);

typedef struct FTDFilterlistClass FTDFilterlistClass;

FTDFilterlist *ftd_filterlist_get_object(void);
GType ftd_filter_list_get_type (void);

struct FTDFilterlist
{
    GObject parent;

    GStaticRWLock rwlock;

    FtdList *avail_filters;
    FTDFilterObject *active_filter;
};

struct FTDFilterlistClass
{
    GObjectClass parent;
};

enum
{
  BRING_TO_FRONT_SIGNAL,
  OPEN_POSTING_SIGNAL,
  LAST_SIGNAL
};

static guint signals[LAST_SIGNAL] = { 0 };

G_DEFINE_TYPE(FTDFilterlist, ftd_filterlist, G_TYPE_OBJECT)

static void
ftd_filterlist_init (FTDFilterlist *obj)
{
    g_static_rw_lock_init(&obj->rwlock);

    obj->avail_filters = NULL;
    obj->active_filter = NULL;
}

static void
filterlist_finalize (GObject *obj)
{
    FTDFilterlist *filterlist = FTD_FILTERLIST(obj);

    g_static_rw_lock_writer_lock(&filterlist->rwlock);

    if (filterlist->avail_filters) {
        FtdList *list = filterlist->avail_filters;

        while (list) {
            FtdFilter *filter = ftd_list_value(list);
            ftd_filter_free_filter(filter);
            list = ftd_list_next(list);
        }

        ftd_list_free(filterlist->avail_filters);
        filterlist->avail_filters = NULL;
    }

    if (filterlist->active_filter) {
        g_object_unref(filterlist->active_filter);
        filterlist->active_filter = NULL;
    }

    g_static_rw_lock_writer_unlock(&filterlist->rwlock);
    g_static_rw_lock_free(&filterlist->rwlock);
}

static void
ftd_filterlist_class_init (FTDFilterlistClass *klass)
{
    GObjectClass *gobject_class = G_OBJECT_CLASS (klass);

    gobject_class->finalize = filterlist_finalize;

#if 0
    signals[BRING_TO_FRONT_SIGNAL] = g_signal_new  ("bring_to_front",
                                                    G_OBJECT_CLASS_TYPE (klass),
                                                    G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
                                                    0,
                                                    NULL, NULL,
                                                    g_cclosure_marshal_VOID__VOID,
                                                    G_TYPE_NONE, 0);

    signals[OPEN_POSTING_SIGNAL] = g_signal_new    ("open_posting",
                                                    G_OBJECT_CLASS_TYPE (klass),
                                                    G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
                                                    0,
                                                    NULL, NULL,
                                                    g_cclosure_marshal_VOID__INT,
                                                    G_TYPE_NONE, 1, G_TYPE_INT);
#endif
}

FTDFilterlist *
ftd_filterlist_new(void)
{
    return g_object_new(FTD_FILTERLIST_TYPE_OBJECT, NULL);
}

void
ftd_filterlist_destroy(FTDFilterlist *obj)
{
    g_object_unref(obj);
}

/**
 * Bouwt de standaard collectie aan filters op.
 * Dit zijn de filters die bij een nieuwe installatie van FTD4linux horen.
 */
static void
ftd_filterlist_init_default(FTDFilterlist *obj)
{
    FtdFilter *filter;
    FTDFilterlist *filterlist = FTD_FILTERLIST(obj);

    filter = ftd_filter_new_filter();
    filter->cat = 0;
    filter->sCat = 0;
    filter->filterNaam = ftd_string_new( "DivX" );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "a0" ) );
    // Alle genres behalve erotische:
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d0" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d1" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d2" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d3" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d4" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d5" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d6" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d7" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d8" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d9" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d10" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d11" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d12" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d13" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d14" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d15" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d16" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d17" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d18" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d19" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d20" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d21" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d22" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d27" ) );
    ftd_filterlist_append_filter(obj, filter);
    ftd_filter_free_filter(filter);

    filter = ftd_filter_new_filter( );
    filter->cat = 0;
    filter->sCat = 1;
    filter->filterNaam = ftd_string_new( "WMV" );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "a1" ) );
    // Alle genres behalve erotische:
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d0" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d1" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d2" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d3" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d4" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d5" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d6" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d7" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d8" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d9" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d10" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d11" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d12" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d13" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d14" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d15" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d16" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d17" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d18" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d19" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d20" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d21" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d22" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d27" ) );
    ftd_filterlist_append_filter(obj, filter);
    ftd_filter_free_filter(filter);

    filter = ftd_filter_new_filter( );
    filter->cat = 0;
    filter->sCat = 2;
    filter->filterNaam = ftd_string_new( "MPG" );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "a2" ) );
    // Alle genres behalve erotische:
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d0" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d1" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d2" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d3" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d4" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d5" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d6" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d7" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d8" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d9" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d10" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d11" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d12" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d13" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d14" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d15" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d16" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d17" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d18" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d19" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d20" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d21" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d22" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d27" ) );
    ftd_filterlist_append_filter(obj, filter);
    ftd_filter_free_filter(filter);

    filter = ftd_filter_new_filter( );
    filter->cat = 0;
    filter->sCat = 3;
    filter->filterNaam = ftd_string_new( "DVD" );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "a3" ) );
    // Alle genres behalve erotische:
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d0" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d1" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d2" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d3" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d4" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d5" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d6" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d7" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d8" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d9" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d10" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d11" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d12" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d13" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d14" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d15" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d16" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d17" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d18" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d19" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d20" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d21" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d22" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d27" ) );
    ftd_filterlist_append_filter(obj, filter);
    ftd_filter_free_filter(filter);

    filter = ftd_filter_new_filter( );
    filter->cat = 0;
    filter->sCat = 4;
    filter->filterNaam = ftd_string_new( "HDTV" );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "a4" ) );
    // Alle genres behalve erotische:
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d0" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d1" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d2" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d3" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d4" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d5" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d6" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d7" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d8" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d9" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d10" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d11" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d12" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d13" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d14" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d15" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d16" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d17" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d18" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d19" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d20" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d21" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d22" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d27" ) );
    ftd_filterlist_append_filter(obj, filter);
    ftd_filter_free_filter(filter);

    filter = ftd_filter_new_filter( );
    filter->cat = 0;
    filter->sCat = 5;
    filter->filterNaam = ftd_string_new( "Afbeeldingen" );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "a5" ) );
    // Alle genres behalve erotische:
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d0" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d1" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d2" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d3" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d4" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d5" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d6" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d7" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d8" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d9" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d10" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d11" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d12" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d13" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d14" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d15" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d16" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d17" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d18" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d19" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d20" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d21" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d22" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d27" ) );
    ftd_filterlist_append_filter(obj, filter);
    ftd_filter_free_filter(filter);

    filter = ftd_filter_new_filter( );
    filter->cat = 0;
    filter->filterNaam = ftd_string_new( "Erotiek" );
    // Alle erotische genres:
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d23" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d24" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d25" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "d26" ) );
    ftd_filterlist_append_filter(obj, filter);
    ftd_filter_free_filter(filter);

    filter = ftd_filter_new_filter( );
    filter->cat = 1;
    filter->filterNaam = ftd_string_new( "Compressed" );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "a0" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "a1" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "a2" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "a3" ) );
    ftd_filterlist_append_filter(obj, filter);
    ftd_filter_free_filter(filter);

    filter = ftd_filter_new_filter( );
    filter->cat = 1;
    filter->sCat = 4;
    filter->filterNaam = ftd_string_new( "Lossless" );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "a4" ) );
    ftd_filterlist_append_filter(obj, filter);
    ftd_filter_free_filter(filter);

    filter = ftd_filter_new_filter( );
    filter->cat = 2;
    filter->sCat = 0;
    filter->filterNaam = ftd_string_new( "Windows" );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "a0" ) );
    ftd_filterlist_append_filter(obj, filter);
    ftd_filter_free_filter(filter);

    filter = ftd_filter_new_filter( );
    filter->cat = 2;
    filter->filterNaam = ftd_string_new( "Mac / Linux" );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "a1" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "a2" ) );
    ftd_filterlist_append_filter(obj, filter);
    ftd_filter_free_filter(filter);

    filter = ftd_filter_new_filter( );
    filter->cat = 2;
    filter->filterNaam = ftd_string_new( "PlayStation" );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "a3" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "a4" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "a5" ) );
    ftd_filterlist_append_filter(obj, filter);
    ftd_filter_free_filter(filter);

    filter = ftd_filter_new_filter( );
    filter->cat = 2;
    filter->filterNaam = ftd_string_new( "Overige consoles" );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "a6" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "a7" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "a8" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "a9" ) );
    ftd_filterlist_append_filter(obj, filter);
    ftd_filter_free_filter(filter);

    filter = ftd_filter_new_filter( );
    filter->cat = 3;
    filter->sCat = 0;
    filter->filterNaam = ftd_string_new( "Windows" );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "a0" ) );
    ftd_filterlist_append_filter(obj, filter);
    ftd_filter_free_filter(filter);

    filter = ftd_filter_new_filter( );
    filter->cat = 3;
    filter->filterNaam = ftd_string_new( "Mac / Linux / OS2" );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "a1" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "a2" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "a3" ) );
    ftd_filterlist_append_filter(obj, filter);
    ftd_filter_free_filter(filter);

    filter = ftd_filter_new_filter( );
    filter->cat = 3;
    filter->filterNaam = ftd_string_new( "PDA / Navigatie" );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "a4" ) );
    filter->tags = ftd_list_append( filter->tags, ftd_string_new( "a5" ) );
    ftd_filterlist_append_filter(obj, filter);
    ftd_filter_free_filter(filter);
}

/**
 * Laad de opgeslagen filters.
 */
void
ftd_filterlist_load(FTDFilterlist *obj)
{
    FTDFilterlist *filterlist = FTD_FILTERLIST(obj);
    FtdString *inhoud;

    g_static_rw_lock_writer_lock(&filterlist->rwlock);

    if (filterlist->avail_filters) {
        FtdList *list = filterlist->avail_filters;

        while (list) {
            FtdFilter *filter = ftd_list_value(list);
            ftd_filter_free_filter(filter);
            list = ftd_list_next(list);
        }

        ftd_list_free(filterlist->avail_filters);
        filterlist->avail_filters = NULL;
    }

    inhoud = ftd_file_load(FILTERS_FILE, FALSE);
    if (inhoud == NULL) {
        g_static_rw_lock_writer_unlock(&filterlist->rwlock);
        ftd_filterlist_init_default(filterlist);
        ftd_filterlist_save(filterlist);
        return;
    }

    filterlist->avail_filters = ftd_filter_parse (inhoud);

    ftd_string_free(inhoud);

    g_static_rw_lock_writer_unlock(&filterlist->rwlock);
}

/**
 * Slaat de filters op.
 */
void
ftd_filterlist_save(FTDFilterlist *obj)
{
    char *volledigeFilename;
    xmlDocPtr doc;
    xmlNodePtr rootNode;
    int retval;
    FTDFilterlist *filterlist = FTD_FILTERLIST(obj);
    FtdList *list;

    g_static_rw_lock_reader_lock(&filterlist->rwlock);

    doc = xmlNewDoc(BAD_CAST "1.0");
    rootNode = xmlNewNode(NULL, BAD_CAST "Filters");
    xmlDocSetRootElement(doc, rootNode);

    list = filterlist->avail_filters;
    while (list) {
        FtdFilter *filter = ftd_list_value(list);

        xmlAddChild(rootNode, ftd_filter_xml_add(filter, doc));

        list = ftd_list_next(list);
    }

    volledigeFilename = ftd_file_parse_cache_filename(FILTERS_FILE, FALSE);
    xmlSetCompressMode(0);
    retval = xmlSaveFormatFile(volledigeFilename, doc, 1);
    g_free(volledigeFilename);

    xmlFreeDoc(doc);
    //xmlCleanupParser();

    g_static_rw_lock_reader_unlock(&filterlist->rwlock);
}

/**
 * Voegt de gegevens van een filter toe aan een XML boom.
 *
 * @arg     filter      Het filter waarvan de gegevens toegevoegd moeten worden.
 * @arg     doc         Het XML document waaraan de gegevens toegevoegd moeten worden.
 *
 * @return  Een nieuwe XML node met daarin de gegevens van het filter.
 */
xmlNodePtr
ftd_filter_xml_add(FtdFilter *filter, xmlDocPtr doc)
{
    xmlNodePtr node, cdataNode, tmpNode;
    FtdString *str;

    g_assert(filter);

    node = xmlNewNode(NULL, BAD_CAST "Filter");

    if (filter->filterNaam) {
        tmpNode = xmlNewNode(NULL, "filterNaam");
        cdataNode = xmlNewCDataBlock(doc, ftd_string_value(filter->filterNaam), ftd_string_length(filter->filterNaam));
        xmlAddChild(tmpNode, cdataNode);
        xmlAddChild(node, tmpNode);
    }

    str = ftd_string_integer(filter->cat);
    xmlNewTextChild(node, NULL, "cat", ftd_string_value(str));
    ftd_string_free(str);

    str = ftd_string_integer(filter->sCat);
    xmlNewTextChild(node, NULL, "sCat", ftd_string_value(str));
    ftd_string_free(str);

    if (filter->extra_tag) {
        tmpNode = xmlNewNode(NULL, "extra_tag");
        cdataNode = xmlNewCDataBlock(doc, ftd_string_value(filter->extra_tag), ftd_string_length(filter->extra_tag));
        xmlAddChild(tmpNode, cdataNode);
        xmlAddChild(node, tmpNode);
    }

    if( filter->tags ) {
        FtdList *list = filter->tags;
        while( list ) {
            FtdString *tag = ftd_list_value( list );
            if( tag ) {
                tmpNode = xmlNewNode(NULL, "tag");
                cdataNode = xmlNewCDataBlock(doc, ftd_string_value(tag), ftd_string_length(tag));
                xmlAddChild(tmpNode, cdataNode);
                xmlAddChild(node, tmpNode);
            }
            list = ftd_list_next( list );
        }
    }

    return node;
}

/**
 * Haalt een lijst met filters uit een XML gecodeerde string.
 *
 * @arg     buffer          De XML gecodeerde string met daarin de gegevens van de filters.
 *
 * @return  Een nieuwe lijst met ::FtdFilter pointers naar de geladen filters.
 */
FtdList *
ftd_filter_parse(FtdString *buffer)
{
    xmlDocPtr   doc;
    xmlNodePtr  cur;
    FtdList    *list = NULL;
    FtdFilter  *filter = NULL;

    g_assert(buffer);

    doc = xmlParseMemory(ftd_string_value(buffer), ftd_string_length(buffer));
    cur = xmlDocGetRootElement(doc);
    if (cur == NULL) {
        fprintf(stderr,"ftd_filter_parse(): empty document!\n");
        xmlFreeDoc(doc);
        return NULL;
    }

    if (strcasecmp(cur->name, "Filters")) {
        fprintf(stderr,"ftd_filter_parse(): document of the wrong type, root node != Filters");
        xmlFreeDoc(doc);
        return NULL;
    }

    cur = cur->xmlChildrenNode;
    if (!cur) {
        g_warning("ftd_filter_parse(): no children of root-node!\n");
        xmlFreeDoc(doc);
        return NULL;
    }

    while (cur) {
        if (!strcasecmp(cur->name, "Filter")) {
            filter = ftd_filter_parse_filter(doc, cur->xmlChildrenNode);

            list = ftd_list_append(list, filter);
        }
        cur = cur->next;
    }
    xmlFreeDoc(doc);

    return list;
}

/**
 * Leest een enkel filter uit een XML boom.
 *
 * @arg     doc         Het XML document waar het filter in staat.
 * @arg     cur         Een pointer naar het element in het document waar het filter staat.
 *
 * @return  Een nieuw filter met de gegevens uit de XML boom.
 */
FtdFilter *
ftd_filter_parse_filter(xmlDocPtr doc, xmlNodePtr cur)
{
    FtdFilter *filter = ftd_filter_new_filter( );

    while(cur != NULL) {
        if (!strcasecmp(cur->name, "filterNaam")) {
            filter->filterNaam = ftd_xml_parse_string(doc, cur);
        } else if (!strcasecmp(cur->name, "cat")) {
            filter->cat = ftd_xml_parse_int(doc, cur);
        } else if (!strcasecmp(cur->name, "sCat")) {
            filter->sCat = ftd_xml_parse_int(doc, cur);
        } else if (!strcasecmp(cur->name, "extra_tag")) {
            filter->extra_tag = ftd_xml_parse_string(doc, cur);
        } else if (!strcasecmp(cur->name, "tag")) {
            filter->tags = ftd_list_append( filter->tags, ftd_xml_parse_string(doc, cur) );
        }
        cur = cur->next;
    }

    return filter;
}

void
ftd_filterlist_append_filter(FTDFilterlist *obj, const FtdFilter *filter)
{
    FTDFilterlist *filterlist = FTD_FILTERLIST(obj);
    FtdFilter *filter_nieuw = ftd_filter_duplicate(filter);

    g_static_rw_lock_writer_lock(&filterlist->rwlock);

    filterlist->avail_filters = ftd_list_append(filterlist->avail_filters, filter_nieuw);

    g_static_rw_lock_writer_unlock(&filterlist->rwlock);
}

static void
ftd_filterlist_clear(FTDFilterlist *obj)
{
    FTDFilterlist *filterlist = FTD_FILTERLIST(obj);

    g_static_rw_lock_writer_lock(&filterlist->rwlock);

    if (filterlist->avail_filters) {
        FtdList *list = filterlist->avail_filters;

        while (list) {
            FtdFilter *filter = ftd_list_value(list);
            ftd_filter_free_filter(filter);
            list = ftd_list_next(list);
        }

        ftd_list_free(filterlist->avail_filters);
        filterlist->avail_filters = NULL;
    }

    g_static_rw_lock_writer_unlock(&filterlist->rwlock);
}

void
ftd_filterlist_foreach(FTDFilterlist *obj, gboolean read_only, GFunc cb, gpointer user_data)
{
    FTDFilterlist *filterlist = FTD_FILTERLIST(obj);

    if (read_only) {
        g_static_rw_lock_reader_lock(&filterlist->rwlock);
    } else {
        g_static_rw_lock_writer_lock(&filterlist->rwlock);
    }

    ftd_list_foreach(filterlist->avail_filters, cb, user_data);

    if (read_only) {
        g_static_rw_lock_reader_unlock(&filterlist->rwlock);
    } else {
        g_static_rw_lock_writer_unlock(&filterlist->rwlock);
    }
}

FTDFilterObject *
ftd_filterlist_get_active_filter(FTDFilterlist *obj)
{
    FTDFilterlist *filterlist = FTD_FILTERLIST(obj);
    FTDFilterObject *filter;

    g_static_rw_lock_reader_lock(&filterlist->rwlock);

    g_object_ref(filterlist->active_filter);
    filter = filterlist->active_filter;

    g_static_rw_lock_reader_unlock(&filterlist->rwlock);

    return filter;
}

/**
 * Stelt de lijst met filters in.
 * De oude lijst wordt vrijgegeven alvorens de nieuwe in te stellen.
 * Gebruik dus niet gegevens uit de oude lijst om deze nieuwe lijst te vullen, maar maak nieuwe filters aan!
 *
 * @arg     filters         Een lijst met ::FtdFilter pointers naar de nieuwe filters.
 */
void
ftd_filterlist_set_filters(FTDFilterlist *obj, FtdList *filters)
{
    FTDFilterlist *filterlist = FTD_FILTERLIST(obj);

    ftd_filterlist_clear(filterlist);

    g_static_rw_lock_writer_lock(&filterlist->rwlock);

    if (filters) {
        FtdList *list = filters;

        while (list) {
            FtdFilter *filter = ftd_list_value(list);
            FtdFilter *nieuw_filter = ftd_filter_duplicate(filter);
            filterlist->avail_filters = ftd_list_append(filterlist->avail_filters, nieuw_filter);

            list = ftd_list_next(list);
        }
    }

    g_static_rw_lock_writer_unlock(&filterlist->rwlock);

    ftd_categories_init();
    ftd_filterlist_save(filterlist);
}
