/* ====================================================================
 * 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_category.h"

static void
init_func(gpointer data, gpointer user_data)
{
    FtdFilter *filter = (FtdFilter *) data;
    int cat = GPOINTER_TO_INT(user_data);

    if(filter->cat == cat) {
        FtdCategory *category = g_malloc0(sizeof(FtdCategory));
        if(filter->filterNaam) {
            category->name = ftd_string_new(ftd_string_value(filter->filterNaam));
        } else {
            category->name = ftd_string_new("");
        }

        category->cat = cat;

        category->filter = ftd_filter_duplicate(filter);

        core->categories = ftd_list_append(core->categories, category);
    }
}

// Important note: this method must be able to be called a second or third time
/**
 * Initialiseert de categorieen.
 * Deze functie wordt aangeroepen vanuit ::ftd_app_core_init.
 */
void
ftd_categories_init(void)
{
    FtdCategory *category;
    FtdList *list;
    FtdFilter *filter;

    g_assert (core);
    g_assert (core->filterlist);

    if (core->categories) {
        ftd_categories_free();
    }

    filter = ftd_filter_new_filter();

    category = g_malloc0(sizeof(FtdCategory));
    category->name = ftd_string_new("Beeld");
    category->cat = 0;
    category->header = TRUE;
    category->aantalPostings = 0;
    category->filter = ftd_filter_new_filter();
    category->filter->cat = 0;

    core->categories = ftd_list_append(core->categories, category);

    ftd_filterlist_foreach(core->filterlist, TRUE, init_func, GINT_TO_POINTER(0));

    category = g_malloc0(sizeof(FtdCategory));
    category->name = ftd_string_new("Geluid");
    category->cat = 1;
    category->header = TRUE;
    category->aantalPostings = 0;
    category->filter = ftd_filter_new_filter();
    category->filter->cat = 1;

    core->categories = ftd_list_append(core->categories, category);

    ftd_filterlist_foreach(core->filterlist, TRUE, init_func, GINT_TO_POINTER(1));

    category = g_malloc0(sizeof(FtdCategory));
    category->name = ftd_string_new("Spelletjes");
    category->cat = 2;
    category->header = TRUE;
    category->aantalPostings = 0;
    category->filter = ftd_filter_new_filter();
    category->filter->cat = 2;

    core->categories = ftd_list_append(core->categories, category);

    ftd_filterlist_foreach(core->filterlist, TRUE, init_func, GINT_TO_POINTER(2));

    category = g_malloc0(sizeof(FtdCategory));
    category->name = ftd_string_new("Applicaties");
    category->cat = 3;
    category->header = TRUE;
    category->aantalPostings = 0;
    category->filter = ftd_filter_new_filter();
    category->filter->cat = 3;

    core->categories = ftd_list_append(core->categories, category);

    ftd_filterlist_foreach(core->filterlist, TRUE, init_func, GINT_TO_POINTER(3));

    ftd_filter_free_filter(filter);
}

/**
 * Ruimt alle categorieen op.
 * Deze functie wordt aangeroepen vanuit ::ftd_app_core_cleanup.
 */
void
ftd_categories_free(void)
{
    FtdList *list;

    g_assert(core);
    g_assert(core->categories);

    list = core->categories;
    while (list) {
        FtdCategory *category = ftd_list_value(list);
        g_assert(category);

        ftd_string_free(category->name);
        if(category->filter) {
            ftd_filter_free_filter(category->filter);
        }
        g_free(category);
        list = ftd_list_next(list);
    }

    ftd_list_free (core->categories);
    core->categories = NULL;
}

/**
 * Vraagt de hoofd-categorie op.
 * Alle categorieen die onder een bepaalde FTD-categorie vallen hebben als ouder een en dezelfde hoofd-categorie.
 * Onder laatstgenoemde vallen alle events van die FTD-categorie.
 * Geef het resultaat niet vrij!
 *
 * @arg     cat         De FTD-categorie waarvan de hoofd-categorie gezocht wordt.
 *
 * @return  De gezochte hoofd-categorie.
 */
FtdCategory *
ftd_category_get_parent(int cat)
{
    FtdList *list;

    g_assert(core);
    g_assert(core->categories);

    list = core->categories;

    while (list) {
        FtdCategory *category = ftd_list_value(list);
        g_assert(category);

        if (category->cat == cat) {
            return category;
        }
        list = ftd_list_next(list);
    }

    return NULL;
}

/**
 * Zet het aantal events in elke categorie op 0.
 */
void
ftd_categories_reset_counters(void)
{
    FtdList *list;

    g_assert(core);
    g_assert(core->categories);

    list = core->categories;

    while (list) {
        FtdCategory *category = ftd_list_value(list);
        category->aantalPostings = 0;
        list = ftd_list_next(list);
    }
}

/**
 * Verhoogt het aantal events in de categorieen behorende bij de gegeven FTD-categorie en tags.
 * Elke categorie waarbinnen een event met deze tags en cat zou vallen krijgt een hoger aantal events,
 *
 * @arg     event       Pointer naar een event
 *
 * @see	::FtdTag.code
 */
void
ftd_category_update(const FtdEvent *event)
{
    // Zoek alle categorien die bij dit event hoort en verhoog het tellertje
    FtdList *list;

    g_assert(core);
    g_assert(core->categories);

    list = core->categories;

    while (list) {
        FtdCategory *category = ftd_list_value(list);
        g_assert(category);

        if (category->filter) {
            if (ftd_filter_accepts(category->filter, event, TRUE)) {
                category->aantalPostings++;
            }
        }

        list = ftd_list_next(list);
    }
}

/**
 * Vraagt alle categorieen op.
 * Geef de categorieen in het resultaat niet vrij!
 *
 * @return  De lijst met alle categorieen.
 */
FtdCategoryList *
ftd_categories_get(void)
{
    return core->categories;
}

// De inhoud van de teruggegeven lijst is FtdCategory-pointers
/**
 * Zoekt de categorieen waaronder een event valt.
 * Geef de categorieen in het resultaat niet vrij!
 * Geef alleen de lijst zelf vrij met ftd_list_free()
 *
 * @arg     event       Het event waarbij de categorieen gezocht worden.
 *
 * @return  Een lijst met ::FtdCategory pointers naar de gezochte categorieen.
 */
FtdList *
ftd_category_find(const FtdEvent *event)
{
    // Zoek de categorieen en geef deze terug
    FtdList *list;
    FtdList *res = NULL;

    g_assert(core);
    g_assert(core->categories);

    list = core->categories;

    while (list) {
        FtdCategory *category = ftd_list_value(list);
        g_assert(category);

        if (ftd_filter_accepts(category->filter, event, FALSE)) {
            res = ftd_list_append(res, category);
        }

        list = ftd_list_next(list);
    }

    return res;
}

/**
 * Geeft gegeven een categorie en sub-categorie de naam van die subcategorie terug.
 *
 * @arg		cat	De FTD-categorie
 * @arg		scat	De sub-categorie
 *
 * @return	De naam van de gezochte subcategorie.
 */
const char *
ftd_category_get_scat_name(int cat, int sCat)
{
    switch (cat) {
        case 0:
            switch (sCat) {
                case 0:
                    return "DivX";
                case 1:
                    return "WMV";
                case 2:
                    return "MPG";
                case 3:
                    return "DVD";
                case 4:
                    return "HDTV";
                case 5:
                    return "IMG";
            }

            break;

        case 1:
            switch (sCat) {
                case 0:
                    return "MP3";
                case 1:
                    return "WMA";
                case 2:
                    return "WAV";
                case 3:
                    return "OGG";
                case 4:
                    return "Lossless";
            }

            break;

        case 2:
            switch(sCat) {
                case 0:
                    return "Windows";
                case 1:
                    return "Macintosh";
                case 2:
                    return "Linux";
                case 3:
                    return "PSX";
                case 4:
                    return "PS2";
                case 5:
                    return "PSP";
                case 6:
                    return "XBox";
                case 7:
                    return "Dreamcast";
                case 8:
                    return "GBA";
                case 9:
                    return "Gamecube";
            }

            break;

        case 3:
            switch (sCat) {
                case 0:
                    return "Windows";
                case 1:
                    return "Macintosh";
                case 2:
                    return "Linux";
                case 3:
                    return "OS2";
                case 4:
                    return "PDA";
                case 5:
                    return "Navigatie";
            }

            break;
    }

    return "";
}
