/* ====================================================================
 * 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 <stdlib.h>
#include <pcre.h>

#include "ftd4linux.h"
#include "ftd_gui_parse.h"

/**
 * De vervangingen om van tags in FTD-teksten HTML-equivalenten te maken.
 */
static FtdParseTags tags[100];

/**
 * Initialiseert de parser.
 */
void
ftd_gui_parse_init(void)
{
    char *tekst, *datadir;

    memset(tags, 0, sizeof(tags));

    // Let op dat alle tags in hoofdletters vermeld moeten worden!
    tags[0].bron = ftd_string_new("[B]");
    tags[0].doel = ftd_string_new("<B>");

    tags[1].bron = ftd_string_new("[I]");
    tags[1].doel = ftd_string_new("<I>");

    tags[2].bron = ftd_string_new("[U]");
    tags[2].doel = ftd_string_new("<U>");

    tags[3].bron = ftd_string_new("[QUOTE]");
    tags[3].doel = ftd_string_new("<BLOCKQUOTE><FONT COLOR='#440000'>");

    tags[4].bron = ftd_string_new("[FTD]");
    tags[4].doel = ftd_string_new("[FTD]"); // FIXME: testpostings nodig!

    tags[5].bron = ftd_string_new("[/B]");
    tags[5].doel = ftd_string_new("</B>");

    tags[6].bron = ftd_string_new("[/I]");
    tags[6].doel = ftd_string_new("</I>");

    tags[7].bron = ftd_string_new("[/U]");
    tags[7].doel = ftd_string_new("</U>");

    tags[8].bron = ftd_string_new("[/QUOTE]");
    tags[8].doel = ftd_string_new("</FONT></BLOCKQUOTE>");

    tags[9].bron = ftd_string_new("[/FTD]");
    tags[9].doel = ftd_string_new("[/FTD]"); // FIXME

    tags[10].bron = ftd_string_new(":D");
    datadir = ftd_file_parse_data_dir("/emoticons/biggrin.gif");
    tekst = g_strdup_printf("%sfile://%s%s", "<IMG SRC='", datadir, "' BORDER='0'>");
    tags[10].doel = ftd_string_new(tekst);
    g_free(tekst);
    g_free(datadir);

    tags[11].bron = ftd_string_new("*D");
    datadir = ftd_file_parse_data_dir("/emoticons/shiny.gif");
    tekst = g_strdup_printf("%sfile://%s%s", "<IMG SRC='", datadir, "' BORDER='0'>");
    tags[11].doel = ftd_string_new(tekst);
    g_free(tekst);
    g_free(datadir);

    tags[12].bron = ftd_string_new(":?");
    datadir = ftd_file_parse_data_dir("/emoticons/confused.gif");
    tekst = g_strdup_printf("%sfile://%s%s", "<IMG SRC='", datadir, "' BORDER='0'>");
    tags[12].doel = ftd_string_new(tekst);
    g_free(tekst);
    g_free(datadir);

    tags[13].bron = ftd_string_new(":+");
    datadir = ftd_file_parse_data_dir("/emoticons/clown.gif");
    tekst = g_strdup_printf("%sfile://%s%s", "<IMG SRC='", datadir, "' BORDER='0'>");
    tags[13].doel = ftd_string_new(tekst);
    g_free(tekst);
    g_free(datadir);

    tags[14].bron = ftd_string_new("|:(");
    datadir = ftd_file_parse_data_dir("/emoticons/frusty.gif");
    tekst = g_strdup_printf("%sfile://%s%s", "<IMG SRC='", datadir, "' BORDER='0'>");
    tags[14].doel = ftd_string_new(tekst);
    g_free(tekst);
    g_free(datadir);

    tags[15].bron = ftd_string_new(":O");
    datadir = ftd_file_parse_data_dir("/emoticons/redface.gif");
    tekst = g_strdup_printf("%sfile://%s%s", "<IMG SRC='", datadir, "' BORDER='0'>");
    tags[15].doel = ftd_string_new(tekst);
    g_free(tekst);
    g_free(datadir);

    tags[16].bron = ftd_string_new(":Z");
    datadir = ftd_file_parse_data_dir("/emoticons/sleephappy.gif");
    tekst = g_strdup_printf("%sfile://%s%s", "<IMG SRC='", datadir, "' BORDER='0'>");
    tags[16].doel = ftd_string_new(tekst);
    g_free(tekst);
    g_free(datadir);

    tags[17].bron = ftd_string_new("}:)");
    datadir = ftd_file_parse_data_dir("/emoticons/devil.gif");
    tekst = g_strdup_printf("%sfile://%s%s", "<IMG SRC='", datadir, "' BORDER='0'>");
    tags[17].doel = ftd_string_new(tekst);
    g_free(tekst);
    g_free(datadir);

    tags[18].bron = ftd_string_new(";)");
    datadir = ftd_file_parse_data_dir("/emoticons/wink.gif");
    tekst = g_strdup_printf("%sfile://%s%s", "<IMG SRC='", datadir, "' BORDER='0'>");
    tags[18].doel = ftd_string_new(tekst);
    g_free(tekst);
    g_free(datadir);

    tags[19].bron = ftd_string_new(":'(");
    datadir = ftd_file_parse_data_dir("/emoticons/cry.gif");
    tekst = g_strdup_printf("%sfile://%s%s", "<IMG SRC='", datadir, "' BORDER='0'>");
    tags[19].doel = ftd_string_new(tekst);
    g_free(tekst);
    g_free(datadir);

    tags[20].bron = ftd_string_new(":P");
    datadir = ftd_file_parse_data_dir("/emoticons/puh2.gif");
    tekst = g_strdup_printf("%sfile://%s%s", "<IMG SRC='", datadir, "' BORDER='0'>");
    tags[20].doel = ftd_string_new(tekst);
    g_free(tekst);
    g_free(datadir);

    tags[21].bron = ftd_string_new(":R");
    datadir = ftd_file_parse_data_dir("/emoticons/pukey.gif");
    tekst = g_strdup_printf("%sfile://%s%s", "<IMG SRC='", datadir, "' BORDER='0'>");
    tags[21].doel = ftd_string_new(tekst);
    g_free(tekst);
    g_free(datadir);

    tags[22].bron = ftd_string_new("8)");
    datadir = ftd_file_parse_data_dir("/emoticons/cool.gif");
    tekst = g_strdup_printf("%sfile://%s%s", "<IMG SRC='", datadir, "' BORDER='0'>");
    tags[22].doel = ftd_string_new(tekst);
    g_free(tekst);
    g_free(datadir);

    tags[23].bron = ftd_string_new(":(");
    datadir = ftd_file_parse_data_dir("/emoticons/frown.gif");
    tekst = g_strdup_printf("%sfile://%s%s", "<IMG SRC='", datadir, "' BORDER='0'>");
    tags[23].doel = ftd_string_new(tekst);
    g_free(tekst);
    g_free(datadir);

    tags[24].bron = ftd_string_new("(.*)\\[[qQ][uU][oO][tT][eE]=([a-zA-Z0-9\\-_ \\.]+)\\](.*)");
    tags[24].doel = ftd_string_new("%s<U>Quote: <B>%s</B></U><BLOCKQUOTE><FONT COLOR='#440000'>%s");
    tags[24].is_regexp = TRUE;

    tags[25].bron = ftd_string_new("(.*)\\[[iI][mM][gG]=([a-zA-Z0-9_]+)\\](.*)");
    datadir = ftd_file_parse_data_dir("/emoticons/");
    tekst = g_strdup_printf("%%s<IMG SRC='file://%s%%s.gif' BORDER=0>%%s", datadir);
    tags[25].doel = ftd_string_new(tekst);
    tags[25].is_regexp = TRUE;
    g_free(tekst);
    g_free(datadir);

    tags[26].bron = ftd_string_new("(.*)ftd://([0-9]+)([^0-9].*)");
    datadir = ftd_file_parse_data_dir("/images/");
    tekst = g_strdup_printf("%%s<A HREF=iets.html#post%%s>ftd:%%s <img src='%sicon_ftd.gif' border=0></A> %%s", datadir);
    tags[26].doel = ftd_string_new(tekst);
    tags[26].has_backreference = TRUE;
    tags[26].is_regexp = TRUE;
    g_free(tekst);
    g_free(datadir);

    tags[27].bron = ftd_string_new("[url]");
    tags[27].doel = ftd_string_new("");

    tags[28].bron = ftd_string_new("[/url");
    tags[28].bron = ftd_string_new("");

    tags[29].bron = ftd_string_new("[URL]");
    tags[29].doel = ftd_string_new("");

    tags[30].bron = ftd_string_new("[/URL]");
    tags[30].doel = ftd_string_new("");

    // Deze vervanging is nodig om te voorkomen dat de regexp hieronder in een oneindigende loop belandt
    tags[31].bron = ftd_string_new("http://");
    tags[31].doel = ftd_string_new("httP://");

    tags[32].bron = ftd_string_new("(.*)httP://([^ \\<]+)([ \\<].*)");
    tekst = g_strdup_printf("%%s<A HREF='iets.html#linkhttp://%%s'>http://%%s</A>%%s");
    tags[32].doel = ftd_string_new(tekst);
    tags[32].has_backreference = TRUE;
    tags[32].is_regexp = TRUE;
    g_free(tekst);
}

/**
 * Ruimt de parser op.
 */
void
ftd_gui_parse_free(void)
{
    int teller;

    for (teller = 0; teller < 100; teller++) {
        if (tags[teller].bron) {
            ftd_string_free(tags[teller].bron);
        }
        if (tags[teller].doel) {
            ftd_string_free(tags[teller].doel);
        }
    }
}

/**
 * Zet alle tags die voorkomen in een tekst om in HTML-equivalenten.
 *
 * @arg     tekst       De te parsen tekst.
 *
 * @return  Een nieuwe string waarin alle tags in de gegeven tekst vervangen zijn voor HTML-equivalenten.
 */
FtdString *
ftd_gui_parse(FtdString *tekst)
{
    FtdString *res;
    FtdString *tmp;
    int teller;

    if (!tekst) {
        return ftd_string_new("");
    }

    res = ftd_string_new(ftd_string_value(tekst));
    res = ftd_string_append(res, " ");              // deze hack is nodig om http:// url's goed te kunnen filteren

    // Laat alle beschikbare tags los op de tekst
    for (teller = 0; teller < 100; teller++) {
        if (tags[teller].bron && tags[teller].doel) {
            if (tags[teller].is_regexp) {
                tmp = ftd_gui_parse_regexp_replace(res, ftd_string_value(tags[teller].bron), ftd_string_value(tags[teller].doel), tags[teller].has_backreference);
            } else {
                tmp = ftd_string_replace(res, ftd_string_value(tags[teller].bron), ftd_string_value(tags[teller].doel));
            }
            ftd_string_free(res);
            res = tmp;
        }
    }

    // Verwijder de spatie aan het einde die aan het begin van deze functie was toegevoegd
    if (ftd_string_value(res)[ftd_string_length(res) - 1] == ' ') {
        ftd_string_value(res)[ftd_string_length(res) - 1] = '\0';
    }

    return res;
}

#define OVECCOUNT 30    /* should be a multiple of 3 */

/**
 * Voert een regex vervanging uit.
 * Alle voorkomens van het gezochte patroon worden vervangen.
 *
 * @arg     bron                De tekst waarin de vervanging plaats moet vinden.
 * @arg     match_regexp        Het gezochte patroon.
 * @arg     replace_regexp      Het vervangings-patroon.
 * @arg     has_backreference   True indien het vervangings-patroon gebruik maakt van backreferences.
 *
 * @return  Een nieuwe string met daarin het resultaat van de vervangingen.
 */
FtdString *
ftd_gui_parse_regexp_replace(FtdString *bron, char *match_regexp, char *replace_pattern, gboolean has_backreference)
{
    pcre *re;
    const char *errmsg = NULL;
    int errpos;
    int ovector[OVECCOUNT];
    int num;
    const char **values = NULL;
    FtdString *ret = NULL;

    re = pcre_compile(match_regexp, PCRE_DOTALL, &errmsg, &errpos, NULL);
    if (re == NULL || errmsg != NULL) {
        g_print("ftd_string_regexp_replace(): match_regexp = %s\nerrmsg = %s\n", match_regexp, errmsg);
        return ftd_string_new(ftd_string_value(bron));
    }

    num = pcre_exec(re, NULL, ftd_string_value(bron), (int) ftd_string_length(bron), 0, 0, ovector, OVECCOUNT);
    if (num > 0) {
        char *tmp;
        FtdString *tmp2;

        pcre_get_substring_list(ftd_string_value(bron), ovector, num, &values);

        if (has_backreference) {
            tmp = g_strdup_printf(replace_pattern, values[1], values[2], values[2], values[3]);
        } else {
            tmp = g_strdup_printf(replace_pattern, values[1], values[2], values[3]);
        }
        tmp2 = ftd_string_new(tmp);
        g_free(tmp);
        pcre_free_substring_list(values);

        // Voer deze functie recursief uit zodat alle instanties van een match aangepakt worden
        ret = ftd_gui_parse_regexp_replace(tmp2, match_regexp, replace_pattern, has_backreference);
        ftd_string_free(tmp2);
    }

    if (ret == NULL) {
        ret = ftd_string_new(ftd_string_value(bron));
    }

    pcre_free(re);

    return ret;
}
