/*
 * Copyright (C) 2005 - 2008  Zarafa B.V.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License, version 3, 
 * as published by the Free Software Foundation with the following additional 
 * term according to sec. 7:
 * 
 * "Zarafa" is a registered trademark of Zarafa B.V. The licensing of the Program
 * under the AGPL does not imply a trademark license. Therefore any rights,
 * title and interest in our trademarks remain entirely with us.
 * However, if you propagate an unmodified version of the Program you are 
 * required to use the term "Zarafa" to indicate that you distribute the 
 * Program. Furthermore you may use our trademarks where it is necessary to 
 * indicate the intended purpose of a product or service provided you use it in 
 * accordance with honest practices in industrial or commercial matters.
 * If you want to propagate modified versions of the Program under the name
 * "Zarafa" or "Zarafa Server", you may only do so if you have a written
 * permission by Zarafa B.V. (to acquire a permission please contact Zarafa at
 * trademark@zarafa.com).
 * The user interface of the software displays a attribution notice containing
 * the term "Zarafa" and/or the Logo of Zarafa. You have to preserve these
 * attribution notices when you propagate unmodified or modified versions of
 * the Program.
 * 
 * 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 Affero General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */

#ifndef RECURRENCE_H
#define RECURRENCE_H

#include <stdlib.h>
#include <string>
#include <list>
#include <map>
#include "mapidefs.h"
#include "timezone_type.h"
using namespace std;

typedef struct bin_timezone_type {
	// The bias values (bias, stdbias and stdbias) are the opposite of what you expect.
	// Thus +1 hour becomes -60, +2 hours becomes -120, -3 becomes +180
	LONG bias;//
	LONG stdbias;//
	LONG dstbias;//
	USHORT const1;
	USHORT startYear;
	USHORT startMonth;//
	USHORT startDayOfWeek;
	USHORT startDay;//
	USHORT startHour;//
	USHORT startMinute;
	USHORT startSecond;
	USHORT startMilliseconds;
	USHORT const2;
	USHORT endYear;
	USHORT endMonth;//
	USHORT endDayOfWeek;
	USHORT endDay;//
	USHORT endHour;//
	USHORT endMinute;
	USHORT endSecond;
	USHORT endMilliseconds;
} bin_timezone_type;

class recurrence{
public:

	recurrence();

	typedef enum freq_type {DAILY, WEEKLY, MONTHLY, YEARLY} freq_type;
	typedef enum term_type {DATE, NUMBER, NEVER} term_type;
	typedef struct changed_occurrence_type {
		time_t startdate;
		time_t enddate;
		time_t basedate;
		unsigned short changes;
		string subject;
		ULONG Remind_before;
		bool Reminder_set;
		string Location;
		ULONG Show_time_as; //Busystatus: busy, free, etc
		bool allday;
		ULONG Label; //prio
		bool Attach;
		bool HasAttendees;
	} changed_occurrence_type;

	HRESULT MakeValid();

	HRESULT setBinary(LPSBinary, LPSBinary);
	HRESULT getBinary(LPSBinary);

	HRESULT getFrequency(freq_type *);
	HRESULT setFrequency(freq_type);

	HRESULT getStartDate(time_t *);
	HRESULT setStartDate(time_t);

	HRESULT getEndDate(time_t *);
	HRESULT setEndDate(time_t);

	HRESULT getStartTime(ULONG *);
	HRESULT setStartTime(ULONG);

	HRESULT getEndTime(ULONG *);
	HRESULT setEndTime(ULONG);

	HRESULT getCount(ULONG *);
	HRESULT setCount(ULONG);

	bool isAllday();
	HRESULT getAllday(bool *);
	HRESULT setAllday(bool);

	HRESULT getTerm(term_type *);
	HRESULT setTerm(term_type);

	HRESULT getInterval(ULONG *);
	HRESULT setInterval(ULONG);

	bool isRegenerating();
	HRESULT getRegenerating(bool *);
	HRESULT setRegenerating(bool);

	HRESULT getWeekdays(UCHAR *);
	HRESULT setWeekdays(UCHAR);

	HRESULT getMonthday(UCHAR *);
	HRESULT setMonthday(UCHAR);

	HRESULT getMonth(UCHAR *);
	HRESULT setMonth(UCHAR);

	HRESULT getNday(UCHAR *);
	HRESULT setNday(CHAR);

	HRESULT getWeekstart(UCHAR *);
	HRESULT setWeekstart(UCHAR);

	HRESULT setDeletedOccurrence(time_t);
	HRESULT removeDeletedOccurrence(time_t);
	list<time_t> getDeletedOccurrences();

	HRESULT getChangedOccurrence(time_t, changed_occurrence_type *);
	HRESULT setChangedOccurrence(changed_occurrence_type);
	HRESULT removeChangedOccurrence(time_t);
	list<changed_occurrence_type> getChangedOccurrences();

	bool isException(time_t);
	list<time_t> getExceptions();

	bool isOccurrence(time_t);
	bool isRuleOccurrence(time_t);
	bool isDeletedOccurrence(time_t);
	bool isChangedOccurrence(time_t);
	bool isAfter(time_t);

	bool isRecurring();

	list<time_t> getOccurrencesBetween(time_t, time_t);

	static HRESULT Local2UTC(timezone_type*, time_t, time_t *);
	static HRESULT UTC2Local(timezone_type*, time_t, time_t *);

	static HRESULT HrClearStructBinTimezoneType(bin_timezone_type * lpBinTimezoneType);
	static HRESULT HrClearStructChangedOccurrencesType(recurrence::changed_occurrence_type * lpChangedOccurrencesType);

private:
	freq_type freq;		// day,week,month,year
	time_t startdate;	//
	time_t enddate;		// until
	ULONG starttime;	// in minutes
	ULONG endtime;		// in minutes
	
	bool allday;

	term_type term;
	ULONG count;		// numoccur

	ULONG interval;		// everyn
	bool regen;
	ULONG weekdays;		// 1 = Sunday, 2 = Monday, 4 = ...
	ULONG monthday;		// 1 to 31
	ULONG month;
	ULONG nday;

	ULONG weekstart;	// 0 = Sunday, 1 = Monday, ...
	list<time_t> exceptions;
	list<time_t> deleted_occurrences;	
	list<changed_occurrence_type> changed_occurrences;

	time_t Minutes2Time(ULONG);
	ULONG Time2Minutes(time_t);
	ULONG Minutes2Month(ULONG);
	time_t DayStartOf(time_t);
	time_t WeekStartOf(time_t);
	time_t MonthStartOf(time_t);
	HRESULT calcEndDate();
	HRESULT calcCount();
	static ULONG DaysInMonth(ULONG);
	static ULONG DaysInMonth(ULONG, ULONG);
	static ULONG DaysInYear(ULONG);
	static ULONG MonthFromTime(time_t);
	static ULONG YearFromTime(time_t);
	static ULONG AllMonthsFromTime(time_t);
	static ULONG WeekDayFromTime(time_t);
	static ULONG MonthDayFromTime(time_t);

	/*ULONG GMT2Local(ULONG);
	ULONG Local2GMT(ULONG);
	LONG GetTimezone(ULONG);
	LONG GetTimezone(time_t t);*/
};

#endif
