/// <summary>
		/// Store the given <see cref="Trigger" />.
		/// </summary>
		/// <param name="ctxt">The scheduling context.</param>
		/// <param name="newTrigger">The <see cref="Trigger" /> to be stored.</param>
		/// <param name="replaceExisting">If <see langword="true" />, any <see cref="Trigger" /> existing in
		/// the <see cref="IJobStore" /> with the same name and group should
		/// be over-written.</param>
		public virtual void StoreTrigger(SchedulingContext ctxt, Trigger newTrigger, bool replaceExisting)
		{
            TriggerWrapper tw = new TriggerWrapper((Trigger)newTrigger.Clone());

			if (triggersByFQN[tw.key] != null)
			{
				if (!replaceExisting)
				{
					throw new ObjectAlreadyExistsException(newTrigger);
				}

                // don't delete orphaned job, this trigger has the job anyways
				RemoveTrigger(ctxt, newTrigger.Name, newTrigger.Group, false);
			}

			if (RetrieveJob(ctxt, newTrigger.JobName, newTrigger.JobGroup) == null)
			{
				throw new JobPersistenceException("The job (" + newTrigger.FullJobName +
				                                  ") referenced by the trigger does not exist.");
			}

			lock (triggerLock)
			{
				// add to triggers array
				triggers.Add(tw);

				// add to triggers by group
				IDictionary grpMap = (Hashtable) triggersByGroup[newTrigger.Group];
				if (grpMap == null)
				{
					grpMap = new Hashtable(100);
					triggersByGroup[newTrigger.Group] = grpMap;
				}
				grpMap[newTrigger.Name] = tw;
				// add to triggers by FQN map
				triggersByFQN[tw.key] = tw;

                if (pausedTriggerGroups.Contains(newTrigger.Group) || pausedJobGroups.Contains(newTrigger.JobGroup))
                {
                    tw.state = InternalTriggerState.Paused;
                    if (blockedJobs.Contains(tw.jobKey))
                    {
                        tw.state = InternalTriggerState.PausedAndBlocked;
                    }
                }
                else if (blockedJobs.Contains(tw.jobKey))
                {
                    tw.state = InternalTriggerState.Blocked;
                }
                else
                {
                    timeTriggers.Add(tw);
                }
			}
		}
		/// <summary>
		/// Applies the misfire.
		/// </summary>
		/// <param name="tw">The trigger wrapper.</param>
		/// <returns></returns>
		protected internal virtual bool ApplyMisfire(TriggerWrapper tw)
		{
			DateTime misfireTime = DateTime.UtcNow;
			if (MisfireThreshold > TimeSpan.Zero)
			{
				misfireTime = misfireTime.AddMilliseconds(-1 * MisfireThreshold.TotalMilliseconds);
			}

            NullableDateTime tnft = tw.trigger.GetNextFireTimeUtc();
            if (!tnft.HasValue || tnft.Value > misfireTime)
			{
				return false;
			}

			ICalendar cal = null;
			if (tw.trigger.CalendarName != null)
			{
				cal = RetrieveCalendar(null, tw.trigger.CalendarName);
			}

			signaler.NotifyTriggerListenersMisfired(tw.trigger);

			tw.trigger.UpdateAfterMisfire(cal);

			if (!tw.trigger.GetNextFireTimeUtc().HasValue)
			{
                tw.state = InternalTriggerState.Complete;
                signaler.NotifySchedulerListenersFinalized(tw.trigger);
				lock (triggerLock)
				{
					timeTriggers.Remove(tw);
				}
			}
			else if (tnft.Equals(tw.trigger.GetNextFireTimeUtc()))
			{
				return false;
			}

			return true;
		}