org.gege.caldavsyncadapter.caldav.entities.CalendarEvent.java Source code

Java tutorial

Introduction

Here is the source code for org.gege.caldavsyncadapter.caldav.entities.CalendarEvent.java

Source

/**
 * Copyright (c) 2012-2013, Gerald Garcia, Timo Berger
 * 
 * This file is part of Andoid Caldav Sync Adapter Free.
 *
 * Andoid Caldav Sync Adapter Free 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 3 of the 
 * License, or at your option any later version.
 *
 * Andoid Caldav Sync Adapter Free 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 Andoid Caldav Sync Adapter Free.  
 * If not, see <http://www.gnu.org/licenses/>.
 * 
 */

package org.gege.caldavsyncadapter.caldav.entities;

import java.io.IOException;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URL;
import java.net.URLDecoder;
import java.text.ParseException;
import java.util.ArrayList;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import net.fortuna.ical4j.data.CalendarBuilder;
import net.fortuna.ical4j.data.ParserException;
import net.fortuna.ical4j.model.Calendar;
import net.fortuna.ical4j.model.Component;
import net.fortuna.ical4j.model.ComponentList;
import net.fortuna.ical4j.model.DateTime;
import net.fortuna.ical4j.model.Dur;
import net.fortuna.ical4j.model.Parameter;
import net.fortuna.ical4j.model.ParameterList;
import net.fortuna.ical4j.model.Property;
import net.fortuna.ical4j.model.PropertyList;
import net.fortuna.ical4j.model.TimeZone;
import net.fortuna.ical4j.model.component.VEvent;
import net.fortuna.ical4j.model.component.VTimeZone;
import net.fortuna.ical4j.model.parameter.Cn;
import net.fortuna.ical4j.model.parameter.CuType;
import net.fortuna.ical4j.model.parameter.PartStat;
import net.fortuna.ical4j.model.parameter.Role;
import net.fortuna.ical4j.model.property.Clazz;
import net.fortuna.ical4j.model.property.Status;
import net.fortuna.ical4j.util.CompatibilityHints;

import org.apache.http.client.ClientProtocolException;
import org.gege.caldavsyncadapter.Event;
import org.gege.caldavsyncadapter.android.entities.AndroidEvent;
import org.gege.caldavsyncadapter.caldav.CaldavFacade;
import org.gege.caldavsyncadapter.caldav.CaldavProtocolException;
import org.gege.caldavsyncadapter.caldav.xml.MultiStatusHandler;
import org.gege.caldavsyncadapter.caldav.xml.sax.MultiStatus;
import org.gege.caldavsyncadapter.caldav.xml.sax.Prop;
import org.gege.caldavsyncadapter.caldav.xml.sax.PropStat;
import org.gege.caldavsyncadapter.caldav.xml.sax.Response;
import org.gege.caldavsyncadapter.syncadapter.SyncAdapter;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

import android.accounts.Account;
import android.content.ContentProviderClient;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.SyncStats;
import android.database.Cursor;
import android.net.Uri;
import android.os.RemoteException;
import android.provider.CalendarContract.Attendees;
import android.provider.CalendarContract.Calendars;
import android.provider.CalendarContract.Events;
import android.provider.CalendarContract.Reminders;
import android.util.Log;

public class CalendarEvent extends org.gege.caldavsyncadapter.Event {
    private static final String TAG = "CalendarEvent";

    private String stringIcs;

    private Calendar calendar;

    private Component calendarComponent;

    private String eTag;
    private URI muri;
    private Uri mAndroidEventUri;
    public URL calendarURL;

    private boolean mAllDay = false;
    private VTimeZone mVTimeZone = null;
    private TimeZone mTimeZone = null;

    private String mstrTimeZoneStart = "";
    private String mstrTimeZoneEnd = "";

    private Account mAccount = null;
    private ContentProviderClient mProvider = null;

    public CalendarEvent(Account account, ContentProviderClient provider) {
        this.mAccount = account;
        this.mProvider = provider;
    }

    public String getETag() {
        return eTag;
    }

    public void setETag(String eTag) {
        this.eTag = eTag;
    }

    public URI getUri() {
        return muri;
    }

    public void setUri(URI uri) {
        this.muri = uri;
    }

    public void setICSasString(String ics) {
        this.stringIcs = ics;
    }

    public boolean setICSasMultiStatus(String stringMultiStatus) {
        boolean Result = false;
        String ics = "";
        MultiStatus multistatus;
        ArrayList<Response> responselist;
        Response response;
        PropStat propstat;
        Prop prop;
        try {
            SAXParserFactory factory = SAXParserFactory.newInstance();
            SAXParser parser = factory.newSAXParser();
            XMLReader reader = parser.getXMLReader();
            MultiStatusHandler contentHandler = new MultiStatusHandler();
            reader.setContentHandler(contentHandler);
            reader.parse(new InputSource(new StringReader(stringMultiStatus)));

            multistatus = contentHandler.mMultiStatus;
            if (multistatus != null) {
                responselist = multistatus.ResponseList;
                if (responselist.size() == 1) {
                    response = responselist.get(0);
                    //HINT: bugfix for google calendar
                    if (response.href.equals(this.getUri().getPath().replace("@", "%40"))) {
                        propstat = response.propstat;
                        if (propstat.status.contains("200 OK")) {
                            prop = propstat.prop;
                            ics = prop.calendardata;
                            this.setETag(prop.getetag);
                            Result = true;
                        }
                    }
                }
            }
        } catch (ParserConfigurationException e1) {
            e1.printStackTrace();
        } catch (SAXException e1) {
            e1.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        this.stringIcs = ics;
        return Result;
    }

    /**
     * sets the Uri of the android event
     * @param uri
     * @see org.gege.caldavsyncadapter.syncadapter.SyncAdapter#createAndroidEvent(ContentProviderClient provider, Account account, Uri calendarUri, CalendarEvent calendarEvent)
     * @see org.gege.caldavsyncadapter.syncadapter.SyncAdapter#updateAndroidEvent(ContentProviderClient provider, Account account, AndroidEvent androidEvent, CalendarEvent calendarEvent)
     */
    public void setAndroidEventUri(Uri uri) {
        mAndroidEventUri = uri;
    }

    /**
     * gets the Uri of the android event
     * @return
     */
    public Uri getAndroidEventUri() {
        return mAndroidEventUri;
    }

    /**
     * reads all ContentValues from the caldav source
     * @param calendarUri
     * @return
     * @see org.gege.caldavsyncadapter.syncadapter.SyncAdapter#createAndroidEvent(ContentProviderClient provider, Account account, Uri calendarUri, CalendarEvent calendarEvent)
     * @see org.gege.caldavsyncadapter.syncadapter.SyncAdapter#updateAndroidEvent(ContentProviderClient provider, Account account, AndroidEvent androidEvent, CalendarEvent calendarEvent)
     */
    public boolean readContentValues() {
        this.ContentValues.put(Events.DTSTART, this.getStartTime());
        this.ContentValues.put(Events.EVENT_TIMEZONE, this.getTimeZoneStart());

        //if (this.getRRule().isEmpty() && this.getRDate().isEmpty()) {
        if (this.getRRule() == null && this.getRDate() == null) {
            //if (AllDay.equals(1)) //{
            //   values.put(Events.ALL_DAY, AllDay);
            //} else {
            this.ContentValues.put(Events.DTEND, this.getEndTime());
            this.ContentValues.put(Events.EVENT_END_TIMEZONE, this.getTimeZoneEnd());
            //}
        } else {
            //if (AllDay.equals(1))
            //   values.put(Events.ALL_DAY, AllDay);
            this.ContentValues.put(Events.DURATION, this.getDuration());
        }
        int AllDay = this.getAllDay();
        this.ContentValues.put(Events.ALL_DAY, AllDay);

        this.ContentValues.put(Events.TITLE, this.getTitle());
        //this.ContentValues.put(Events.CALENDAR_ID, ContentUris.parseId(calendarUri));
        this.ContentValues.put(Events._SYNC_ID, this.getUri().toString());
        this.ContentValues.put(ETAG, this.getETag());
        this.ContentValues.put(Events.DESCRIPTION, this.getDescription());
        this.ContentValues.put(Events.EVENT_LOCATION, this.getLocation());
        this.ContentValues.put(Events.ACCESS_LEVEL, this.getAccessLevel());
        this.ContentValues.put(Events.STATUS, this.getStatus());
        this.ContentValues.put(Events.RDATE, this.getRDate());
        this.ContentValues.put(Events.RRULE, this.getRRule());
        this.ContentValues.put(Events.EXRULE, this.getExRule());
        this.ContentValues.put(Events.EXDATE, this.getExDate());
        this.ContentValues.put(UID, this.getUid());
        this.ContentValues.put(RAWDATA, this.stringIcs);

        return true;
    }

    /**
     * receives a single event and parses its content
     * @return success of this function
     * @see CalendarEvent#parseIcs()
     * @throws ClientProtocolException
     * @throws IOException
     * @throws CaldavProtocolException
     * @throws ParserException
     */
    public boolean fetchBody()
            throws ClientProtocolException, IOException, CaldavProtocolException, ParserException {
        boolean Error = false;

        //replaced fetchEvent() with getEvent()
        //CaldavFacade.fetchEvent(this);
        CaldavFacade.getEvent(this);

        boolean Parse = this.parseIcs();
        if (!Parse)
            Error = true;

        return !Error;
    }

    public java.util.ArrayList<ContentValues> getReminders() {
        java.util.ArrayList<ContentValues> Result = new java.util.ArrayList<ContentValues>();
        ContentValues Reminder;

        /*
         * http://sourceforge.net/tracker/?func=detail&aid=3021704&group_id=107024&atid=646395
         */

        net.fortuna.ical4j.model.component.VEvent event = (VEvent) this.calendarComponent;

        //ComponentList ComList = this.calendar.getComponents(Component.VALARM);
        ComponentList ComList = event.getAlarms();

        if (ComList != null) {
            for (Object objCom : ComList) {
                Component Com = (Component) objCom;
                Reminder = new ContentValues();

                //Property ACTION = Com.getProperty("ACTION");
                Property TRIGGER = Com.getProperty("TRIGGER");
                if (TRIGGER != null) {
                    Dur Duration = new Dur(TRIGGER.getValue());
                    //if (ACTION.getValue().equals("DISPLAY"))

                    int intDuration = Duration.getMinutes() + Duration.getHours() * 60
                            + Duration.getDays() * 60 * 24;

                    Reminder.put(Reminders.EVENT_ID, ContentUris.parseId(mAndroidEventUri));
                    Reminder.put(Reminders.METHOD, Reminders.METHOD_ALERT);
                    Reminder.put(Reminders.MINUTES, intDuration);

                    Result.add(Reminder);
                }
            }
        }
        return Result;
    }

    public java.util.ArrayList<ContentValues> getAttandees() {
        java.util.ArrayList<ContentValues> Result = new java.util.ArrayList<ContentValues>();
        ContentValues Attendee;
        PropertyList Propertys = calendarComponent.getProperties(Property.ATTENDEE);
        if (Propertys != null) {
            for (Object objProperty : Propertys) {
                Property property = (Property) objProperty;
                Attendee = ReadAttendeeProperties(property, Property.ATTENDEE);
                if (Attendee != null)
                    Result.add(Attendee);
            }
        }
        Propertys = calendarComponent.getProperties(Property.ORGANIZER);
        if (Propertys != null) {
            for (Object objProperty : Propertys) {
                Property property = (Property) objProperty;
                Attendee = ReadAttendeeProperties(property, Property.ORGANIZER);
                if (Attendee != null)
                    Result.add(Attendee);
            }
        }

        return Result;
    }

    private String mstrcIcalPropertyError = "net.fortunal.ical4j.invalid:";

    private ContentValues ReadAttendeeProperties(Property property, String Type) {
        ContentValues Attendee = null;

        ParameterList Parameters = property.getParameters();
        Parameter CN = Parameters.getParameter(Cn.CN);
        Parameter ROLE = Parameters.getParameter(Role.ROLE);
        Parameter CUTYPE = Parameters.getParameter(CuType.CUTYPE);
        //Parameter RSVP     = Parameters.getParameter("RSVP");
        Parameter PARTSTAT = Parameters.getParameter(PartStat.PARTSTAT);

        String strCN = "";
        String strROLE = "";
        String strCUTYPE = "";
        String strValue = property.getValue().replace("mailto:", "");
        String strPARTSTAT = "";

        if (strValue.startsWith(mstrcIcalPropertyError)) {
            strValue = strValue.replace(mstrcIcalPropertyError, "");
            try {
                strValue = URLDecoder.decode(strValue, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }

        if (CN != null)
            strCN = CN.getValue();
        if (ROLE != null)
            strROLE = ROLE.getValue();
        if (CUTYPE != null)
            strCUTYPE = CUTYPE.getValue();
        if (PARTSTAT != null)
            strPARTSTAT = PARTSTAT.getValue();

        if (strCN.equals("")) {
            if (!strValue.equals("")) {
                strCN = strValue;
            }
        }

        if (!strCN.equals("")) {
            if (strCUTYPE.equals("") || strCUTYPE.equals("INDIVIDUAL")) {
                Attendee = new ContentValues();

                Attendee.put(Attendees.EVENT_ID, ContentUris.parseId(mAndroidEventUri));

                Attendee.put(Attendees.ATTENDEE_NAME, strCN);
                Attendee.put(Attendees.ATTENDEE_EMAIL, strValue);

                if (strROLE.equals("OPT-PARTICIPANT"))
                    Attendee.put(Attendees.ATTENDEE_TYPE, Attendees.TYPE_OPTIONAL);
                else if (strROLE.equals("NON-PARTICIPANT"))
                    Attendee.put(Attendees.ATTENDEE_TYPE, Attendees.TYPE_NONE);
                else if (strROLE.equals("REQ-PARTICIPANT"))
                    Attendee.put(Attendees.ATTENDEE_TYPE, Attendees.TYPE_REQUIRED);
                else if (strROLE.equals("CHAIR"))
                    Attendee.put(Attendees.ATTENDEE_TYPE, Attendees.TYPE_REQUIRED);
                else
                    Attendee.put(Attendees.ATTENDEE_TYPE, Attendees.TYPE_NONE);

                if (Type.equals(Property.ATTENDEE))
                    Attendee.put(Attendees.ATTENDEE_RELATIONSHIP, Attendees.RELATIONSHIP_ATTENDEE);
                else if (Type.equals(Property.ORGANIZER))
                    Attendee.put(Attendees.ATTENDEE_RELATIONSHIP, Attendees.RELATIONSHIP_ORGANIZER);
                else
                    Attendee.put(Attendees.ATTENDEE_RELATIONSHIP, Attendees.RELATIONSHIP_NONE);

                if (strPARTSTAT.equals(PartStat.NEEDS_ACTION.getValue()))
                    Attendee.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_INVITED);
                else if (strPARTSTAT.equals(PartStat.ACCEPTED.getValue()))
                    Attendee.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_ACCEPTED);
                else if (strPARTSTAT.equals(PartStat.DECLINED.getValue()))
                    Attendee.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_DECLINED);
                else if (strPARTSTAT.equals(PartStat.COMPLETED.getValue()))
                    Attendee.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_NONE);
                else if (strPARTSTAT.equals(PartStat.TENTATIVE.getValue()))
                    Attendee.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_TENTATIVE);
                else
                    Attendee.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_INVITED);

            }
        }

        return Attendee;
    }

    private long getAccessLevel() {
        long Result = Events.ACCESS_DEFAULT;
        String Value = "";
        Property property = calendarComponent.getProperty(Property.CLASS);
        if (property != null) {
            Value = property.getValue();
            if (Value.equals(Clazz.PUBLIC))
                Result = Events.ACCESS_PUBLIC;
            else if (Value.equals(Clazz.PRIVATE))
                Result = Events.ACCESS_PRIVATE;
            else if (Value.equals(Clazz.CONFIDENTIAL))
                Result = Events.ACCESS_PRIVATE; // should be ACCESS_CONFIDENTIAL, but is not implemented within Android
        }

        return Result;
    }

    private int getStatus() {
        int Result = -1;
        String Value = "";
        Property property = calendarComponent.getProperty(Property.STATUS);
        if (property != null) {
            Value = property.getValue();
            if (Value.equals(Status.VEVENT_CONFIRMED.getValue()))
                Result = Events.STATUS_CONFIRMED;
            else if (Value.equals(Status.VEVENT_CANCELLED.getValue()))
                Result = Events.STATUS_CANCELED;
            else if (Value.equals(Status.VEVENT_TENTATIVE.getValue()))
                Result = Events.STATUS_TENTATIVE;
        }

        return Result;
    }

    private String getDescription() {
        String Result = null;
        Property property = calendarComponent.getProperty(Property.DESCRIPTION);
        if (property != null)
            Result = property.getValue();

        return Result;
    }

    private String getLocation() {
        String Result = null;
        Property property = calendarComponent.getProperty(Property.LOCATION);
        if (property != null)
            Result = property.getValue();

        return Result;
    }

    private String getTitle() {
        Property property = calendarComponent.getProperty(Property.SUMMARY);
        if (property != null)
            return property.getValue();
        else
            return "**unkonwn**";
    }

    private String getRRule() {
        String Result = null;
        Property property = calendarComponent.getProperty(Property.RRULE);
        if (property != null)
            Result = property.getValue();

        return Result;
    }

    private String getExRule() {
        String Result = null;
        Property property = calendarComponent.getProperty(Property.EXRULE);
        if (property != null)
            Result = property.getValue();

        return Result;
    }

    private String getRDate() {
        String Result = null;

        java.util.ArrayList<String> ExDates = this.getRDates();
        for (String Value : ExDates) {
            if (Result == null)
                Result = "";
            if (!Result.isEmpty())
                Result += ",";
            Result += Value;
        }

        return Result;
    }

    private java.util.ArrayList<String> getRDates() {
        java.util.ArrayList<String> Result = new java.util.ArrayList<String>();
        PropertyList Propertys = calendarComponent.getProperties(Property.RDATE);
        if (Propertys != null) {
            Property property;
            for (Object objProperty : Propertys) {
                property = (Property) objProperty;
                Result.add(property.getValue());
            }
        }

        return Result;
    }

    private String getExDate() {
        String Result = null;

        java.util.ArrayList<String> ExDates = this.getExDates();
        for (String Value : ExDates) {
            if (Result == null)
                Result = "";
            if (!Result.isEmpty())
                Result += ",";
            Result += Value;
        }

        return Result;
    }

    private java.util.ArrayList<String> getExDates() {
        java.util.ArrayList<String> Result = new java.util.ArrayList<String>();
        PropertyList Propertys = calendarComponent.getProperties(Property.EXDATE);
        if (Propertys != null) {
            Property property;
            for (Object objProperty : Propertys) {
                property = (Property) objProperty;
                Result.add(property.getValue());
            }
        }

        return Result;
    }

    private String getUid() {
        String Result = "";
        Property prop = calendarComponent.getProperty(Property.UID);
        if (prop != null) {
            Result = prop.getValue();
        }

        return Result;
    }

    private Long getTimestamp(Property prop) {
        Long Result = null;
        String strTimeZone = "";
        //TimeZone timeZone = null;

        try {
            String strDate = prop.getValue();

            Parameter parAllDay = prop.getParameter("VALUE");
            if (parAllDay != null) {
                if (parAllDay.getValue().equals("DATE")) {
                    mAllDay = true;
                    strDate += "T000000Z";
                }
            }

            Parameter propTZ = prop.getParameter(Property.TZID);
            if (propTZ != null)
                strTimeZone = propTZ.getValue();

            //TimeZoneRegistry registry = TimeZoneRegistryFactory.getInstance().createRegistry();
            //if (!strTimeZone.equals(""))
            //   timeZone = registry.getTimeZone(strTimeZone);

            //if (timeZone != null) {
            if (!strTimeZone.equals("")) {
                //Result = new DateTime(strDate, timeZone);
                //Result1 = Result.getTime();

                //20130331T120000
                int Year = Integer.parseInt(strDate.substring(0, 4));
                int Month = Integer.parseInt(strDate.substring(4, 6)) - 1;
                int Day = Integer.parseInt(strDate.substring(6, 8));
                int Hour = Integer.parseInt(strDate.substring(9, 11));
                int Minute = Integer.parseInt(strDate.substring(11, 13));
                int Second = Integer.parseInt(strDate.substring(13, 15));

                // time in UTC
                java.util.TimeZone jtz = java.util.TimeZone.getTimeZone("UTC");
                java.util.Calendar cal = java.util.GregorianCalendar.getInstance(jtz);
                cal.set(Year, Month, Day, Hour, Minute, Second);
                cal.set(java.util.Calendar.MILLISECOND, 0);
                Result = cal.getTimeInMillis();

                // get the timezone
                String[] IDs = java.util.TimeZone.getAvailableIDs();
                Boolean Found = false;
                for (int i = 0; i < IDs.length; i++) {
                    Found = Found || IDs[i].equals(strTimeZone);
                }
                if (Found) {
                    jtz = java.util.TimeZone.getTimeZone(strTimeZone);

                    // subtract the offset
                    Result -= jtz.getRawOffset();

                    // remove dst
                    if (jtz.inDaylightTime(new java.util.Date(Result)))
                        Result -= jtz.getDSTSavings();

                } else {
                    if (mTimeZone != null) {
                        // subtract the offset
                        Result -= mTimeZone.getRawOffset();

                        // remove dst
                        if (mTimeZone.inDaylightTime(new java.util.Date(Result)))
                            Result -= mTimeZone.getDSTSavings();
                    } else {
                        // unknown Time?
                        // treat as local time, should not happen too often :)
                        Result = new DateTime(strDate).getTime();
                    }
                }
            } else {
                if (strDate.endsWith("Z")) {
                    // GMT or UTC
                    Result = new DateTime(strDate).getTime();
                } else {
                    // unknown Time?
                    // treat as local time, should not happen too often :)
                    Result = new DateTime(strDate).getTime();
                }
            }

        } catch (ParseException e) {
            e.printStackTrace();
        }

        return Result;
    }

    private long getStartTime() {
        long Result = 0;
        Property prop;
        /*
         * DTSTART;TZID=Europe/Berlin:20120425T080000
         * DTSTART;TZID=(GMT+01.00) Sarajevo/Warsaw/Zagreb:20120305T104500
         * DTSTART:20120308T093000Z
         * DTSTART;VALUE=DATE:20120709
         * DTSTART;TZID=Europe/Berlin:20130330T100000
         */

        prop = calendarComponent.getProperty(Property.DTSTART);
        if (prop != null) {
            Parameter propTZ = prop.getParameter(Property.TZID);
            if (propTZ != null)
                mstrTimeZoneStart = propTZ.getValue();
            Result = getTimestamp(prop);
        }

        return Result;
    }

    private long getEndTime() {
        long Result = 0;
        Property propDtEnd;
        Property propDuration;

        propDtEnd = calendarComponent.getProperty(Property.DTEND);
        propDuration = calendarComponent.getProperty(Property.DURATION);
        if (propDtEnd != null) {
            Parameter propTZ = propDtEnd.getParameter(Property.TZID);
            if (propTZ != null)
                mstrTimeZoneEnd = propTZ.getValue();
            Result = getTimestamp(propDtEnd);

        } else if (propDuration != null) {
            Result = 0;
            long Start = this.getStartTime();
            String strDuration = propDuration.getValue();
            Dur dur = new Dur(strDuration);
            Result = Start + dur.getSeconds() * 1000 + dur.getMinutes() * 60 * 1000
                    + dur.getHours() * 60 * 60 * 1000 + dur.getDays() * 60 * 60 * 24 * 1000;

            mstrTimeZoneEnd = mstrTimeZoneStart;
        }

        return Result;
    }

    private String getTimeZoneStart() {
        String Result = "GMT";

        if (!mstrTimeZoneStart.equals("")) {
            Result = mstrTimeZoneStart;
        }

        return Result;
    }

    private String getTimeZoneEnd() {
        String Result = "GMT";

        if (!mstrTimeZoneEnd.equals("")) {
            Result = mstrTimeZoneEnd;
        }

        return Result;
    }

    private String getDuration() {
        String Result = "";
        Property prop = calendarComponent.getProperty("DURATION");

        if (prop != null) {
            //DURATION:PT1H
            Result = prop.getValue();
        } else {
            // no DURATION given by this event. we have to calculate it by ourself
            Result = "P";
            long Start = this.getStartTime();
            long End = this.getEndTime();
            long Duration = 0;
            if (End != 0)
                Duration = (End - Start) / 1000; // get rid of the milliseconds, they cann't be described with RFC2445-Duration

            int Days = (int) Math.ceil(Duration / 24 / 60 / 60);
            int Hours = (int) Math.ceil((Duration - (Days * 24 * 60 * 60)) / 60 / 60);
            int Minutes = (int) Math.ceil((Duration - (Days * 24 * 60 * 60) - (Hours * 60 * 60)) / 60);
            int Seconds = (int) (Duration - (Days * 24 * 60 * 60) - (Hours * 60 * 60) - (Minutes * 60));

            if (Days > 0)
                Result += String.valueOf(Days) + "D";

            if (!mAllDay) {
                //if a ALL_DAY event occurs, there is no need for hours, minutes and seconds (Android doesn't understand them)
                Result += "T";
                Result += String.valueOf(Hours) + "H";
                Result += String.valueOf(Minutes) + "M";
                Result += String.valueOf(Seconds) + "S";
            }
        }

        return Result;
    }

    private int getAllDay() {
        int Result = 0;

        if (mAllDay)
            Result = 1;

        return Result;
    }

    /**
     * opens the first items of the event
     * @return success of this function
     * @see AndroidEvent#createIcs()
     * @see CalendarEvent#fetchBody()
     * @throws CaldavProtocolException
     * @throws IOException
     * @throws ParserException
     */
    private boolean parseIcs() throws CaldavProtocolException, IOException, ParserException {
        boolean Error = false;

        CalendarBuilder builder = new CalendarBuilder();
        CompatibilityHints.setHintEnabled(CompatibilityHints.KEY_RELAXED_UNFOLDING, true);
        CompatibilityHints.setHintEnabled(CompatibilityHints.KEY_RELAXED_PARSING, true);
        CompatibilityHints.setHintEnabled(CompatibilityHints.KEY_RELAXED_VALIDATION, true);
        CompatibilityHints.setHintEnabled(CompatibilityHints.KEY_OUTLOOK_COMPATIBILITY, true);

        StringReader reader = new StringReader(this.stringIcs);
        try {
            this.calendar = builder.build(reader);
        } catch (ParserException ex) {
            // ical4j fails with this: "Cannot set timezone for UTC properties"
            // CREATED;TZID=America/New_York:20130129T140250
            Error = true;
        }

        if (!Error) {
            ComponentList components = null;
            components = this.calendar.getComponents(Component.VEVENT);
            if (components.size() == 0) {
                components = this.calendar.getComponents(Component.VTODO);
                if (components.size() == 0) {
                    throw new CaldavProtocolException("unknown events in ICS");
                } else {
                    Log.e(TAG, "unsupported event TODO in ICS");
                    Error = true;
                }
            } else if (components.size() > 1) {
                Log.e(TAG, "Several events in ICS -> only first will be processed");
            }

            // get the TimeZone information
            Component mCom = this.calendar.getComponent(Component.VTIMEZONE);
            if (mCom != null)
                mVTimeZone = (VTimeZone) this.calendar.getComponent(Component.VTIMEZONE);
            if (mVTimeZone != null)
                mTimeZone = new TimeZone(mVTimeZone);

            if (!Error)
                calendarComponent = (Component) components.get(0);
        }

        return !Error;
    }

    /**
     * searches for an android event
     * @param androidCalendar
     * @return the android event
     * @throws RemoteException
     */
    public AndroidEvent getAndroidEvent(DavCalendar androidCalendar) throws RemoteException {
        boolean Error = false;
        Uri uriEvents = Events.CONTENT_URI;
        Uri uriAttendee = Attendees.CONTENT_URI;
        Uri uriReminder = Reminders.CONTENT_URI;
        AndroidEvent androidEvent = null;

        String selection = "(" + Events._SYNC_ID + " = ?)";
        String[] selectionArgs = new String[] { this.getUri().toString() };
        Cursor curEvent = this.mProvider.query(uriEvents, null, selection, selectionArgs, null);

        Cursor curAttendee = null;
        Cursor curReminder = null;

        if (curEvent == null) {
            Error = true;
        }
        if (!Error) {
            if (curEvent.getCount() == 0) {
                Error = true;
            }
        }
        if (!Error) {
            curEvent.moveToNext();

            long EventID = curEvent.getLong(curEvent.getColumnIndex(Events._ID));
            Uri returnedUri = ContentUris.withAppendedId(uriEvents, EventID);

            androidEvent = new AndroidEvent(this.mAccount, this.mProvider, returnedUri,
                    androidCalendar.getAndroidCalendarUri());
            androidEvent.readContentValues(curEvent);

            selection = "(" + Attendees.EVENT_ID + " = ?)";
            selectionArgs = new String[] { String.valueOf(EventID) };
            curAttendee = this.mProvider.query(uriAttendee, null, selection, selectionArgs, null);
            selection = "(" + Reminders.EVENT_ID + " = ?)";
            selectionArgs = new String[] { String.valueOf(EventID) };
            curReminder = this.mProvider.query(uriReminder, null, selection, selectionArgs, null);
            androidEvent.readAttendees(curAttendee);
            androidEvent.readReminder(curReminder);
            curAttendee.close();
            curReminder.close();
        }
        curEvent.close();

        return androidEvent;
    }

    /**
     * creates a new androidEvent from a given calendarEvent
     * @param androidCalendar
     * @return
     * @throws ClientProtocolException
     * @throws IOException
     * @throws CaldavProtocolException
     * @throws RemoteException
     * @throws ParserException
     * @see {@link SyncAdapter#synchroniseEvents(CaldavFacade, Account, ContentProviderClient, Uri, DavCalendar, SyncStats)}
     */
    public boolean createAndroidEvent(DavCalendar androidCalendar)
            throws ClientProtocolException, IOException, CaldavProtocolException, RemoteException, ParserException {
        boolean Result = false;
        boolean BodyFetched = this.fetchBody();
        int CountAttendees = 0;
        int CountReminders = 0;

        if (BodyFetched) {
            //calendarEvent.readContentValues(calendarUri);
            this.readContentValues();
            this.setAndroidCalendarId(ContentUris.parseId(androidCalendar.getAndroidCalendarUri()));

            Uri uri = this.mProvider.insert(
                    asSyncAdapter(Events.CONTENT_URI, this.mAccount.name, this.mAccount.type), this.ContentValues);
            this.setAndroidEventUri(uri);

            Log.d(TAG, "Creating calendar event for " + uri.toString());

            //check the attendees
            java.util.ArrayList<ContentValues> AttendeeList = this.getAttandees();
            for (ContentValues Attendee : AttendeeList) {
                this.mProvider.insert(Attendees.CONTENT_URI, Attendee);
                CountAttendees += 1;
            }

            //check the reminders
            java.util.ArrayList<ContentValues> ReminderList = this.getReminders();
            for (ContentValues Reminder : ReminderList) {
                this.mProvider.insert(Reminders.CONTENT_URI, Reminder);
                CountReminders += 1;
            }

            if ((CountAttendees > 0) || (CountReminders > 0)) {
                //the events gets dirty when attendees or reminders were added
                AndroidEvent androidEvent = this.getAndroidEvent(androidCalendar);

                androidEvent.ContentValues.put(Events.DIRTY, 0);
                int RowCount = this.mProvider.update(
                        asSyncAdapter(androidEvent.getUri(), this.mAccount.name, this.mAccount.type),
                        androidEvent.ContentValues, null, null);
                Result = (RowCount == 1);
            } else {
                Result = true;
            }

        }
        return Result;
    }

    /**
     * the android event is getting updated
     * @param provider
     * @param account
     * @param androidEvent
     * @param calendarEvent
     * @return
     * @throws ClientProtocolException
     * @throws IOException
     * @throws CaldavProtocolException
     * @throws RemoteException
     * @throws ParserException
     * @see {@link SyncAdapter#synchroniseEvents(CaldavFacade, Account, ContentProviderClient, Uri, Calendar, SyncStats)}
     */
    public boolean updateAndroidEvent(AndroidEvent androidEvent)
            throws ClientProtocolException, IOException, CaldavProtocolException, RemoteException, ParserException {
        boolean BodyFetched = this.fetchBody();
        int Rows = 0;

        if (BodyFetched) {
            this.readContentValues();
            this.setAndroidCalendarId(androidEvent.getAndroidCalendarId());
            this.setAndroidEventUri(androidEvent.getUri());

            Log.d(TAG, "AndroidEvent is dirty: " + androidEvent.ContentValues.getAsString(Events.DIRTY));

            if (androidEvent.checkEventValuesChanged(this.ContentValues)) {
                // just set the raw data from server event into android event
                if (androidEvent.ContentValues.containsKey(Event.RAWDATA))
                    androidEvent.ContentValues.remove(Event.RAWDATA);
                androidEvent.ContentValues.put(Event.RAWDATA, this.ContentValues.getAsString(Event.RAWDATA));

                //update the attendees and reminders
                this.updateAndroidAttendees();
                this.updateAndroidReminder();

                androidEvent.ContentValues.put(Events.DIRTY, 0); // the event is now in sync
                Log.d(TAG, "Update calendar event: for " + androidEvent.getUri());

                Rows = mProvider.update(asSyncAdapter(androidEvent.getUri(), mAccount.name, mAccount.type),
                        androidEvent.ContentValues, null, null);
                //Log.i(TAG, "Updated calendar event: rows effected " + Rows.toString());
            } else {
                Log.d(TAG, "Update calendar event not needed: for " + androidEvent.getUri());
            }
        }
        return (Rows == 1);
    }

    /**
     * updates the attendees from a calendarEvent to its androidEvent.
     * the calendarEvent has to know its androidEvent via {@link CalendarEvent#setAndroidEventUri(Uri)}
     * @param provider
     * @return
     * @see SyncAdapter#updateAndroidEvent(ContentProviderClient, Account, AndroidEvent, CalendarEvent)
     */
    private boolean updateAndroidAttendees() {
        boolean Result = false;

        try {
            String mSelectionClause = "(" + Attendees.EVENT_ID + " = ?)";
            String[] mSelectionArgs = { Long.toString(ContentUris.parseId(this.getAndroidEventUri())) };
            int RowDelete;
            RowDelete = this.mProvider.delete(Attendees.CONTENT_URI, mSelectionClause, mSelectionArgs);
            Log.d(TAG, "Attendees Deleted:" + String.valueOf(RowDelete));

            java.util.ArrayList<ContentValues> AttendeeList = this.getAttandees();
            for (ContentValues Attendee : AttendeeList) {
                this.mProvider.insert(Attendees.CONTENT_URI, Attendee);
            }
            Log.d(TAG, "Attendees Inserted:" + String.valueOf(AttendeeList.size()));
            Result = true;
        } catch (RemoteException e) {
            e.printStackTrace();
        }

        return Result;
    }

    /**
     * update the reminders from a calendarEvent to its androidEvent.
     * the calendarEvent has to know its androidEvent via {@link CalendarEvent#setAndroidEventUri(Uri)}
     * @param provider
     * @return
     * @see SyncAdapter#updateAndroidEvent(ContentProviderClient, Account, AndroidEvent, CalendarEvent)
     */
    private boolean updateAndroidReminder() {
        boolean Result = false;

        try {
            String mSelectionClause = "(" + Reminders.EVENT_ID + " = ?)";
            String[] mSelectionArgs = { Long.toString(ContentUris.parseId(this.getAndroidEventUri())) };
            int RowDelete;
            RowDelete = this.mProvider.delete(Reminders.CONTENT_URI, mSelectionClause, mSelectionArgs);
            Log.d(TAG, "Reminders Deleted:" + String.valueOf(RowDelete));

            Uri ReminderUri;
            java.util.ArrayList<ContentValues> ReminderList = this.getReminders();
            for (ContentValues Reminder : ReminderList) {
                ReminderUri = this.mProvider.insert(Reminders.CONTENT_URI, Reminder);
                System.out.println(ReminderUri);
            }
            Log.d(TAG, "Reminders Inserted:" + String.valueOf(ReminderList.size()));

            Result = true;
        } catch (RemoteException e) {
            e.printStackTrace();
        }

        return Result;
    }

    private static Uri asSyncAdapter(Uri uri, String account, String accountType) {
        return uri.buildUpon().appendQueryParameter(android.provider.CalendarContract.CALLER_IS_SYNCADAPTER, "true")
                .appendQueryParameter(Calendars.ACCOUNT_NAME, account)
                .appendQueryParameter(Calendars.ACCOUNT_TYPE, accountType).build();
    }
}