/* ====================================================================
 * 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 "ftd4linux.h"
#include "ftd_app_core.h"
#include "ftd_config.h"
#include "ftd_watchlist.h"

static FtdString       *ftd_events_sort_categoriseerd (gboolean, int, FtdParseFunc);
static FtdString       *ftd_events_sort_niet_categoriseerd (gboolean, FtdParseFunc);

/**
 * Sorteert de events in de gegeven lijst en geeft deze terug in een XML gecodeerde string.
 * De sorteercriteria die gebruikt worden staan in ::FtdFilter.veld en ::FtdFilter.asc van ::FtdAppCore.filter.
 *
 * @arg     use_filtered_list       boolean om aan te geven of de volledige lijst gebruikt moet worden of niet
 *
 * @return  De lijst, gesorteerd volgens de criteria, in een nieuwe XML gecodeerde string.
 */
static FtdString *
ftd_events_sort (gboolean use_filtered_list, FtdParseFunc parse_func)
{
    FtdString *res;
    FtdFilter *filter = ftd_eventlist_get_filter(core->eventlist);

    if (filter->categoriseerd == FALSE) {
        FtdString *data;
        char buf[8192];
        char *datetime;
        FtdList *list;
        char *path;
        char *path_tmp;
        FtdString *path_tmp2;
        FtdString *path_tmp3;
        FtdString *path_tmp4;

        res = ftd_string_new ("<Events>\n");

        data = ftd_events_sort_apply_filter(filter);
        res = ftd_string_append (res, ftd_string_value(data));
        ftd_string_free(data);

        snprintf(buf, sizeof(buf), "\t<AantalEvents>%i</AantalEvents>\n", ftd_eventlist_get_count(core->eventlist, TRUE));
        ftd_string_append(res, buf);

        datetime = ftd_string_date(time(NULL));
        snprintf(buf, sizeof(buf), "\t<DateTimeGenerated><![CDATA[%s]]></DateTimeGenerated>\n", datetime);
        g_free(datetime);
        res = ftd_string_append (res, buf);

        snprintf(buf, sizeof(buf), "\t<PrevCheck>%i</PrevCheck>\n", (int) core->config->prevCheck);
        ftd_string_append(res, buf);

        data = ftd_watchlist_print();
        ftd_string_append(res, ftd_string_value(data));
        ftd_string_free(data);

        list = core->config->watchlist;

        // FIXME: moet netter kunnen
        path_tmp = ftd_file_parse_data_dir(NULL);
        path_tmp2 = ftd_string_new(path_tmp);
        path_tmp3 = ftd_string_replace(path_tmp2, " ", "%20");
        path_tmp4 = ftd_string_replace(path_tmp3, "\\", "/");
        path = ftd_string_value(path_tmp4);
        snprintf(buf, sizeof(buf), RANZIGE_JAVASCRIPT_POSTLIST, path, path, path, path, path, path, path, path);
        res = ftd_string_append(res, buf);
        ftd_string_free(path_tmp4);
        ftd_string_free(path_tmp3);
        ftd_string_free(path_tmp2);
        g_free(path_tmp);

        data = ftd_events_sort_niet_categoriseerd (use_filtered_list, parse_func);
        res = ftd_string_append (res, ftd_string_value(data));
        ftd_string_free (data);

        res = ftd_string_append (res, "</Events>\n");
    } else {
        FtdString *sortTags;
        FtdString *data;
        FtdList *list;
        char buf[8192];
        char *datetime;
        int teller;
        char *path;
        char *path_tmp;
        FtdString *path_tmp2;
        FtdString *path_tmp3;
        FtdString *path_tmp4;

        sortTags = ftd_events_sort_apply_filter(filter);

        res = ftd_string_new ("<Events>\n");
        snprintf(buf, sizeof(buf), "\t<AantalEvents>%i</AantalEvents>\n", ftd_eventlist_get_count(core->eventlist, TRUE));
        res = ftd_string_append (res, buf);

        datetime = ftd_string_date(time(NULL));
        snprintf(buf, sizeof(buf), "\t<DateTimeGenerated><![CDATA[%s]]></DateTimeGenerated>\n", datetime);
        g_free(datetime);
        res = ftd_string_append (res, buf);

        snprintf(buf, sizeof(buf), "\t<PrevCheck>%i</PrevCheck>\n", (int) core->config->prevCheck);
        ftd_string_append(res, buf);

        data = ftd_watchlist_print();
        ftd_string_append(res, ftd_string_value(data));
        ftd_string_free(data);

        list = core->config->watchlist;

        // FIXME: moet netter kunnen
        path_tmp = ftd_file_parse_data_dir(NULL);
        path_tmp2 = ftd_string_new(path_tmp);
        path_tmp3 = ftd_string_replace(path_tmp2, " ", "%20");
        path_tmp4 = ftd_string_replace(path_tmp3, "\\", "/");
        path = ftd_string_value(path_tmp4);
        snprintf(buf, sizeof(buf), RANZIGE_JAVASCRIPT_POSTLIST, path, path, path, path, path, path, path, path);
        res = ftd_string_append(res, buf);
        ftd_string_free(path_tmp4);
        ftd_string_free(path_tmp3);
        ftd_string_free(path_tmp2);
        g_free(path_tmp);

        for (teller = 0; teller < 4; teller++) {
            FtdString *data;

            data = ftd_events_sort_categoriseerd(use_filtered_list, teller, parse_func);
            if (data == NULL) {
                continue;
            }

            switch (teller) {
                case 0:
                    res = ftd_string_append (res, "\t<CatEvents catName=\"Beeld\">\n");
                    break;
                case 1:
                    res = ftd_string_append (res, "\t<CatEvents catName=\"Geluid\">\n");
                    break;
                case 2:
                    res = ftd_string_append (res, "\t<CatEvents catName=\"Games\">\n");
                    break;
                case 3:
                    res = ftd_string_append (res, "\t<CatEvents catName=\"Apps\">\n");
                    break;
            }

            res = ftd_string_append (res, ftd_string_value(sortTags));
            res = ftd_string_append (res, ftd_string_value(data));
            ftd_string_free (data);

            res = ftd_string_append (res, "\t</CatEvents>\n");
        }

        ftd_string_free (sortTags);

        res = ftd_string_append (res, "</Events>\n");
    }

    ftd_filter_free_filter(filter);

    return res;
}

/**
 * Past de sortering van de gegevens toe op de data.
 * Deze functie sorteert niet zelf, maar geeft instructie in XML-formaat mee voor de XSLT-verwerker.
 *
 * @return  De nieuwe string met de XML-gecodeerde sorterings-gegevens.
 */
FtdString *
ftd_events_sort_apply_filter (const FtdFilter *filter)
{
    FtdString *res = ftd_string_new("");

    /* Geef aan op welk veld er gesorteerd moet worden */
    switch (filter->veld) {
        case FTDEVENT_SORT_DATUM:
            res = ftd_string_append(res, "\t<SortMode>Stamp</SortMode>\n");
            break;
        case FTDEVENT_SORT_TITEL:
            res = ftd_string_append(res, "\t<SortMode>Title</SortMode>\n");
            break;
        case FTDEVENT_SORT_POSTER:
            res = ftd_string_append(res, "\t<SortMode>Poster</SortMode>\n");
            break;
        case FTDEVENT_SORT_RATING:
            res = ftd_string_append(res, "\t<SortMode>Rating</SortMode>\n");
            break;
        default:
            g_warning("ftd_events_sort_apply_filter(): Onbekend sorteerveld %i\n", filter->veld);
            break;
    }

    if (filter->asc) {
        res = ftd_string_append(res, "\t<SortRichting>ascending</SortRichting>\n");
    } else {
        res = ftd_string_append(res, "\t<SortRichting>descending</SortRichting>\n");
    }

    return res;
}

struct events_sort_data {
    int cat;
    int teller;
    FtdString *res;
    gboolean sorted;
    int count;
    FtdParseFunc parse_func;
};

static gboolean
events_sort_func(gpointer key, gpointer value, gpointer data)
{
    struct events_sort_data *func_data = (struct events_sort_data *) data;
    FtdEvent *event = (FtdEvent *) value;
    FtdString *tekst;

    if (func_data->cat >= 0) {
        if (event->cat != func_data->cat) {    // Controleer of de betreffende posting wel in de goede categorie zit
            return FALSE;
        }
    }

    tekst = ftd_events_sort_print(event, func_data->sorted, func_data->teller, func_data->parse_func);
    func_data->teller++;
    func_data->count++;

    func_data->res = ftd_string_append (func_data->res, ftd_string_value (tekst));

    ftd_string_free (tekst);

    return FALSE;
}

/**
 * Geeft een in XML gecodeerde string terug met alle events uit de lijst, met indeling in de FTD categorieen.
 * Roep deze functie aan voor elke FTD categorie om alle events te krijgen.
 *
 * @arg     eventlist       De lijst met events die omgezet moet worden.
 * @arg     cat             De FTD categorie waarvan de events in de string moeten komen.
 *
 * @return  Een nieuwe XML gecodeerde string met daarin alle events uit de lijst die als FTD categorie cat hebben.
 */
static FtdString *
ftd_events_sort_categoriseerd (gboolean use_filtered_list, int cat, FtdParseFunc parse_func)
{
    struct events_sort_data func_data;
    char *tmp;

    func_data.cat = cat;
    func_data.res = ftd_string_new("");
    func_data.teller = 0;
    func_data.sorted = TRUE;
    func_data.count = 0;
    func_data.parse_func = parse_func;

    ftd_eventlist_foreach(core->eventlist, use_filtered_list, TRUE, events_sort_func, &func_data);

    tmp = g_strdup_printf("\t\t<AantalEvents>%i</AantalEvents>\n", func_data.count);

    func_data.res = ftd_string_append(func_data.res, tmp);

    return func_data.res;
}

/**
 * Geeft een in XML gecodeerde string terug met alle events uit de lijst.
 *
 * @arg     eventlist       De lijst met events die omgezet moet worden.
 *
 * @return  Een nieuwe XML gecodeerde string met daarin alle events uit de lijst.
 */
static FtdString *
ftd_events_sort_niet_categoriseerd (gboolean use_filtered_list, FtdParseFunc parse_func)
{
    struct events_sort_data func_data;

    func_data.cat = -1;
    func_data.res = ftd_string_new("");
    func_data.teller = 0;
    func_data.sorted = FALSE;
    func_data.parse_func = parse_func;

    ftd_eventlist_foreach(core->eventlist, use_filtered_list, TRUE, events_sort_func, &func_data);

    return func_data.res;
}

/**
 * Geeft de gegevens van een event terug in een XML gecodeerde string.
 *
 * @arg     event           Het event waarvan de gegevens in de string moeten komen.
 * @arg     categoriseerd   True indien de uitvoer gecategoriseerd op FTD-categorie weergegeven gaat worden.
 * @arg     pos             De positie van dit event in de uiteindelijke lijst.
 *
 * @return  Een nieuwe XML gecodeerde string met alle gegevens van het gegeven event.
 */
FtdString *
ftd_events_sort_print (FtdEvent *event, gboolean categoriseerd, int pos, FtdParseFunc parse_func)
{
    FtdString *res;
    FtdString *tmp;
    FtdString *url;
    char buf[65535]; // FIXME: Wat is het maximum voor het veld Description ??
    char *datum;
    FtdList *list;

    int max_rating = ftd_config_get()->ratingScale * 10;
    int rating = (event->rating > max_rating) ? max_rating : event->rating;
    float factor = (float) (100.0 / ftd_config_get()->ratingScale);
    rating = rating * factor;

    // FIXME: Deze routine opnieuw schrijven zodat deze van libxml2 functies gebruik maakt

    g_assert(event);

    res = ftd_string_new ("");

    if (categoriseerd) { res = ftd_string_append(res, "\t"); }
    res = ftd_string_append (res, "\t<Event>\n");

    snprintf(buf, sizeof(buf), "\t\t<PostID>%i</PostID>\n", event->postId);
    if (categoriseerd) { res = ftd_string_append(res, "\t"); }
    res = ftd_string_append (res, buf);

    datum = ftd_string_date(event->stamp);
    if (datum != NULL) {
        snprintf(buf, sizeof(buf), "\t\t<Datum>%s</Datum>\n", datum);
        if (categoriseerd) { res = ftd_string_append(res, "\t"); }
        res = ftd_string_append (res, buf);
        g_free (datum);
    }

    snprintf(buf, sizeof(buf), "\t\t<Stamp>%li</Stamp>\n", event->stamp);
    if (categoriseerd) { res = ftd_string_append(res, "\t"); }
    res = ftd_string_append (res, buf);

    snprintf(buf, sizeof(buf), "\t\t<Status>%i</Status>\n", event->status);
    if (categoriseerd) { res = ftd_string_append(res, "\t"); }
    res = ftd_string_append (res, buf);

    // Filename KAN leeg zijn (losse mp3 files)
    if (event->fileName) {
        snprintf(buf, sizeof(buf), "\t\t<FName><![CDATA[%s]]></FName>\n", ftd_string_value(event->fileName));
        if (categoriseerd) { res = ftd_string_append(res, "\t"); }
        res = ftd_string_append (res, buf);
    }

    snprintf(buf, sizeof(buf), "\t\t<Title><![CDATA[%s]]></Title>\n", ftd_string_value(event->title));
    if (categoriseerd) { res = ftd_string_append(res, "\t"); }
    res = ftd_string_append (res, buf);

    tmp = ftd_splitted_list_concat(event->groups);
    snprintf(buf, sizeof(buf), "\t\t<Groups><![CDATA[%s]]></Groups>\n",
             ftd_string_value(tmp));
    ftd_string_free(tmp);
    if (categoriseerd) { res = ftd_string_append(res, "\t"); }
    res = ftd_string_append (res, buf);

    snprintf(buf, sizeof(buf), "\t\t<NumNewsgroups>%i</NumNewsgroups>\n",
            ftd_list_length(event->groups));
    if (categoriseerd) { res = ftd_string_append(res, "\t"); }
    res = ftd_string_append (res, buf);

    list = event->groups;

    while (list) {
        FtdString *groupId = ftd_list_value(list);
        FtdGroup *group;
        char *strippedGroup;

        g_assert(groupId);

        group = ftd_group_by_id(atoi(ftd_string_value(groupId)));
        if (!group) {
            g_warning("ftd_events_sort_print(): nieuwsgroep behorende bij groupId %s onbekend (eventid = %i)!\n", ftd_string_value(groupId), event->postId);
            list = ftd_list_next(list);
            continue;
        }

        strippedGroup = ftd_string_strip_newsgroup(group->groupName);
        snprintf(buf, sizeof(buf), "\t\t<Newsgroups><![CDATA[%s]]></Newsgroups>\n", strippedGroup);
        g_free(strippedGroup);
        if (categoriseerd) { res = ftd_string_append(res, "\t"); }
        res = ftd_string_append (res, buf);
        list = ftd_list_next(list);
    }

    snprintf(buf, sizeof(buf), "\t\t<Poster><![CDATA[%s]]></Poster>\n", ftd_string_value(event->poster));
    if (categoriseerd) { res = ftd_string_append(res, "\t"); }
    res = ftd_string_append (res, buf);

    url = ftd_string_add_http(event->link);
    snprintf(buf, sizeof(buf), "\t\t<Link><![CDATA[%s]]></Link>\n", ftd_string_value(url));
    ftd_string_free(url);
    if (categoriseerd) { res = ftd_string_append(res, "\t"); }
    res = ftd_string_append (res, buf);

    snprintf(buf, sizeof(buf), "\t\t<Rating>%i</Rating>\n", rating);
    if (categoriseerd) { res = ftd_string_append(res, "\t"); }
    res = ftd_string_append (res, buf);

    snprintf(buf, sizeof(buf), "\t\t<Cat>%i</Cat>\n", event->cat);
    if (categoriseerd) { res = ftd_string_append(res, "\t"); }
    res = ftd_string_append (res, buf);

    snprintf(buf, sizeof(buf), "\t\t<SCat>%i</SCat>\n", event->sCat);
    if (categoriseerd) { res = ftd_string_append(res, "\t"); }
    res = ftd_string_append (res, buf);

    tmp = ftd_events_sort_parse_tags(event);
    snprintf(buf, sizeof(buf), "\t\t<TagInfo><![CDATA[%s]]></TagInfo>\n", ftd_string_value(tmp));
    ftd_string_free(tmp);
    if (categoriseerd) { res = ftd_string_append(res, "\t"); }
    res = ftd_string_append (res, buf);

    snprintf(buf, sizeof(buf), "\t\t<Tag><![CDATA[%s]]></Tag>\n", ftd_string_value(event->extra_tag));
    if (categoriseerd) { res = ftd_string_append(res, "\t"); }
    res = ftd_string_append (res, buf);

    snprintf(buf, sizeof(buf), "\t\t<Updated>%i</Updated>\n", (int) event->updated);
    if (categoriseerd) { res = ftd_string_append(res, "\t"); }
    res = ftd_string_append (res, buf);

    snprintf(buf, sizeof(buf), "\t\t<Pos>%i</Pos>\n", pos);
    if (categoriseerd) { res = ftd_string_append(res, "\t"); }
    res = ftd_string_append(res, buf);

    /* Velden uit de event info */
    if (event->announcement) {
        if (parse_func) {
            tmp = parse_func(event->announcement);
        } else {
            tmp = ftd_string_new(ftd_string_value(event->announcement));
        }

        snprintf(buf, sizeof(buf), "\t\t<Ann><![CDATA[%s]]></Ann>\n", ftd_string_value(tmp));
        if (categoriseerd) { res = ftd_string_append(res, "\t"); }
        res = ftd_string_append (res, buf);
        ftd_string_free(tmp);
    }

    if (event->description) {
        if (parse_func) {
            tmp = parse_func(event->description);
        } else {
            tmp = ftd_string_new(ftd_string_value(event->description));
        }

        snprintf(buf, sizeof(buf), "\t\t<Des><![CDATA[%s]]></Des>\n", ftd_string_value(tmp));
        if (categoriseerd) { res = ftd_string_append(res, "\t"); }
        res = ftd_string_append (res, buf);
        ftd_string_free(tmp);
    }

    if (event->sig) {
        if (parse_func) {
            tmp = parse_func(event->sig);
        } else {
            tmp = ftd_string_new(ftd_string_value(event->sig));
        }

        snprintf(buf, sizeof(buf), "\t\t<Sig><![CDATA[%s]]></Sig>\n", ftd_string_value(tmp));
        if (categoriseerd) { res = ftd_string_append(res, "\t"); }
        res = ftd_string_append (res, buf);
        ftd_string_free(tmp);
    }

    snprintf(buf, sizeof(buf), "\t\t<FType>%i</FType>\n", event->fileType);
    if (categoriseerd) { res = ftd_string_append(res, "\t"); }
    res = ftd_string_append (res, buf);

    snprintf(buf, sizeof(buf), "\t\t<Files>%i</Files>\n", event->aantalFiles);
    if (categoriseerd) { res = ftd_string_append(res, "\t"); }
    res = ftd_string_append (res, buf);

    snprintf(buf, sizeof(buf), "\t\t<FStart>%i</FStart>\n", event->fileStart);
    if (categoriseerd) { res = ftd_string_append(res, "\t"); }
    res = ftd_string_append (res, buf);

    snprintf(buf, sizeof(buf), "\t\t<AantalParFiles>%i</AantalParFiles>\n", event->aantalParFiles);
    if (categoriseerd) { res = ftd_string_append(res, "\t"); }
    res = ftd_string_append (res, buf);

    snprintf(buf, sizeof(buf), "\t\t<Kudos>%i</Kudos>\n", event->kudos);
    if (categoriseerd) { res = ftd_string_append(res, "\t"); }
    res = ftd_string_append (res, buf);

    snprintf(buf, sizeof(buf), "\t\t<ParType>%i</ParType>\n", event->parType);
    if (categoriseerd) { res = ftd_string_append(res, "\t"); }
    res = ftd_string_append (res, buf);

    snprintf(buf, sizeof(buf), "\t\t<ParBlockSize>%i</ParBlockSize>\n", event->parBlockSize);
    if (categoriseerd) { res = ftd_string_append(res, "\t"); }
    res = ftd_string_append (res, buf);

    snprintf(buf, sizeof(buf), "\t\t<NumViews>%i</NumViews>\n", event->numViews);
    if (categoriseerd) { res = ftd_string_append(res, "\t"); }
    res = ftd_string_append (res, buf);

    if (event->image) {
        snprintf(buf, sizeof(buf), "\t\t<Img><![CDATA[%s]]></Img>\n", ftd_string_value(event->image));
        if (categoriseerd) { res = ftd_string_append(res, "\t"); }
        res = ftd_string_append (res, buf);
    }

    if (event->mp3Tracks) {
        snprintf(buf, sizeof(buf), "\t\t<MP3>\n");
        if (categoriseerd) { res = ftd_string_append(res, "\t"); }
        res = ftd_string_append (res, buf);

        list = event->mp3Tracks;

        while (list) {
            FtdString *track = ftd_list_value(list);
            g_assert(track);
            snprintf(buf, sizeof(buf), "\t\t\t<Track><![CDATA[%s]]></Track>\n", ftd_string_value(track));
            if (categoriseerd) { res = ftd_string_append(res, "\t"); }
            res = ftd_string_append (res, buf);
            list = ftd_list_next(list);
        }
        snprintf(buf, sizeof(buf), "\t\t</MP3>\n");
        if (categoriseerd) { res = ftd_string_append(res, "\t"); }
        res = ftd_string_append (res, buf);
    }

    /* Forumberichten */
    if (event->forum) {
        tmp = ftd_events_forum_print(event, parse_func);
        if (tmp) {
            res = ftd_string_append(res, ftd_string_value(tmp));
            ftd_string_free(tmp);
        }
    }

    snprintf(buf, sizeof(buf), "\t\t<Locked>%i</Locked>\n", event->locked);
    if (categoriseerd) { res = ftd_string_append(res, "\t"); }
    res = ftd_string_append (res, buf);

    if (event->reason) {
        snprintf(buf, sizeof(buf), "\t\t\t<Reason><![CDATA[%s]]></Reason>\n", ftd_string_value(event->reason));
        if (categoriseerd) { res = ftd_string_append(res, "\t"); }
        res = ftd_string_append (res, buf);
    }

    snprintf(buf, sizeof(buf), "\t\t\t<UpdatedInWatchlist>%i</UpdatedInWatchlist>\n", event->geupdated_in_watchlist);
    if (categoriseerd) { res = ftd_string_append(res, "\t"); }
    res = ftd_string_append (res, buf);

    /* Watchlist */
    snprintf(buf, sizeof(buf), "\t\t<Watchlist>%i</Watchlist>\n", ftd_watchlist_is_in_list(event->postId));
    if (categoriseerd) { res = ftd_string_append(res, "\t"); }
    res = ftd_string_append(res, buf);

    if (categoriseerd) { res = ftd_string_append(res, "\t"); }
    res = ftd_string_append (res, "\t</Event>\n");

    return res;
}

/**
 * Geeft de XML gecodeerde string terug met daarin de gegevens van alle events.
 *
 * @return  Een nieuwe XML gecodeerde string met de gegevens.
 */
FtdString *
ftd_events_sort_total(FtdParseFunc parse_func)
{
    return ftd_events_sort(FALSE, parse_func);
}

/**
 * Geeft de XML gecodeerde string terug met daarin de gegevens van alle gefilterde events.
 *
 * @return  Een nieuwe XML gecodeerde string met de gegevens.
 */
FtdString *
ftd_events_sort_filtered(FtdParseFunc parse_func)
{
    return ftd_events_sort(TRUE, parse_func);
}

/**
 * Geeft een XML gecodeerde string met de tags van het gegeven event.
 *
 * @arg     event       Het event waarvan de tags in de XML geplaatst moeten worden.
 *
 * @return  Een nieuwe string met de tags in XML gecodeerd formaat.
 */
FtdString *
ftd_events_sort_parse_tags(FtdEvent *event)
{
    FtdList *list;
    FtdString *prevTagName = NULL;

    FtdString *ret = ftd_string_new("<TABLE STYLE='font-family: arial; font-size: 11px;'>");

    g_assert(event);

    ret = ftd_string_append(ret, "<TR><TD><B>Categorie :</B></TD><TD>");
    ret = ftd_string_append(ret, ftd_string_category(event->cat));
    ret = ftd_string_append(ret, "</TD></TR>");

    list = event->tags;
    while (list) {
        const FtdTag *tag;
        FtdString *tagname = ftd_list_value(list);

        tag = ftd_tag_find(tagname, event->cat);
        if (tag) {
            if (prevTagName && strcmp(ftd_string_value(prevTagName), ftd_string_value(tag->parent->name)) == 0) {
                ret = ftd_string_append(ret, "<TR><TD></TD><TD>");
            } else {
                ret = ftd_string_append(ret, "<TR><TD><B>");
                ret = ftd_string_append(ret, ftd_string_value(tag->parent->name));
                ret = ftd_string_append(ret, " :</B></TD><TD>");
            }

            ret = ftd_string_append(ret, ftd_string_value(tag->name));
            ret = ftd_string_append(ret, "</TD></TR>");

            prevTagName = tag->parent->name;
        } else {
            ret = ftd_string_append(ret, "<TR><TD><B>Onbekende tag :</B></TD><TD>");
            ret = ftd_string_append(ret, ftd_string_value(tagname));
            ret = ftd_string_append(ret, "</TD></TR>");
        }

        list = ftd_list_next(list);
    }

    ret = ftd_string_append(ret, "<TR><TD><B>Status :</B></TD><TD>");
    ret = ftd_string_append(ret, ftd_string_status(event->status));
    ret = ftd_string_append(ret, "</TD></TR>");

    if (event->link && ftd_string_length(event->link) > 0) {
        FtdString *url = ftd_string_add_http(event->link);
        ret = ftd_string_append(ret, "<TR><TD><B>Weblink :</B></TD><TD><A HREF='iets.html#link");
        ret = ftd_string_append(ret, ftd_string_value(url));
        ret = ftd_string_append(ret, "'>");
        ret = ftd_string_append(ret, ftd_string_value(url));
        ret = ftd_string_append(ret, "</A></TD></TR>");
        ftd_string_free(url);
    }

    if (event->extra_tag && ftd_string_length(event->extra_tag) > 0) {
        ret = ftd_string_append(ret, "<TR><TD><B>Tag :</B></TD><TD>");
        ret = ftd_string_append(ret, ftd_string_value(event->extra_tag));
        ret = ftd_string_append(ret, "</TD></TR>");
    }

    if (event->reason && ftd_string_length(event->reason) > 0) {
        ret = ftd_string_append(ret, "<TR><TD><B>Reden van verwijdering :</B></TD><TD>");
        ret = ftd_string_append(ret, ftd_string_value(event->reason));
        ret = ftd_string_append(ret, "</TD></TR>");
    }

    ret = ftd_string_append(ret, "</TABLE>");

    return ret;
}
