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

static FtdString *ftd_events_forum_print_reactie(FtdEventForumReactie *reactie, FtdParseFunc parse_func);

/**
 * Maakt een nieuw forum aan.
 *
 * @return  Een nieuw forum.
 */
FtdEventForum *
ftd_events_forum_new()
{
    FtdEventForum *forum = g_malloc0(sizeof(FtdEventForum));

    return forum;
}

/**
 * Geeft een forum en alle reacties vrij.
 *
 * @arg     forum       Het vrij te geven forum.
 */
void
ftd_events_forum_free(FtdEventForum *forum)
{
    FtdList *list;

    g_assert(forum);

    list = forum->forum_reacties;
    while (list) {
        FtdEventForumReactie *reactie = ftd_list_value(list);
        ftd_events_forum_reactie_free(reactie);
        list = ftd_list_next(list);
    }

    ftd_list_free(forum->forum_reacties);
    g_free (forum);
}

/**
 * Maakt een nieuwe forum-reactie aan.
 *
 * @return  De nieuwe forum-reactie.
 */
FtdEventForumReactie *
ftd_events_forum_reactie_new()
{
    FtdEventForumReactie *reactie;

    reactie = (FtdEventForumReactie *) g_malloc0(sizeof(FtdEventForumReactie));

    return reactie;
}

/**
 * Geeft een forum-reactie vrij.
 *
 * @arg     reactie     De vrij te geven reactie.
 */
void
ftd_events_forum_reactie_free(FtdEventForumReactie *reactie)
{
    if (reactie->author) {
        ftd_string_free(reactie->author);
    }

    if (reactie->body) {
        ftd_string_free(reactie->body);
    }

    if (reactie->avatar) {
        ftd_string_free(reactie->avatar);
    }

    g_free (reactie);
}

struct _forum_fetch_data
{
    int eventid;
    time_t lastCheck;

    char *errmsg;
    FtdErrorCode retval;

    void (*cb) (FtdErrorCode, int, time_t, char *, gpointer);
    gpointer data;
};

static gboolean
forum_exec_cb(gpointer data)
{
    struct _forum_fetch_data *fetch_data = (struct _forum_fetch_data *) data;

    fetch_data->cb(fetch_data->retval, fetch_data->eventid, fetch_data->lastCheck, fetch_data->errmsg, fetch_data->data);
    g_free(fetch_data);

    return FALSE;
}

static gpointer
forum_fetch_func(gpointer data)
{
    struct _forum_fetch_data *fetch_data = (struct _forum_fetch_data *) data;

    fetch_data->retval = ftd_events_forum_fetch(fetch_data->eventid, fetch_data->lastCheck, &fetch_data->errmsg);

    g_idle_add(forum_exec_cb, data);

    return NULL;
}

/**
 * Haalt het forum van een event op van de FTD servers in een aparte thread.
 *
 * @arg     eventid     Het FTD-nummer van het event waarvan het forum opgehaald moet worden.
 * @arg     lastCheck   De timestamp van de laatste keer dat het forum geupdate is.
 * @arg
 *
 * @return  Een fout-code die aangaf of het forum succesvol opgehaald werd.
 */
void
ftd_events_forum_fetch_async(int eventid, time_t lastCheck, void (*cb) (FtdErrorCode, int, time_t, char *, gpointer), gpointer data)
{
    GThread *thread;
    GError *err = NULL;
    struct _forum_fetch_data *fetch_data;

    g_assert(cb);

    fetch_data = g_malloc(sizeof(struct _forum_fetch_data));

    fetch_data->eventid = eventid;
    fetch_data->lastCheck = lastCheck;
    fetch_data->cb = cb;
    fetch_data->data = data;

    thread = g_thread_create(forum_fetch_func, fetch_data, FALSE, &err);
    if (!thread) {
        cb(ERROR_UNKNOWN, eventid, lastCheck, err->message, data);
    }
}

/**
 * Haalt het forum van een event op van de FTD servers.
 *
 * @arg     eventid     Het FTD-nummer van het event waarvan het forum opgehaald moet worden.
 * @arg     lastCheck   De timestamp van de laatste keer dat het forum geupdate is.
 * @arg     errmsg      Hier wordt een eventuele foutmelding van de server in geplaatst.
 *
 * @return  Een fout-code die aangaf of het forum succesvol opgehaald werd.
 */
FtdErrorCode
ftd_events_forum_fetch(int eventid, time_t lastCheck, char **errmsg)
{
    FtdList     *params = NULL;
    char         tmp[12];
    FtdErrorCode retval;
    FtdString   *uitvoer;
    FtdEvent    *event;

    *errmsg = NULL;

    event = ftd_eventlist_lookup_id(core->eventlist, eventid);
    if (!event) {
        g_print(__FILE__ ":%i postid = %i\n", eventid);
        return ERROR_ORIGEVENT;
    }

    snprintf(tmp, sizeof(tmp), "%i", eventid);
    params = ftd_list_append(params, ftd_http_parameter_new("id", tmp));
    snprintf(tmp, sizeof(tmp), "%i", (unsigned int) lastCheck);
    params = ftd_list_append(params, ftd_http_parameter_new("lastcheck", tmp));

    retval = ftd_http_curl_execute(FTD_URL_POSTS_FORUM, params, TRUE, &uitvoer, TRUE, NULL, TRUE);

    ftd_http_parameter_free_all(params);

    if (retval != ERROR_NONE) {
        if (retval == ERROR_MSG) {
            *errmsg = g_strdup(ftd_string_value(uitvoer));
        }

        ftd_string_free(uitvoer);
        ftd_event_free(event);

        return retval;
    }

    if (ftd_events_forum_parse(uitvoer, event) != 0) {
        ftd_event_free(event);
        return ERROR_PARSE;
    }

    ftd_eventlist_add_or_replace_event(core->eventlist, event);
    ftd_event_free(event);

    return ERROR_NONE;
}

/**
 * Voegt een bericht toe aan het forum van een event.
 *
 * @arg     body            Het toe te voegen bericht.
 * @arg     postid          Het FTD-nummer van het event waar het bericht toegevoegd moet worden.
 * @arg     message_data    Ongebruikt.
 * @arg     errmsg          Hier wordt een eventuele foutmelding van de server in meegegeven.
 *
 * @return  Een fout-code die aangeeft of het bericht succesvol is toegevoegd of niet.
 */
FtdErrorCode
ftd_events_forum_post(gchar *body, int postid, gpointer message_data, char **errmsg)
{
    FtdList     *params = NULL;
    char         tmp[12];
    FtdErrorCode retval;
    FtdString   *uitvoer = NULL;
    FtdString   *encoded_body, *encoded_body2;

    *errmsg = NULL;

    params = ftd_list_append(params, ftd_http_parameter_new("m", "add"));
    encoded_body = ftd_string_new(body);
    encoded_body2 = ftd_string_replace(encoded_body, "\n", "\r\n");

    params = ftd_list_append(params, ftd_http_parameter_new("b", ftd_string_value(encoded_body2)));
    snprintf(tmp, sizeof(tmp), "%i", postid);
    params = ftd_list_append(params, ftd_http_parameter_new("s", tmp));

    retval = ftd_http_curl_execute(FTD_URL_FORUM, params, TRUE, &uitvoer, TRUE, NULL, TRUE);

    ftd_http_parameter_free_all(params);

    ftd_string_free(encoded_body);
    ftd_string_free(encoded_body2);

    if (retval != ERROR_NONE) {
        if (retval == ERROR_MSG) {
            *errmsg = g_strdup(ftd_string_value(uitvoer));
        }

        if( uitvoer ) {
            ftd_string_free(uitvoer);
        }

        return retval;
    }

    if( uitvoer ) {
        ftd_string_free( uitvoer );
    }

    return ERROR_NONE;
}

/**
 * Geeft een string terug met daarin het forum van het gegeven event in XML gecodeerd.
 *
 * @arg     event       Het event waarvan het forum gecodeerd moet worden.
 *
 * @return  De XML-codering van het forum.
 */
FtdString *
ftd_events_forum_print(FtdEvent *event, FtdParseFunc parse_func)
{
    FtdString *res = ftd_string_new("");
    char tmp[1024];
    FtdList *list;

    g_assert(event);
    g_assert(event->forum);

    list = event->forum->forum_reacties;
    while (list) {
        FtdEventForumReactie *reactie = ftd_list_value(list);
        FtdString *tmp = ftd_events_forum_print_reactie(reactie, parse_func);
        if (!tmp) {
            continue;
        }

        res = ftd_string_append(res, ftd_string_value(tmp));
        ftd_string_free(tmp);

        list = ftd_list_next(list);
    }

    sprintf(tmp, "\t\t<NumReacties>%i</NumReacties>\n", ftd_list_length(event->forum->forum_reacties));
    res = ftd_string_append(res, tmp);

    return res;
}

/**
 * Geeft de lengte van de langste string in een forum reactie terug.
 *
 * @arg     reactie         De reactie die bekeken moet worden.
 *
 * @return  De lengte van de langste string in de reactie.
 */
int
ftd_events_forum_get_highest_length(FtdEventForumReactie *reactie)
{
    unsigned int res = 0;

    g_assert(reactie);

    res = ftd_string_length(reactie->author);
    if (res < ftd_string_length(reactie->body)) {
        res = ftd_string_length(reactie->body);
    }

    return res;
}

/**
 * Geeft een forum reacie terug in een string in XML gecodeerde vorm.
 *
 * @arg     reactie         De reactie die in XML omgezet moet worden.
 *
 * @return  De reactie gecodeerd in XML.
 */
static FtdString *
ftd_events_forum_print_reactie(FtdEventForumReactie *reactie, FtdParseFunc parse_func)
{
    FtdString *res;
    FtdString *parsedBericht;
    char *tmp;
    unsigned int len;
    char *buf;

    if (!reactie) {
        return NULL;
    }

    len = ftd_events_forum_get_highest_length(reactie);

    if (parse_func) {
        parsedBericht = parse_func(reactie->body);
    } else {
        parsedBericht = ftd_string_new(ftd_string_value(reactie->body));
    }

    if (len < ftd_string_length(parsedBericht)) {
        len = ftd_string_length(parsedBericht);
    }

    len += 100;

    buf = (char *) g_malloc(len);

    res = ftd_string_new("");
    res = ftd_string_append(res, "\t\t<Reactie>\n");

    snprintf(buf, len, "\t\t\t<MessID>%i</MessID>\n", reactie->messageId);
    res = ftd_string_append(res, buf);

    snprintf(buf, len, "\t\t\t<Kudos>%i</Kudos>\n", reactie->kudos);
    res = ftd_string_append(res, buf);

    snprintf(buf, len, "\t\t\t<Author><![CDATA[%s]]></Author>\n", ftd_string_value(reactie->author));
    res = ftd_string_append(res, buf);

    snprintf(buf, len, "\t\t\t<Body><![CDATA[%s]]></Body>\n", ftd_string_value(parsedBericht));
    res = ftd_string_append(res, buf);
    ftd_string_free(parsedBericht);

    snprintf(buf, len, "\t\t\t<Stamp>%i</Stamp>\n", (unsigned int) reactie->stamp);
    res = ftd_string_append(res, buf);

    if (reactie->stamp > 0) {
        tmp = ftd_string_date(reactie->stamp);
        snprintf(buf, len, "\t\t\t<Datum><![CDATA[%s]]></Datum>\n", tmp);
        res = ftd_string_append(res, buf);
        g_free(tmp);
    }

    if (reactie->lastEdited > 0) {
        tmp = ftd_string_date(reactie->lastEdited);
        snprintf(buf, len, "\t\t\t<Edit><![CDATA[%s]]></Edit>\n", tmp);
        res = ftd_string_append(res, buf);
        g_free(tmp);
    }

    snprintf(buf, len, "\t\t\t<Avatar><![CDATA[%s]]></Avatar>\n", ftd_string_value(reactie->avatar));
    res = ftd_string_append(res, buf);

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

    g_free(buf);

    return res;
}
