private FreeBusyCollection createFreeBusyFromEvents(
            List<DateTimeRange> syncEvents,
            List<DateTimeRange> exchEvents)
        {
            FreeBusyCollection result = new FreeBusyCollection();
            foreach (DateTimeRange r in syncEvents)
            {
                AddFreeBusyBlock(result, r, true);
            }

            foreach (DateTimeRange r in exchEvents)
            {
                AddFreeBusyBlock(result, r, false);
            }
            return result;
        }
        private void AddFreeBusyBlock(
            FreeBusyCollection result,
            DateTimeRange eventRange,
            bool existingEvent)
        {
            FreeBusyTimeBlock block = new FreeBusyTimeBlock(eventRange);
            Appointment appt = new Appointment();
            appt.StartDate = eventRange.Start;
            appt.EndDate = eventRange.End;
            appt.BusyStatus = BusyStatus.Busy;

            if (existingEvent)
            {
                AssignOwnership(appt);
            }

            block.Appointments.Add(appt);
            result.Appointments.Add(appt);
            result[eventRange.Start] = block;
        }
        void dump(FreeBusyCollection fbc)
        {
            Console.WriteLine("Begin FreeBusyCollection");

            foreach (KeyValuePair<DateTime, FreeBusyTimeBlock> pair in fbc)
            {
                DateTime dt = pair.Key;
                FreeBusyTimeBlock b = pair.Value;
                Console.WriteLine("{0}: {1} -> {2} [{3}]",
                    dt, b.StartDate, b.EndDate, b.Appointments.Count );
            }
            Console.WriteLine("End FreeBusyCollection");
        }
        /// <summary>
        /// Ctor for an Exchange user from an Active Directory ResultSet
        /// </summary>
        /// <param name="properties">Active Directory propertes</param>
        public ExchangeUser(ResultPropertyCollection properties)
        {
            this.accountName = GetFirstString(properties["sAMAccountName"]);
            this.mailnickname = GetFirstString(properties["mailnickname"]);
            this.proxyAddresses = GetPrimarySmtpAddress( properties );
            this.email = GetFirstString(properties["mail"]);
            this.commonName = GetFirstString(properties["CN"]);
            this.legacyExchangeDN = GetFirstString( properties[ "legacyExchangeDN" ] );
            this.DN = GetFirstString(properties["distinguishedName"]);
            this.objectClasses = GetStringList(properties["objectclass"]);
            this.displayName = GetFirstString(properties["displayName"]);

            this.freeBusyCommonName = parseFreeBusyCommonName(legacyExchangeDN);
            this.busyTimesBlocks = new FreeBusyCollection();

            AdjustAccountName();
            Validate();
        }
        private static void ConvertFreeBusyToBlocks(
            DateTimeRange window,
            List<DateTimeRange> ranges,
            FreeBusyCollection times,
            IntervalTree<FreeBusyTimeBlock> intervals)
        {
            foreach (DateTimeRange range in ranges)
            {
                /* If the free busy date is between the start and end dates request */
                if (DateUtil.IsWithinRange(range.Start, window.Start, window.End) ||
                    DateUtil.IsWithinRange(range.End, window.Start, window.End))
                {
                    /* Add the a new FreeBusyTimeBlock to the collection,
                     * Set the key to the start date of the block */
                    FreeBusyTimeBlock block = new FreeBusyTimeBlock(range);

                    if (!times.ContainsKey(range.Start))
                    {
                        times.Add(range.Start, block);
                        intervals.Insert(range, block);
                    }
                }
            }
        }
        /// <summary>
        /// Combines the free busy and appointment blocks supplied to the exchange user object
        /// If no appointments are supplied the user will still have free busy time blocks assigned
        /// to them, with a null appointment assigned to the free busy time.
        /// </summary>
        /// <param name="exchangeUser">Exchange users to apply freeBusy and appointments</param>
        /// <param name="freeBusy">The collection of FreeBusy blocks to assign to exchangeUser</param>
        /// <param name="appointments">The collection of appointment blocks to assign to exchangeUser</param>
        /// <param name="window">Window to merge for</param>
        protected void MergeFreeBusyWithAppointments(
            ExchangeUser exchangeUser,
            FreeBusy freeBusy,
            List<Appointment> appointments,
            DateTimeRange window)
        {
            using (BlockTimer bt = new BlockTimer("MergeFreeBusyWithAppointments"))
            {
                IntervalTree<FreeBusyTimeBlock> busyIntervals =
                    new IntervalTree<FreeBusyTimeBlock>();
                FreeBusyCollection busyTimes = new FreeBusyCollection();
                int appointmentsCount = 0;
                List<DateTimeRange> combinedTimes =
                    FreeBusyConverter.MergeFreeBusyLists(freeBusy.All, freeBusy.Tentative);

                /* Add the date ranges from each collection in the FreeBusy object */
                ConvertFreeBusyToBlocks(window,
                                        combinedTimes,
                                        busyTimes,
                                        busyIntervals);

                if (appointments != null && appointments.Count > 0)
                {
                    appointmentsCount = appointments.Count;
                    foreach (Appointment appt in appointments)
                    {
                        log.DebugFormat("Appt \"{0}\" {1} {2} response = {3} status = {4} busy = {5}",
                                        appt.Subject,
                                        appt.Range,
                                        appt.StartDate.Kind,
                                        appt.ResponseStatus,
                                        appt.MeetingStatus,
                                        appt.BusyStatus);

                        if (appt.BusyStatus == BusyStatus.Free)
                        {
                            continue;
                        }

                        DateTimeRange range = new DateTimeRange(appt.StartDate, appt.EndDate);
                        List<FreeBusyTimeBlock> result =
                            busyIntervals.FindAll(range, IntervalTreeMatch.Overlap);

                        log.DebugFormat("Found {0} ranges overlap {1}", result.Count, range);

                        foreach (FreeBusyTimeBlock block in result)
                        {
                            log.DebugFormat("Adding \"{0}\" to FB {1} {2}",
                                            appt.Subject,
                                            block.Range,
                                            block.StartDate.Kind);
                            block.Appointments.Add(appt);
                        }

                        busyTimes.Appointments.Add(appt);
                    }
                }

                foreach (FreeBusyTimeBlock block in busyTimes.Values)
                {
                    block.Appointments.Sort(CompareAppointmentsByRanges);
                }

                log.InfoFormat("Merge Result of {0} + Appointment {1} -> {2}",
                               combinedTimes.Count,
                               appointmentsCount,
                               busyTimes.Count);

                /* Assign the data structure to the exchange user */
                exchangeUser.BusyTimes = busyTimes;
            }
        }