/*
 * Copyright 2005 - 2009  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:
 *  
 * According to sec. 7 of the GNU Affero General Public License, version
 * 3, the terms of the AGPL are supplemented with the following terms:
 * 
 * "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
 * allowed 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 interactive user interface of the software displays an attribution
 * notice containing the term "Zarafa" and/or the logo of Zarafa.
 * Interactive user interfaces of unmodified and modified versions must
 * display Appropriate Legal Notices according to sec. 5 of the GNU
 * Affero General Public License, version 3, when you propagate
 * unmodified or modified versions of the Program. In accordance with
 * sec. 7 b) of the GNU Affero General Public License, version 3, these
 * Appropriate Legal Notices must retain the logo of Zarafa or display
 * the words "Initial Development by Zarafa" if the display of the logo
 * is not reasonably feasible for technical reasons. The use of the logo
 * of Zarafa in Legal Notices is allowed for unmodified and modified
 * versions of the software.
 * 
 * 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/>.
 * 
 */

// This is a hard one. To create a recurring appointment, we need to save
// the start and end time of the appointment in local time. So if I'm in 
// GMT+8, and I want the appointment at 9:00, I will simply save 9*60 = 540
// in the startDate. To make this usable for other users in other timezones,
// we have to tell the server in which timezone this is. The timezone is normally
// defined as a startdate and enddate for DST, the offset in minutes (so GMT+2 is 120)
// plus the extra DST offset when DST is in effect. 
//
// We can't retrieve this directly from the browser, so we assume that the DST change
// will occure on a Sunday at 2:00 or 3:00 AM, and simply scan all the sundays in a
// year, looking for changes. We then have to guess which bit is DST and which is 'normal'
// by assuming that the DST offset will be less than the normal offset. From this we
// calculate the start and end dates of DST and the actuall offset in minutes.
//
// Unfortunately we can't detect the difference between 'the last week of october' and
// 'the fourth week of october'. This can cause subtle problems, so we assume 'last week'
// because this is most prevalent.
// 
// Note that this doesn't work for many strange DST changes, see 
// http://webexhibits.org/daylightsaving/g.html

function getTimeZone()
{
    var tzswitch = new Array();
    var n = 0;
    var lastoffset;
    
    var t = new Date();
    
    var tz = new Object();
    
    // We use the year 2000 to do the testing. No special reason.
    t.setYear(2000);
    t.setDate(2);
    t.setMonth(0);
    // Jan 2, 2000 was a sunday
    t.setHours(5);
    // Use 5:00 am because any change should have happened by then
    t.setMinutes(0);
    t.setSeconds(0);
    t.setMilliseconds(0);
    
    lastoffset = t.getTimezoneOffset();
    
    for(i=0;i<52;i++) {
        if(t.getTimezoneOffset() != lastoffset) {
            // Found a switch
            tzswitch[n] = new Object;
            tzswitch[n].switchweek = t.getWeekNrOfMonth();
            tzswitch[n].switchmonth = t.getMonth();
            tzswitch[n].offset = t.getTimezoneOffset();
            n++;
            
            // We assume DST is only set or removed once per year
            if(n == 2)
                break;
                
            lastoffset = t.getTimezoneOffset();
        }
        
        // advance one week
        t.setTime(t.getTime() + 7 * 24 * 60 * 60 * 1000);
    }
    
    if(n == 0) {
        // No DST in this timezone
        tz.timezone = t.getTimezoneOffset();
        tz.timezonedst = 0;
        tz.dststartday = 0;
        tz.dststartweek = 0;
        tz.dststartmonth = 0;
        tz.dststarthour = 0;
        tz.dstendday = 0;
        tz.dstendweek = 0;
        tz.dstendmonth = 0;
        tz.dstendhour = 0;
        return tz;
    } else if(n == 1) {
        // This should be impossible unless DST started somewhere in the year 2000
        // and ended more than a year later. This is an error.
        return;
    } else if(n == 2) {
        if(tzswitch[0].offset < tzswitch[1].offset) {
            // Northern hemisphere
            tz.timezone = tzswitch[1].offset;
            tz.timezonedst = tzswitch[0].offset - tzswitch[1].offset;
            tz.dststartday = 0; // assume sunday
            tz.dststartweek = tzswitch[0].switchweek == 4 ? 5 : tzswitch[0].switchweek; // assume 'last' week if week = 4
            tz.dststartmonth = tzswitch[0].switchmonth + 1;
            tz.dststarthour = 2; // Start at 02:00 AM
            tz.dstendday = 0;
            tz.dstendweek = tzswitch[1].switchweek == 4 ? 5 : tzswitch[1].switchweek;
            tz.dstendmonth = tzswitch[1].switchmonth + 1;
            tz.dstendhour = 3;
            return tz;
            
        } else {
            // Southern hemisphere
            tz.timezone = tzswitch[0].offset;
            tz.timezonedst = tzswitch[1].offset - tzswitch[0].offset;
            tz.dststartday = 0; // assume sunday
            tz.dststartweek = tzswitch[1].switchweek == 4 ? 5 : tzswitch[1].switchweek; // assume 'last' week if week = 4
            tz.dststartmonth = tzswitch[1].switchmonth + 1;
            tz.dststarthour = 2; // Start at 02:00 AM
            tz.dstendday = 0;
            tz.dstendweek = tzswitch[0].switchweek == 4 ? 5 : tzswitch[0].switchweek;
            tz.dstendmonth = tzswitch[0].switchmonth + 1;
            tz.dstendhour = 3;
            return tz;
        }
    } else {
        // Multi-DST timezone ? This is also an error.
        return;
    }
}

function setRecurrenceType(type)
{
    var daily = dhtml.getElementById('daily');
    var weekly = dhtml.getElementById('weekly');
    var monthly = dhtml.getElementById('monthly');
    var yearly = dhtml.getElementById('yearly');
    
    var types = new Array(daily, weekly, monthly, yearly);
    var elems = new Array('type_daily', 'type_weekly', 'type_monthly', 'type_yearly');
    var i;
    
    for(i=0;i<4;i++) {
        types[i].style.display = (i == type - 10 ? '' : 'none');
    }

    dhtml.getElementById(elems[type-10]).checked = true;
}

function submitRecurrence()
{
	var tmpDate = dhtml.getElementById("recstart_date").value.split("-");
	var startDate = new Date(parseInt(tmpDate[2],10), parseInt(tmpDate[1],10)-1, parseInt(tmpDate[0],10)).getTime();
	tmpDate = dhtml.getElementById("recend_date").value.split("-");
	var endDate = new Date(parseInt(tmpDate[2],10), parseInt(tmpDate[1],10)-1, parseInt(tmpDate[0],10)).getTime();
	var currentDate = timeToZero(new Date().getTime()/1000)*1000;

	var submitResult = false;
    if(dhtml.getElementById("end_by").checked){
		if(startDate == endDate){
    		alert(_("Start date and End date for range of recurrence can not be same."));  
		}else if(endDate < currentDate){
			if(confirm(_("All instances of this recurring appointment occur in the past.") + "\n" + _("would you like to continue?")))
				submitResult = true;
		}else if(startDate > endDate){
    		alert(_("The recurrence pattern is not valid."));
		}else{
			submitResult = true;
		}
    }else{
		submitResult = true;
	}
	if(submitResult){
	    var result = retrieveRecurrence();
	    window.resultCallBack(result, window.callBackData);
	    window.close();
    }
}

// Retrieves the recurrence pattern by querying the view 'object'
function retrieveRecurrence() {
    var recurdata = new Object();

    if(dhtml.getElementById('end_by').checked) {
        recurdata.term = 0x21;
        recurdata.end = window.range_end.getValue(1);
    } else if(dhtml.getElementById('end_after').checked) {
        recurdata.term = 0x22;
        recurdata.numoccur = parseInt(dhtml.getElementById('end_aftern').value);
        recurdata.end = 79870662000; // 1-1-4501
    } else if(dhtml.getElementById('no_end').checked) {
        recurdata.term = 0x23;
        recurdata.end = 79870662000; // 1-1-4501
    }
    
    recurdata.start = window.range_start.getValue(1);
    recurdata.startocc = window.appo_start.getValue() / 60;
    recurdata.endocc = window.appo_end.getValue() / 60;
    
    // Recurrence from 23:00 to 01:00 should store 23*60->25*60, not 23*60->1*60
    if(recurdata.endocc < recurdata.startocc)
        recurdata.endocc += 24*60;
    
    /**
     * NOTE: alldayevent is not part of recurrence data,
     * but it can be set in recurrence window, so adding
     * to callBackData.
     */
    if(dhtml.getElementById('allday_event').checked) {
    	recurdata.alldayevent = 1;
    }
    
    if(dhtml.getElementById('type_daily').checked) {
        recurdata.type = 10;
        if(dhtml.getElementById('daily_everyndays').checked) {
            recurdata.subtype = 0;
            recurdata.everyn = parseInt(dhtml.getElementById('daily_ndays').value) * 1440;
        } else if(dhtml.getElementById('daily_weekdays').checked) {
            recurdata.subtype = 1;
            recurdata.everyn = 1;
        }
    } else if(dhtml.getElementById('type_weekly').checked) {
        recurdata.type = 11;
        recurdata.everyn = parseInt(dhtml.getElementById('weekly_everynweeks').value);
        recurdata.weekdays = 0;
        recurdata.subtype = 1; // always subtype 1 
        
        if(dhtml.getElementById('weekly_sunday').checked)
            recurdata.weekdays |= 1;
        if(dhtml.getElementById('weekly_monday').checked) 
            recurdata.weekdays |= 2;
        if(dhtml.getElementById('weekly_tuesday').checked) 
            recurdata.weekdays |= 4;
        if(dhtml.getElementById('weekly_wednesday').checked) 
            recurdata.weekdays |= 8;
        if(dhtml.getElementById('weekly_thursday').checked) 
            recurdata.weekdays |= 16;
        if(dhtml.getElementById('weekly_friday').checked) 
            recurdata.weekdays |= 32;
        if(dhtml.getElementById('weekly_saturday').checked) 
            recurdata.weekdays |= 64;
    } else if(dhtml.getElementById('type_monthly').checked) {
        recurdata.type = 12;
        if(dhtml.getElementById('monthly_ndayofmonth').checked) {
            recurdata.subtype = 2;
            recurdata.monthday = parseInt(dhtml.getElementById('monthly_dayn').value);
            recurdata.everyn = parseInt(dhtml.getElementById('monthly_everynmonths').value);
        } else if(dhtml.getElementById('monthly_nweekdayofmonth').checked) {
            recurdata.subtype = 3;
            recurdata.nday = parseInt(dhtml.getElementById('monthly_nweekday').value);
            recurdata.weekdays = parseInt(dhtml.getElementById('monthly_weekday').value);
            recurdata.everyn = parseInt(dhtml.getElementById('monthly_weekdayeverynmonths').value);
        }
    } else if(dhtml.getElementById('type_yearly').checked) {
        recurdata.type = 13;
        recurdata.everyn = 1;
        if(dhtml.getElementById('yearly_month').checked) {
            recurdata.subtype = 2;
            recurdata.month = parseInt(dhtml.getElementById('yearly_eachmonth').value);
            recurdata.monthday = parseInt(dhtml.getElementById('yearly_mday').value);
        } else if(dhtml.getElementById('yearly_nthweekday').checked) {
            recurdata.subtype = 3;
            recurdata.nday = parseInt(dhtml.getElementById('yearly_nth').value);
            recurdata.weekdays = parseInt(dhtml.getElementById('yearly_weekday').value);
            recurdata.month = parseInt(dhtml.getElementById('yearly_onmonth').value);
        }
    }
    
    return recurdata;
}

// Sets up the document 'object' to show the recurrence pattern in 'recurrence'
function showRecurrence(recurrence, object) {
    // Set daily/weekly/monthly/yearly
    setRecurrenceType(recurrence.type);
    
    // Set start date
    object.range_start.setValue(recurrence.start);
    
    // Set start/end time (this is stored and displayed in local time, so no conversion is done!)
    object.appo_start.setValue(recurrence.startocc * 60);
    object.appo_end.setValue(recurrence.endocc * 60);
    
    //set all day event
    if (recurrence["allday_event"]) {
    	dhtml.setValue(dhtml.getElementById("allday_event"), true);
    }
    switch(recurrence.term) {
        case 0x21:
            dhtml.getElementById('end_by').checked = true;
            object.range_end.setValue(recurrence.end);
            break;
        case 0x22:
            dhtml.getElementById('end_after').checked = true;
            dhtml.getElementById('end_aftern').value = recurrence.numoccur;
            break;
        case 0x23:
            dhtml.getElementById('no_end').checked = true;
            break;
    }
    
    // Set all the knobs from the recurrence info					
    switch(recurrence.type) {
    case 10:
        // Daily
        if(recurrence.subtype == 1) {
            dhtml.getElementById('daily_weekdays').checked = true;
        } else {
            dhtml.getElementById('daily_everyndays').checked = true;
            dhtml.getElementById('daily_ndays').value = Math.floor(recurrence.everyn / 1440);
        }
        break;
    case 11:
        // Weekly
        dhtml.getElementById('weekly_everynweeks').value = recurrence.everyn;
        
        dhtml.getElementById('weekly_sunday').checked = recurrence.weekdays & 1;
        dhtml.getElementById('weekly_monday').checked = recurrence.weekdays & 2;
        dhtml.getElementById('weekly_tuesday').checked = recurrence.weekdays & 4;
        dhtml.getElementById('weekly_wednesday').checked = recurrence.weekdays & 8;
        dhtml.getElementById('weekly_thursday').checked = recurrence.weekdays & 16;
        dhtml.getElementById('weekly_friday').checked = recurrence.weekdays & 32;
        dhtml.getElementById('weekly_saturday').checked = recurrence.weekdays & 64;
        break;
    case 12:
        // Monthly
        if(recurrence.subtype == 2) {
            // Day 15 of every 2 months
            dhtml.getElementById('monthly_ndayofmonth').checked = true;
            dhtml.getElementById('monthly_dayn').value = recurrence.monthday;
            dhtml.getElementById('monthly_everynmonths').value = recurrence.everyn;
        } else if(recurrence.subtype == 3) {
            // The 2nd tuesday of every 2 months
            dhtml.getElementById('monthly_nweekdayofmonth').checked = true;
            dhtml.getElementById('monthly_nweekday').value = recurrence.nday;
            dhtml.getElementById('monthly_weekday').value = recurrence.weekdays;
            dhtml.getElementById('monthly_weekdayeverynmonths').value = recurrence.everyn;
        }
        break;
    case 13:
        // Yearly
        if(recurrence.subtype == 2) {
            // Day 15 of February every 2 years
            dhtml.getElementById('yearly_month').checked = true;
            dhtml.getElementById('yearly_eachmonth').value = recurrence.month;
            dhtml.getElementById('yearly_mday').value = recurrence.monthday;
        } else if(recurrence.subtype == 3) {
            // 2nd tuesday in november every 2 years
            dhtml.getElementById('yearly_nthweekday').checked = true;
            dhtml.getElementById('yearly_nth').value = recurrence.nday;
            dhtml.getElementById('yearly_weekday').value = recurrence.weekdays;
            dhtml.getElementById('yearly_onmonth').value = recurrence.month;
        }
        break;
    }
}

function recurrenceOnInputChangePreventZero(moduleObject, element, event){
	if(parseInt(element.value, 10) == 0){
		element.value = "1";
	}
}

/**
 * Function which sets time 00:00 in timepickers
 * when alldayevent checkbox is checked.
 */
function eventRecurrenceAllDayEvent(moduleObject, element, event)
{
	if (element.checked){
		moduleObject.appo_start.setValue(0);
		moduleObject.appo_end.setValue(0);
	}
}