/// <summary> 
        /// Add the <see cref="IJob" /> identified by the given
        /// <see cref="JobDetail" /> to the Scheduler, and
        /// associate the given <see cref="Trigger" /> with it.
        /// <p>
        /// If the given Trigger does not reference any <see cref="IJob" />, then it
        /// will be set to reference the Job passed with it into this method.
        /// </p>
        /// </summary>
        public virtual DateTime ScheduleJob(SchedulingContext ctxt, JobDetail jobDetail, Trigger trigger)
        {
            ValidateState();


            if (jobDetail == null)
            {
                throw new SchedulerException("JobDetail cannot be null",
                        SchedulerException.ErrorClientError);
            }

            if (trigger == null)
            {
                throw new SchedulerException("Trigger cannot be null",
                        SchedulerException.ErrorClientError);
            }

            jobDetail.Validate();

            if (trigger.JobName == null)
            {
                trigger.JobName = jobDetail.Name;
                trigger.JobGroup = jobDetail.Group;
            }
            else if (trigger.JobName != null && !trigger.JobName.Equals(jobDetail.Name))
            {
                throw new SchedulerException("Trigger does not reference given job!", SchedulerException.ErrorClientError);
            }
            else if (trigger.JobGroup != null && !trigger.JobGroup.Equals(jobDetail.Group))
            {
                throw new SchedulerException("Trigger does not reference given job!", SchedulerException.ErrorClientError);
            }

            trigger.Validate();

            ICalendar cal = null;
            if (trigger.CalendarName != null)
            {
                cal = resources.JobStore.RetrieveCalendar(ctxt, trigger.CalendarName);
                if (cal == null)
                {
                    throw new SchedulerException(string.Format(CultureInfo.InvariantCulture, "Calendar not found: {0}", trigger.CalendarName),
                                                 SchedulerException.ErrorPersistenceCalendarDoesNotExist);
                }
            }

            NullableDateTime ft = trigger.ComputeFirstFireTimeUtc(cal);

            if (!ft.HasValue)
            {
                throw new SchedulerException("Based on configured schedule, the given trigger will never fire.",
                                             SchedulerException.ErrorClientError);
            }

            resources.JobStore.StoreJobAndTrigger(ctxt, jobDetail, trigger);
            NotifySchedulerThread(trigger.GetNextFireTimeUtc());
            NotifySchedulerListenersScheduled(trigger);

            return ft.Value;
        }