/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/*
 * evolution-util.c
 *
 *  Created on: 26.10.2010
 *      Author: Hendrik Helwich <h.helwich@tarent.de>,
 *      		Peter Neuhaus <p.neuhaus@tarent.de>,
 *      		Andreas Grau <a.grau@tarent.de>
 */

/*
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * 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 Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser 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
 */

/* FIXME remove the use of timegm() */
#define _BSD_SOURCE
#define _SVID_SOURCE

#include <time.h>

#include "evolution-util.h"
#include "../logging.h"

/**
 * Convert an evolution iCal time type to an internal date((/time) structure.
 */
void
date_or_datetime_e_to_i(icaltimetype *t, Date_or_datetime *date)
{
	if (t) {
		if (t->is_date)
			date->date = g_date_new_dmy((GDateDay)t->day , (GDateMonth)t->month, (GDateYear)t->year);
		else
			date->date_time = datetime_e_to_i(t);
	} else {
		log_debug("\nError: date_or_datetime is NULL");
		t = NULL;
	}
}

time_t *
datetime_e_to_i(icaltimetype *t)
{
	struct tm *timeinfo = g_new0(struct tm, 1);
	time_t *dt = g_new0(time_t, 1);

	timeinfo->tm_year = t->year-1900;
	timeinfo->tm_mon = t->month-1;
	timeinfo->tm_mday = t->day;
	timeinfo->tm_hour = t->hour;
	timeinfo->tm_min = t->minute;
	timeinfo->tm_sec = t->second;

	*dt = timegm( timeinfo );
	g_free(timeinfo);
	return dt;
}

/**
 * Convert an internal date((/time) structure to an evolution iCal time type.
 */
void
date_or_datetime_i_to_e(Date_or_datetime *date, icaltimetype *t, gboolean is_utc)
{
	if (date) {
		if(date->date) {
			t->year = date->date->year;
			t->month = date->date->month;
			t->day = date->date->day;
			t->is_date = 1;
			t->is_utc = is_utc ? 1 : 0;
		} else if(date->date_time)
			datetime_i_to_e(date->date_time, t, is_utc);


	} else {
		log_debug("\nError: date_or_datetime is NULL");
		t = NULL;
	}
}

void
datetime_i_to_e(time_t *date_time, icaltimetype *t, gboolean is_utc)
{
	struct tm * timeinfo;
	timeinfo = gmtime (date_time);

	t->year = timeinfo->tm_year+1900;
	t->month = timeinfo->tm_mon+1;
	t->day = timeinfo->tm_mday;
	t->hour = timeinfo->tm_hour;
	t->minute = timeinfo->tm_min;
	t->second = timeinfo->tm_sec;
	t->is_date = 0;

	t->is_utc = is_utc ? 1 : 0;
}

/**
 * Convert UTC to local time.
 *
 * @param date_time
 * 			the ECalComponentDateTime struct to be converted
 * @param vtimezone
 * 			the ICalendar VTIMEZONE block
 */
void
utc_to_localtime(ECalComponentDateTime *date_time, gchar *vtimezone)
{
	/* get icaltimezone for UTC */
	icaltimezone *utc = icaltimezone_get_utc_timezone();

	if (vtimezone == NULL) { /* localtime is UTC */
		/* this step is needed to set the "Z" suffix in
		 * ICalendar timestamp, e.g. "20101104T111300Z"
		 */
		if (date_time->tzid != NULL)
			g_free ((gpointer)(date_time->tzid));
		date_time->tzid = g_strdup(icaltimezone_get_tzid(utc));
		date_time->value->is_utc = 1;
	} else {
		/* deserialize vtimezone */
		ECalComponent *local_tz = e_cal_component_new_from_string(vtimezone);

		/* get icaltimezone for localtime */
		icaltimezone *ical_tz = ecalcomponent_tz_get_icaltimezone(local_tz);

		/* is this really needed? probably not, but who knows... */
		/* date_time->tzid = g_strdup(icaltimezone_get_tzid(ical_tz)); */
		date_time->tzid = icaltimezone_get_tzid(ical_tz);
		date_time->value->is_utc = (strcmp(date_time->tzid, icaltimezone_get_tzid(utc)) != 0) ? 0 : 1;

		/* ...convert time */
		icaltimezone_convert_time(date_time->value, utc, ical_tz);

		/* free unused data structures */
		g_object_unref(local_tz); /* recursively frees its components */
		g_free(ical_tz);
	}
}

/**
 * Convert local time to UTC
 *
 * @param date_time
 * 			the ECalComponentDateTime struct to be converted
 * @param local_tz
 * 			an ECalComponent representing the local timezone
 */
void
localtime_to_utc(ECalComponentDateTime *date_time, ECalComponent *local_tz)
{
	icaltimezone *ical_tz = NULL;
	icaltimezone *utc = NULL;

	if (date_time->value->is_utc || local_tz == NULL) /* local_tz == UTC */
		return;

	/* get icaltimezone for localtime */
	ical_tz = ecalcomponent_tz_get_icaltimezone(local_tz);

	/* get icaltimezone for UTC */
	utc = icaltimezone_get_utc_timezone();

	/* ...convert time */
	icaltimezone_convert_time(date_time->value, ical_tz, utc);
#if 0
	icaltimezone_free(utc, 1);
	icaltimezone_free_builtin_timezones();
#endif

	/* free unused data structures */
	g_free(ical_tz);
}

/**
 * Get icaltimezone for ECalComponent.
 */
icaltimezone*
ecalcomponent_tz_get_icaltimezone(ECalComponent *ecal_tz)
{
	/* icalcomponent_get_timezone() does not work as advertised,
	 * therefore it's a bit more complicated...
	 */
	icalcomponent *icalcomp = e_cal_component_get_icalcomponent(ecal_tz);
	icaltimezone *ical_tz = icaltimezone_new();
	icaltimezone_set_component(ical_tz, icalcomp);
	return ical_tz;
}
