/*   Cataract - Static web photo gallery generator
 *   Copyright (C) 2009 Tomas Bzatek <tbzatek@users.sourceforge.net>
 *
 *   This program is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU General Public License
 *   as published by the Free Software Foundation; either version 2
 *   of the License, or any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/stat.h>
#include <unistd.h>

#include <glib.h>
#include <glib/gprintf.h>

#include "replace-table.h"
#include "gallery-utils.h"




ReplaceTable *
replace_table_new ()
{
  return (ReplaceTable *) g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
}

void
replace_table_free (ReplaceTable *table)
{
  g_return_if_fail (table != NULL);

  g_hash_table_destroy (table);
}


/*
 *   replace_table_add_key: add tag/value pair to replace
 *
 *      tag, value will be referenced inside
 *
 */
void
replace_table_add_key (ReplaceTable *table, const gchar *tag, const gchar *value)
{
  g_return_if_fail (table != NULL);

  if (tag != NULL && value != NULL)
    g_hash_table_replace (table, g_strdup (tag), g_strdup (value));
}

void
replace_table_add_key_int (ReplaceTable *table, const gchar *tag, gint value)
{
  g_return_if_fail (table != NULL);

  if (tag != NULL)
    g_hash_table_replace (table, g_strdup (tag), g_strdup_printf ("%d", value));
}

void
replace_table_add_key_printf (ReplaceTable *table, const gchar *tag, const gchar *format, ...)
{
  va_list args;
  gchar *s = NULL;

  g_return_if_fail (table != NULL);

  if (tag != NULL && format != NULL) {
    va_start (args, format);
    g_vasprintf (&s, format, args);
    g_hash_table_replace (table, g_strdup (tag), s);
    va_end (args);
  }
}


/*
 *   replace_table_process: process buffer and replace all tags filled in the replace table
 *
 *      - reallocates source buffer
 *
 */
void
replace_table_process (gchar **buffer, ReplaceTable *table)
{
  gchar *token;
  gchar *start, *end;
  gchar *b;
  gchar *replace_value;
  GString *dst;
  gboolean tag_parameter;
  gboolean handled;

  g_return_if_fail (table != NULL);
  g_return_if_fail (buffer != NULL);
  if (*buffer == NULL || strlen (*buffer) < 1)
    return;


  dst = g_string_new (NULL);
  b = *buffer;
  while ((token = get_next_token (b, &start, &end, &tag_parameter))) {
    handled = FALSE;

    /*  push the string before the token  */
    g_string_append_len (dst, b, start - b);

    replace_value = g_strdup (g_hash_table_lookup (table, token));
    if (replace_value) {
      if (! tag_parameter)
        adjust_tags_normal (&replace_value);
      else
        adjust_tags_parameter (&replace_value);
      g_string_append (dst, replace_value);
      g_free (replace_value);
      handled = TRUE;
    }

    /*  push the tag if not matched above  */
    if (! handled)
      g_string_append_len (dst, start, end - start + 1);

    g_free (token);
    b = end + 1;
  }
  /*  push rest of the buffer till the end of the line  */
  g_string_append (dst, b);

  g_free (*buffer);
  *buffer = g_string_free (dst, FALSE);
}


/*
 *   adjust_tags_normal:    adjust string for normal HTML use
 *   adjust_tags_parameter: adjust string for use as tag parameter value
 *        - both funtions return newly allocated string
 */
void
adjust_tags_normal (gchar **str)
{
  fix_entities (str);
}

void
adjust_tags_parameter (gchar **str)
{
  /*  TODO: replace line endings with a single space?  */
  remove_tags (str, "<!--", "-->");       /*  comments  */
  remove_tags (str, "<", ">");            /*  tags      */
  fix_entities (str);                     /*  entities  */
  str_replace (str, "\"", "&quot;");      /*  "         */
  str_replace (str, "'", "&apos;");       /*  '         */
}


/* -------------------------------------------------------------------------------------------------------- */


/*
 *   get_next_token: retrieves first token (<!-- $(TOKEN) --> or $(TOKEN)) in the string
 *      - returns newly allocated token name, caller is responsible for freeing
 *      - start and end are positions of token in the source string 's'
 *      - tag_parameter indicates where the token stands - as a tag itself ( <!-- $(TOKEN) --> )
 *        or as a parameter value of some tag ( $(TOKEN) )
 *
 */
gchar *
get_next_token (const gchar *s, gchar **start, gchar **end, gboolean *tag_parameter)
{
  gchar *dollar;
  gchar *end_brace;
  gchar *b;

  *start = NULL;
  *end = NULL;
  if (tag_parameter)
    *tag_parameter = TRUE;

  dollar = strstr (s, "$(");
  if (dollar == NULL)
    return NULL;
  end_brace = strchr (dollar + 2, ')');
  if (end_brace == NULL)
    return NULL;

  /*  Go back and try to find placeholder beginning  */
  for (b = dollar - 1; b >= s + 3; b--) {
    if (*b == '-' && *(b-1) == '-' && *(b-2) == '!' && *(b-3) == '<') {
      *start = b - 3;
      if (tag_parameter)
        *tag_parameter = FALSE;
      break;
    }
    if (*b != ' ')
      break;
  }
  if (*start == NULL)
    *start = dollar;

  /*  Go forth and try to find placeholder end  */
  for (b = end_brace + 1; b <= end_brace + strlen (end_brace) - 3; b++) {
    if (*b == '-' && *(b+1) == '-' && *(b+2) == '>') {
      *end = b + 2;
      break;
    }
    if (*b != ' ')
      break;
  }
  if (*end == NULL)
    *end = end_brace;

  return g_strndup (dollar + 2, end_brace - dollar - 2);
}

