/*   Cataract - Static web photo gallery generator
 *   Copyright (C) 2010 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.
 */

#define _XOPEN_SOURCE   /*  for strptime()  */
#define _BSD_SOURCE     /*  for struct tm.tm_gmtoff  */

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>

#include <glib.h>

#include <config.h>

#include "setup.h"
#include "atom-writer.h"
#include "gallery-utils.h"




TAtomFeed *
atom_writer_new ()
{
  return g_new0 (TAtomFeed, 1);
}

static time_t
parse_timestamp (const gchar *timestamp)
{
  struct tm t = {0};
  long saved_tm_gmtoff;


  if (timestamp == NULL || strlen (timestamp) == 0) {
    g_print ("parse_timestamp() error: invalid timestamp NULL\n");
    return 0;
  }

  strptime (timestamp, "%FT%T%z", &t);
  saved_tm_gmtoff = t.tm_gmtoff;

  return mktime (&t) - saved_tm_gmtoff;
}

static gint
feed_list_date_sort_func (TAtomFeedItem *item1, TAtomFeedItem *item2)
{
  time_t t1, t2;

  t1 = parse_timestamp (item1->date);
  t2 = parse_timestamp (item2->date);

  return - (t1 - t2);
}

static gchar *
atom_create_tag (const gchar *base_url, const gchar *date, const gchar *title, const gchar *path)
{
  gchar *s, *s2, *s3;

  /*  http://feedvalidator.org/docs/error/InvalidTAG.html  */

  /*  extract domain name  */
  s2 = strstr (base_url, "://");
  if (s2 != NULL) {
    s2 += 3;
    s3 = strstr (s2, "/");

    /*  no slash found, treat it as is  */
    if (s3 == NULL)
      s3 = g_strdup (s2);
    else
      s3 = g_strndup (s2, s3 - s2);

    s = g_strdup_printf ("tag:%s,", s3);
    g_free (s3);
  }
  else {
    g_print ("atom_create_tag() error: invalid base_url '%s'\n", base_url);
    s = g_strdup ("tag:unknown.cgg.gallery.com,");
  }

  /*  copy the date, let's assume correct format  */
  s3 = g_strndup (date, 10);
  s2 = g_strdup_printf ("%s%s:x", s, s3 ? s3 : "2010-01-01");
  g_free (s3);
  g_free (s);
  s = s2;

  /*  append hashed title and path  */
  if (title) {
    s2 = g_strdup_printf ("%s.%u", s, g_str_hash (title));
    g_free (s);
    s = s2;
  }
  if (path) {
    s2 = g_strdup_printf ("%s.%u", s, g_str_hash (path));
    g_free (s);
    s = s2;
  }

  return s;
}

void
atom_writer_write_to_file (TAtomFeed *feed, const gchar *filename, TGallerySetup *setup)
{
  FILE* f;
  GSList *list;
  TAtomFeedItem *item;
  gchar *s;
  const gchar *last_updated;

  f = fopen (filename, "w");
  if (f == NULL) {
    log_error ("Error writing atom feed: %s\n", strerror (errno));
    return;
  }

  /*  sort items by date  */
  feed->items = g_slist_sort (feed->items, (GCompareFunc) feed_list_date_sort_func);

  /*  find most recent date  */
  last_updated = NULL;
  for (list = feed->items; list; list = list->next) {
    item = list->data;
    last_updated = item->date;
    if (last_updated)
      break;
  }

  /*  write header  */
  fprintf (f, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
  fprintf (f, "<feed xmlns=\"http://www.w3.org/2005/Atom\">\n");
  fprintf (f, "   <title>%s</title>\n", feed->title);
  if (last_updated)
    fprintf (f, "   <updated>%s</updated>\n", last_updated);

  s = atom_create_tag (feed->base_url, last_updated, feed->title, NULL);
  fprintf (f, "   <id>%s</id>\n", s);
  g_free (s);

  s = g_build_path ("/", feed->base_url, "/", NULL);
  fprintf (f, "   <link rel=\"alternate\" type=\"text/html\" href=\"%s\"/>\n", s);
  g_free (s);

  fprintf (f, "   <link rel=\"self\" type=\"application/atom+xml\" href=\"%s\"/>\n", feed->feed_url);
  fprintf (f, "   <generator uri=\"%s\" version=\"%s\">%s</generator>\n", APP_HOMEPAGE, VERSION, APP_NAME_FULL);

  if (setup->favicon_file)
    fprintf (f, "   <icon>%s</icon>\n", setup->favicon_file);

  if (setup->meta_author || setup->meta_author_email) {
    fprintf (f, "   <author>\n");
    if (setup->meta_author)
      fprintf (f, "      <name>%s</name>\n", setup->meta_author);
    if (setup->meta_author_email)
      fprintf (f, "      <email>%s</email>\n", setup->meta_author_email);
    fprintf (f, "   </author>\n");
  }
  fprintf (f, "\n");

  /*  write items  */
  for (list = feed->items; list; list = list->next) {
    item = list->data;
    if (item->title == NULL || strlen (item->title) == 0 ||
        item->date == NULL || strlen (item->date) == 0 ||
        item->path == NULL || strlen (item->path) == 0)
      log_error ("Error: missing required fields in feed item data (title = '%s').\n", item->title);
    else {
      fprintf (f, "   <entry>\n");
      fprintf (f, "      <title>%s</title>\n", item->title);
      s = g_build_path ("/", setup->feed_base_url, item->path, "/", NULL);
      fprintf (f, "      <link rel=\"alternate\" type=\"text/html\" href=\"%s\"/>\n", s);
      g_free (s);

      s = atom_create_tag (feed->base_url, item->date, item->title, item->path);
      fprintf (f, "      <id>%s</id>\n", s);
      g_free (s);

      fprintf (f, "      <updated>%s</updated>\n", item->date);
      fprintf (f, "      <summary");
      if (item->summary_type)
        fprintf (f, " type=\"%s\"", item->summary_type);
      fprintf (f, ">\n%s\n      </summary>\n", item->summary);
      fprintf (f, "   </entry>\n\n");
    }
  }

  fprintf (f, "</feed>\n");
  fclose (f);
}

static void
atom_feed_item_free (TAtomFeedItem *item)
{
  g_free (item->title);
  g_free (item->path);
  g_free (item->date);
  g_free (item->summary);
  g_free (item->summary_type);
  g_free (item);
}

void
atom_writer_free (TAtomFeed *feed)
{
  if (feed) {
    g_slist_foreach (feed->items, (GFunc) atom_feed_item_free, NULL);
    g_slist_free (feed->items);
    g_free (feed->title);
    g_free (feed->base_url);
    g_free (feed->feed_url);
    g_free (feed);
  }
}

void
atom_writer_set_title (TAtomFeed *feed, const gchar *title)
{
  g_free (feed->title);
  feed->title = g_markup_escape_text (title, -1);
}

void
atom_writer_set_base_url (TAtomFeed *feed, const gchar *base_url)
{
  g_free (feed->base_url);
  feed->base_url = g_strdup (base_url);
}

void
atom_writer_set_feed_url (TAtomFeed *feed, const gchar *feed_url)
{
  g_free (feed->feed_url);
  feed->feed_url = g_strdup (feed_url);
}


G_LOCK_DEFINE (atom_writer_items);

TAtomFeedItem *
atom_writer_add_item (TAtomFeed *feed)
{
  TAtomFeedItem *item;

  item = g_new0 (TAtomFeedItem, 1);

  G_LOCK (atom_writer_items);
  feed->items = g_slist_append (feed->items, item);
  G_UNLOCK (atom_writer_items);

  return item;
}


void
atom_feed_item_set_title (TAtomFeedItem *item, const gchar *title)
{
  g_free (item->title);
  item->title = g_markup_escape_text (title, -1);
}

void
atom_feed_item_set_path (TAtomFeedItem *item, const gchar *path)
{
  g_free (item->path);
  item->path = g_strdup (path);
}

void
atom_feed_item_set_date (TAtomFeedItem *item, const gchar *date)
{
  g_free (item->date);
  item->date = g_strdup (date);
}

void
atom_feed_item_set_summary (TAtomFeedItem *item, const gchar *summary)
{
  g_free (item->summary);
  item->summary = g_markup_escape_text (summary, -1);
}

void
atom_feed_item_set_summary_type (TAtomFeedItem *item, const gchar *summary_type)
{
  g_free (item->summary_type);
  item->summary_type = g_strdup (summary_type);
}

