/* ====================================================================
 * 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_mail.h"
#include "ftd_file.h"

/**
 * Stelt een nieuw mail-bericht op
 *
 * @arg     from            De gebruikersnaam van de afzender of ontvanger indien de gebruiker de zender is.
 * @arg     subject         Het onderwerp.
 * @arg     body            Het bericht zelf.
 * @arg     stamp           De timestamp van het bericht.
 *
 * @return  Een nieuwe mailbericht met de gegevens.
 */
FtdMailBericht *
ftd_mail_bericht_new(char *from, char *subject, char *body, time_t stamp)
{
    FtdMailBericht *bericht;

    if ((!from) || (!subject) || (!body)) {
        return NULL;
    }

    bericht = g_malloc(sizeof(FtdMailBericht));
    memset(bericht, 0, sizeof(FtdMailBericht));

    bericht->from = ftd_string_new(from);
    bericht->subject = ftd_string_new(subject);
    bericht->body = ftd_string_new(body);
    bericht->stamp = stamp;

    return bericht;
}

/**
 * Geeft een mailbericht vrij.
 *
 * @arg     bericht         Het vrij te geven bericht.
 */
void
ftd_mail_bericht_free(FtdMailBericht *bericht)
{
    g_assert(bericht);
    ftd_string_free(bericht->from);
    ftd_string_free(bericht->subject);
    ftd_string_free(bericht->body);
    g_free(bericht);
}

/**
 * Geeft een lijst met mails vrij.
 * De lijst zelf wordt ook vrijgegeven.
 *
 * @arg     mail_list       Een lijst met ::FtdMailBericht pointers die brijgegeven moeten worden.
 */
void
ftd_mail_free(FtdList *mail_list)
{
    FtdList *list;

    list = mail_list;
    while (list) {
        FtdMailBericht *bericht = ftd_list_value(list);
        g_assert(bericht);

        ftd_mail_bericht_free(bericht);
        list = ftd_list_next(list);
    }

    ftd_list_free(mail_list);
}

/**
 * Laadr de bekende mailberichten.
 */
void
ftd_mail_load(void)
{
    FtdString *data;

    g_assert(core);

    data = ftd_file_load(MAIL_FILE, FALSE);
    if (data == NULL) {
        /* Bestand bestond nog niet, aanmaken */
        ftd_mail_save();
        return;
    }

    if (core->mail) {
        ftd_mail_free(core->mail);
    }

    core->mail = ftd_mail_parse(data);

    ftd_string_free(data);
}

/**
 * Slaat de mailberichten op.
 */
int
ftd_mail_save(void)
{
    FtdString   *xmlData = ftd_string_new("");
    FtdList     *list;
    int          retval;

    xmlData = ftd_string_append(xmlData, "<Mail>\n");
    list = core->mail;
    while (list) {
        FtdMailBericht *bericht = ftd_list_value(list);
        FtdString *tekst;
        g_assert(bericht);

        tekst = ftd_mail_print(bericht, FALSE, NULL);

        xmlData = ftd_string_append(xmlData, ftd_string_value(tekst));
        ftd_string_free(tekst);
        list = ftd_list_next(list);
    }
    xmlData = ftd_string_append(xmlData, "</Mail>\n");

    retval = ftd_file_save(MAIL_FILE, xmlData, FALSE);
    ftd_string_free(xmlData);

    return retval;
}

/**
 * Checkt op de FTD server voor nieuwe mail.
 *
 * @arg     mailWaiting         Dit wordt true als er nieuwe mail beschikbaar is.
 * @arg     errmsg              Een eventueel foutbericht van de server wordt hier in geplaatst.
 *
 * @return  Een fout-code die aangeeeft of het checken voor mail succesvol was verlopen.
 */
FtdErrorCode
ftd_mail_check(gboolean *mailWaiting, char **errmsg)
{
    FtdList         *params = NULL;
    FtdString       *uitvoer;
    FtdErrorCode     retval;

    g_assert(mailWaiting);

    params = ftd_list_append(params, ftd_http_parameter_new("mode", "check"));
    retval = ftd_http_curl_execute(FTD_URL_MAIL, 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));
        } else {
            *errmsg = NULL;
        }

        ftd_string_free(uitvoer);

        return retval;
    }

    /* Op dit punt moeten we een string hebben met de waarde 'Y' of 'N'
     * elke andere waarde is ongeldig */
    if (strncmp(ftd_string_value(uitvoer), "Y", 1) == 0) {
        *mailWaiting = TRUE;
        ftd_string_free( uitvoer );
        return ERROR_NONE;
    }

    if (strncmp(ftd_string_value(uitvoer), "N", 1) == 0) {
        *mailWaiting = FALSE;
        ftd_string_free( uitvoer );
        return ERROR_NONE;
    }

    /* Hier mogen we niet geraken */

    ftd_string_free( uitvoer );
    *errmsg = NULL;

    return ERROR_RES;
}

/**
 * Haalt de mail van de FTd server op.
 *
 * @arg     numNewMail          Hierin wordt het aantal nieuwe berichten geplaatst.
 * @arg     errmsg              Een eventueel foutbericht van de server wordt hier in geplaatst.
 *
 * @return  Een fout-code die aangeeft of het binnenhalen van de nieuwe mail succesvol was.
 */
FtdErrorCode
ftd_mail_fetch(int *numNewMail, char **errmsg)
{
    FtdList         *params = NULL;
    FtdString       *uitvoer;
    FtdErrorCode     retval;
    FtdList         *listNieuw;

    g_assert(numNewMail);

    params = ftd_list_append(params, ftd_http_parameter_new("mode", "read"));
    retval = ftd_http_curl_execute(FTD_URL_MAIL, 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));
        } else {
            *errmsg = NULL;
        }

        ftd_string_free(uitvoer);

        return retval;
    }

    listNieuw = ftd_mail_parse(uitvoer);

    if (listNieuw == NULL) {
        ftd_string_free( uitvoer );
        *errmsg = NULL;
        return ERROR_PARSE;
    }

    ftd_string_free( uitvoer );
    core->mail = ftd_mail_merge(core->mail, listNieuw);
    *numNewMail = ftd_list_length(listNieuw);
    ftd_mail_save();
    ftd_mail_load();

    return ERROR_NONE;
}

/**
 * Voegt een lijst met nieuwe mails bij een andere lijst.
 *
 * @arg     origLijst           De lijst met ::FtdMailBericht pointers die de originele mails zijn.
 * @arg     nieuwLijst          De lijst met ::FtdMailBericht pointers die bij de andere lijst gevoegd moeten worden.
 *
 * @return  De nieuwe lijst met ::FtdMailBericht pointers met alle mails uit de twee lijsten.
 */
FtdList *
ftd_mail_merge(FtdList *origList, FtdList *nieuwList)
{
    FtdList *res = NULL;

    while (origList) {
        res = ftd_list_append(res, ftd_list_value(origList));
        origList = ftd_list_next(origList);
    }

    while (nieuwList) {
        res = ftd_list_append(res, ftd_list_value(nieuwList));
        nieuwList = ftd_list_next(nieuwList);
    }

    return res;
}

/**
 * Geeft een mailbericht weer als XML gecodeerde string.
 *
 * @arg     bericht         Het bericht dat omgezet moet worden.
 * @arg     parseBody       True indien het bericht zelf geparsed moet worden om het bruikbaar te maken voor HTML uitvoer.
 *
 * @return  Een nieuwe string met de XML gecodeerde gegevens van het bericht.
 */
FtdString *
ftd_mail_print(FtdMailBericht *bericht, gboolean parseBody, FtdParseFunc parse_func)
{
    FtdString *uitvoer;
    char tmp[64];
    char *datum;

    g_assert(core);
    g_assert(bericht);

    uitvoer = ftd_string_new("");
    uitvoer = ftd_string_append(uitvoer, "\t<Event Code=\"");
    snprintf(tmp, sizeof(tmp), "%i", bericht->type);
    uitvoer = ftd_string_append(uitvoer, tmp);
    uitvoer = ftd_string_append(uitvoer, "\">\n");

    uitvoer = ftd_string_append(uitvoer, "\t\t<From><![CDATA[");
    uitvoer = ftd_string_append(uitvoer, bericht->from ? ftd_string_value(bericht->from) : "");
    uitvoer = ftd_string_append(uitvoer, "]]></From>\n");

    uitvoer = ftd_string_append(uitvoer, "\t\t<Subject><![CDATA[");
    uitvoer = ftd_string_append(uitvoer, bericht->subject ? ftd_string_value(bericht->subject) : "");
    uitvoer = ftd_string_append(uitvoer, "]]></Subject>\n");

    uitvoer = ftd_string_append(uitvoer, "\t\t<Body><![CDATA[");
    if (parse_func) {
        FtdString *parsed_tekst = parse_func(bericht->body);
        uitvoer = ftd_string_append(uitvoer, ftd_string_value(parsed_tekst));
        ftd_string_free(parsed_tekst);
    } else {
        uitvoer = ftd_string_append(uitvoer, bericht->body ? ftd_string_value(bericht->body) : "");
    }
    uitvoer = ftd_string_append(uitvoer, "]]></Body>\n");

    uitvoer = ftd_string_append(uitvoer, "\t\t<Stamp>");
    snprintf(tmp, sizeof(tmp), "%i", (unsigned int) bericht->stamp);
    uitvoer = ftd_string_append(uitvoer, tmp);
    uitvoer = ftd_string_append(uitvoer, "</Stamp>\n");

    uitvoer = ftd_string_append(uitvoer, "\t\t<DateTime>");
    datum = ftd_string_date(bericht->stamp);
    snprintf(tmp, sizeof(tmp), "%s", datum);
    g_free(datum);
    uitvoer = ftd_string_append(uitvoer, tmp);
    uitvoer = ftd_string_append(uitvoer, "</DateTime>\n");

    uitvoer = ftd_string_append(uitvoer, "\t</Event>\n");

    return uitvoer;
}

/**
 * Verstuurt een nieuwe mail.
 *
 * @arg     bericht         Het te versturen bericht. De ontvanger staat in ::FtdMailBericht.from.
 * @arg     errmsg          Een eventueel foutbericht van de server wordt hier in geplaatst.
 *
 * @return  Een fout-code die aangeeft of het versturen van de mail succesvol was.
 */
FtdErrorCode
ftd_mail_post(FtdMailBericht *bericht, char **errmsg)
{
    FtdList         *params = NULL;
    FtdErrorCode     retval;
    FtdString       *uitvoer;

    params = ftd_list_append(params, ftd_http_parameter_new("mode", "write"));
    params = ftd_list_append(params, ftd_http_parameter_new("to", ftd_string_value(bericht->from)));
    params = ftd_list_append(params, ftd_http_parameter_new("s", ftd_string_value(bericht->subject)));
    params = ftd_list_append(params, ftd_http_parameter_new("b", ftd_string_value(bericht->body)));
    retval = ftd_http_curl_execute(FTD_URL_MAIL, 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));
        } else {
            *errmsg = NULL;
        }

        ftd_string_free(uitvoer);

        return retval;
    }

    if (strstr(ftd_string_value(uitvoer), "SENT")) {
        FtdString *body = ftd_string_replace(bericht->body, "\n", "\r\n<BR />");
        bericht->stamp = time(NULL);
        bericht->type = MAIL_TYPE_VERZONDEN;
        ftd_string_free(bericht->body);
        bericht->body = body;
        core->mail = ftd_list_append(core->mail, bericht);
        ftd_mail_save();
        ftd_string_free(uitvoer);
        return 0;
    }

    if (!strncmp(ftd_string_value(uitvoer), "NOTFOUND", 8)) {
        ftd_string_free(uitvoer);
        *errmsg = NULL;
        return -1;
    }

    ftd_string_free(uitvoer);

    *errmsg = NULL;

    return ERROR_RES;
}

/**
 * Geeft alle mail terug.
 *
 * @return  De lijst met ::FtdMailBericht pointers naar alle mailberichten.
 */
const FtdList *
ftd_mail_get(void)
{
    g_assert(core);
    return core->mail;
}

/**
 * Verwijdert een mailbericht.
 *
 * @arg     bericht         Het te verwijderen mailbericht.
 */
void
ftd_mail_delete(FtdMailBericht *bericht)
{
    g_assert (core);
    g_assert (core->mail);
    ftd_mail_bericht_free(bericht);
    core->mail = ftd_list_remove(core->mail, bericht);

    ftd_mail_save();
}

/**
 * Geeft het aantal mailberichten terug.
 *
 * @return  Het aantal mailberichten.
 */
int
ftd_mail_get_num_messages(void)
{
    g_assert (core);
    // g_assert(core->mail) is hier niet nodig aangezien deze lijst leeg kan zijn

    return ftd_list_length(core->mail);
}
