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

#include "ftd4linux.h"

/**
 * Geeft een uppercase equivalent van tekst terug.
 *
 * @arg     tekst       Een string.
 * @arg     len         De lengte van tekst.
 *
 * @return  Een nieuwe string waarin elk teken uit tekst gekopieerd is en eventueel hoofdletter gemaakt.
 */
char *
ftd_string_upcase(char *tekst)
{
    int teller;
    char *res;
    int len;

    len = strlen(tekst);
    res = g_strdup(tekst);

    for (teller = 0; teller < len; teller++) {
        if (res[teller] >= 'a' && res [teller] <= 'z') {
            res[teller] += 'A' - 'a';
        }
    }

    res[len] = '\0';

    return res;
}

/**
 * Geeft een representatie van een datum terug.
 *
 * @arg     date        De timestamp die gerepresenteerd moet worden.
 *
 * @return  Een nieuwe string met daarin een representatie van date.
 */
char *
ftd_string_date(time_t date)
{
    struct tm *nu;
    char *res;

    if ((nu = localtime(&date)) == NULL) {
        g_warning("ftd_string_date(): datum kan niet geparsed worden\n");
        return NULL;
    }

    res = (char *) g_malloc (32);

    strftime (res, 31, "%d-%m (%H:%M)", nu);

    /* de struct tm *nu moet niet gefree'd worden */

    return res;
}

/**
 * Geeft een representatie van een getal terug.
 *
 * @arg     integer     Een getal.
 *
 * @return  Een nieuwe string met daarin een representatie van integer.
 */
FtdString *
ftd_string_integer(int integer)
{
    /* INTMAX = 2147483647 oftewel 10 tekens + extra +/- teken + \0 = 12 */
    char buffer[12];

    snprintf(buffer, 11, "%d", integer);

    return ftd_string_new(buffer);
}

/**
 * Converteert van een ::FtdString naar een C-string.
 *
 * @arg     string      De te converteren string.
 *
 * @return  Het C-string equivalent van string.
 */
char *
ftd_string_value(FtdString *string)
{
    if (string == NULL) {
        return NULL;
    } else {
        return string->str;
    }
}

/**
 * Converteert van een C-string naar een ::FtdString.
 *
 * @arg     tekst       De te converteren string.
 *
 * @return  De ::FtdString equivalent van tekst.
 */
FtdString *
ftd_string_new(const char *tekst)
{
    if (tekst == NULL) {
        return NULL;
    } else {
        return g_string_new(tekst);
    }
}

/**
 * Voert een standaard vervanging uit.
 * Alle voorkomens van zoekTerm worden vervangen.
 *
 * @arg     bron        De tekst waarin de vervangingen uitgevoerd moeten worden.
 * @arg     zoekTerm    De gezochte term.
 * @arg     vervangTerm De te vervangen term.
 *
 * @return  Een nieuwe string met het resultaat van de vervangingen.
 */
FtdString *
ftd_string_replace(FtdString *bron, char *zoekTerm, char *vervangTerm)
{
    FtdString *uitvoer = NULL;
    char *res = NULL;
    char *tekst;
    char *begin = NULL;
    int pos = 0;
    int zoekTermLen = strlen(zoekTerm);
    int len = 0;
    char *zoekTermUpper = ftd_string_upcase(zoekTerm);

    g_assert(bron);

    // Voorkom vreemd gedrag als de lengte van bron < lengte van zoekterm
    if (ftd_string_length(bron) < zoekTermLen) {
        g_free( zoekTermUpper );
        return ftd_string_new(ftd_string_value(bron));
    }

    tekst = ftd_string_upcase(ftd_string_value(bron));

    // Tel het aantal keer dat de zoekterm voorkomt in de brontekst.
    // Deze waarde moeten we eerst weten zodat we weten hoeveel geheugen
    // we moeten alloceren
    begin = tekst - zoekTermLen;
    while ((begin = strstr(begin + zoekTermLen, zoekTermUpper))) {
        pos++;
    }

    // Zoekterm komt niet voor in de brontekst -> kappen
    if (pos == 0) {
        g_free(tekst);
        g_free(zoekTermUpper);
        return ftd_string_new(ftd_string_value(bron));
    }

    // Alloceer geheugen voor ons resultaat in op te slaan
    res = (char *) g_malloc(ftd_string_length(bron) + ((strlen(vervangTerm) - zoekTermLen) * pos) + 1);
    memset(res, 0, ftd_string_length(bron) + ((strlen(vervangTerm) - zoekTermLen) * pos) + 1);

    // Zoek naar alle posities waar de zoekterm op voorkomt
    pos = 0;
    while ((begin = strstr(tekst + pos, zoekTermUpper))) {
        len = begin - tekst;    // lang leve pointers

        // Kopieer het stuk voor 'begin' naar de resultaat buffer
        if (len - pos > 0) {
            strncat(res, ftd_string_value(bron) + pos, len - pos);
        }

        // Kopieer de vervangende term naar de buffer
        strncat(res, vervangTerm, strlen(vervangTerm));

        // Onthou waar we gebleven zijn
        pos = len + zoekTermLen;
    }

    // Kopieer nu nog het laatste stukje tekst van de bron
    strncat(res, ftd_string_value(bron) + pos, ftd_string_length(bron) - pos);

    uitvoer = ftd_string_new(res);
    g_free(res);
    g_free(tekst);
    g_free(zoekTermUpper);

    return uitvoer;
}

/**
 * Haalt alt.binaries van een nieuwsgroep-naam af en vervangt dit voor a.b indien nodig.
 *
 * @arg     group       De nieuwsgroep.
 *
 * @return  Een nieuwe string met het resultaat van de vervanging of een kopie van group.
 */
char *
ftd_string_strip_newsgroup(FtdString *group)
{
    char *res;

    if (strncmp(ftd_string_value(group), "alt.binaries", 12) == 0) {
        res = (char *) g_malloc (ftd_string_length(group) - 7);
        snprintf(res, ftd_string_length(group) - 8, "a.b.%s", ftd_string_value(group) + 13);
    } else {
        res = g_strdup(ftd_string_value(group));
    }

    return res;
}

/**
 * Zet http:// voor een url indien nodig.
 *
 * @arg     url     De url.
 *
 * @return  Een nieuwe string met het resultaat van de vervanging of een kopie van url.
 */
FtdString *
ftd_string_add_http(FtdString *url)
{
    FtdString *res = ftd_string_new("");

    if (!url) {
        return res;
    }

    if (ftd_string_length(url) == 0) {
        return res;
    }

    if (strncasecmp(ftd_string_value(url), "http://", 7) != 0) {
        res = ftd_string_append(res, "http://");
    }

    res = ftd_string_append(res, ftd_string_value(url));

    return res;
}

/**
 * Geeft een tekst-representatie van een FTD-categorie weer.
 * Geef het resultaat niet vrij!
 *
 * @arg     cat         De FTD-categorie.
 *
 * @return  Een string met een tekst-representatie van de FTD-categorie.
 */
const char *
ftd_string_category(int cat)
{
    switch (cat) {
        case 0:
            return "Beeld";
        case 1:
            return "Geluid";
        case 2:
            return "Spelletjes";
        case 3:
            return "Applicaties";
        default:
            return "";
    }
}

/**
 * Geeft een tekst-representatie van een event-status.
 * Geef het resultaat niet vrij!
 *
 * @arg     status      De event-status.
 *
 * @return  Een tekst-representatie van status.
 */
const char *
ftd_string_status(FtdStatus status)
{
    switch (status) {
        case FTDSTATUS_NONE:
            return "Onbekend";
        case FTDSTATUS_DELETED2:
        case FTDSTATUS_DELETED:
            return "Verwijderd";
        case FTDSTATUS_SPOT:
            return "Spot";
        case FTDSTATUS_READY:
            return "Ready";
        case FTDSTATUS_ANNOUNCE:
            return "Aangekondigd";
        case FTDSTATUS_UPLOADING:
            return "Bezig met uploaden";
        case FTDSTATUS_UNSUPPORTED:
            return "Niet meer ondersteund";
    }

    return "";
}

/**
 * Voegt de waarde toe aan de gegeven string en geeft de nieuwe string terug.
 *
 * @arg     string      De ::FtdString* om iets aan toe te voegen.
 * @arg     value       De toe te voegen tekst, een char*.
 *
 * @return  De nieuwe ::FtdString.
 */
FtdString *
ftd_string_append(FtdString *string, const char *value)
{
    return g_string_append(string, value);
}

/**
 * Geeft een ::FtdString en de tekst daarin vrij.
 *
 * @arg     string      De ::FtdString* die vrijgegeven dient te worden.
 */
void
ftd_string_free(FtdString *string)
{
    g_return_if_fail(string);
    g_string_free(string, TRUE);
}

/**
 * Heeft de lengte van een ::FtdString terug.
 *
 * @arg     string      De ::FtdString* waarvan de lengte gezocht wordt.
 *
 * @return  De lengte van de gegeven string.
 */
gsize
ftd_string_length(FtdString *string)
{
    return string->len;
}

void
ftd_string_append_printf (FtdString *string, const gchar *format, ...)
{
    g_string_append_printf(string, format);
}
