private void EffectDropped(Guid effectGuid, TimeSpan startTime, Row row)
        {
            //Modified 12-3-2014 to allow Control-Drop of effects to replace selected effects

            TimeSpan duration = TimeSpan.FromSeconds(2.0); // TODO: need a default value here. I suggest a per-effect default.
            //TimeSpan startTime = Util.Min(TimelineControl.PixelsToTime(location.X), (_sequence.Length - duration)); // Ensure the element is inside the grid.

            if (ModifierKeys.HasFlag(Keys.Control) && TimelineControl.SelectedElements.Any())
            {

                var message = string.Format("This action will replace {0} effects, are you sure ?",
                    TimelineControl.SelectedElements.Count());
                //messageBox Arguments are (Text, Title, No Button Visible, Cancel Button Visible)
                MessageBoxForm.msgIcon = SystemIcons.Warning; //this is used if you want to add a system icon to the message form.
                var messageBox = new MessageBoxForm(message, @"Replace existing effects?", true, false);
                messageBox.ShowDialog();
                if (messageBox.DialogResult == DialogResult.No)
                {
                    return;
                }

                var newEffects = (from elem in TimelineControl.SelectedElements let newEffectInstance = ApplicationServices.Get<IEffectModuleInstance>(effectGuid) select CreateEffectNode(newEffectInstance, elem.Row, elem.StartTime, elem.Duration)).ToList();

                RemoveSelectedElements();
                AddEffectNodes(newEffects);
                SelectEffectNodes(newEffects);

                //Add the undo action for the newly created effects
                var act = new EffectsAddedUndoAction(this, newEffects);
                _undoMgr.AddUndoAction(act);
            }
            else
            {
                AddNewEffectById(effectGuid, row, startTime, duration, true);
            }
        }
        protected void DrawElement(object sender, DrawElementEventArgs e)
        {
            //Make sure we have enough of an effect to show up
            if (e.Duration > TimeSpan.FromSeconds(.010))
            {
                var newEffects = new List<EffectNode>();
                foreach (Row drawingRow in e.Rows)
                {
                    var newEffect = ApplicationServices.Get<IEffectModuleInstance>(e.Guid);

                    try
                    {
                        newEffects.Add(CreateEffectNode(newEffect, drawingRow, e.StartTime, e.Duration));
                    }
                    catch (Exception ex)
                    {
                        string msg = "TimedSequenceEditor: <DrawElement> - error adding effect of type " +
                                     newEffect.Descriptor.TypeId + " to row " +
                                     ((drawingRow == null) ? "<null>" : drawingRow.Name);
                            Logging.Error(msg, ex);
                    }
                }
                AddEffectNodes(newEffects);
                SequenceModified();
                var act = new EffectsAddedUndoAction(this, newEffects);
                _undoMgr.AddUndoAction(act);
                SelectEffectNodes(newEffects);
            }
        }
        private List<Element> CloneElements(IEnumerable<Element> elements)
        {
            var newElements = new List<Element>();
            foreach (var element in elements)
            {
                var newEffect = ApplicationServices.Get<IEffectModuleInstance>(element.EffectNode.Effect.TypeId);
                newEffect.ModuleData = element.EffectNode.Effect.ModuleData.Clone();

                try
                {
                    // get the target element
                    if (element.Row != null)
                    {
                        var effectNode = CreateEffectNode(newEffect, element.Row, element.StartTime, element.Duration);
                        LayerManager.AssignEffectNodeToLayer(effectNode, LayerManager.GetLayer(element.EffectNode));
                        // put it in the sequence and in the timeline display
                        newElements.Add(AddEffectNode(effectNode));
                    }
                    else
                    {
                        Logging.Error("TimedSequenceEditor: <CloneElements> - Skipping element; element.Row is null!");

                    }

                } catch (Exception ex)
                {
                    string msg = "TimedSequenceEditor CloneElements: error adding effect of type " + newEffect.Descriptor.TypeId + " to row " +
                                 ((element.Row == null) ? "<null>" : element.Row.Name);
                    Logging.Error(msg, ex);
                }
            }

            SequenceModified();

            //Add elements as a group to undo
            var act = new EffectsAddedUndoAction(this, newElements.Select(x => x.EffectNode).ToArray());
            _undoMgr.AddUndoAction(act);

            return newElements;
        }
        private void AddMultipleEffects(TimeSpan startTime, String effectName, Guid effectId, Row row)
        {
            var eDialog = new Form_AddMultipleEffects();
            if (ModifierKeys == (Keys.Shift | Keys.Control) && _amLastEffectCount > 0)
            {
                eDialog.EffectCount = _amLastEffectCount;
                eDialog.StartTime = _amLastStartTime;
                eDialog.Duration = _amLastDuration;
                eDialog.DurationBetween = _amLastDurationBetween;
            }
            else
            {
                eDialog.EffectCount = 2;
                eDialog.StartTime = startTime;
                eDialog.Duration = TimeSpan.FromSeconds(2);
                eDialog.DurationBetween = TimeSpan.FromSeconds(2);
            }
            eDialog.EffectName = effectName;
            eDialog.SequenceLength = eDialog.EndTime = SequenceLength;
            eDialog.MarkCollections = _sequence.MarkCollections;
            eDialog.ShowDialog();

            if (eDialog.DialogResult == DialogResult.OK)
            {
                _amLastEffectCount = eDialog.EffectCount;
                _amLastStartTime = eDialog.StartTime;
                _amLastDuration = eDialog.Duration;
                _amLastDurationBetween = eDialog.DurationBetween;

                var newEffects = new List<EffectNode>();

                if (eDialog.AlignToBeatMarks)
                {
                    newEffects = AddEffectsToBeatMarks(eDialog.CheckedMarks, eDialog.EffectCount, effectId, eDialog.StartTime, eDialog.Duration, row, eDialog.FillDuration, eDialog.SkipEOBeat);
                }
                else
                {
                    TimeSpan nextStartTime = eDialog.StartTime;
                    for (int i = 0; i < eDialog.EffectCount; i++)
                    {
                        if (nextStartTime + eDialog.Duration > SequenceLength)
                        {
                            //if something went wrong in the forms calculations
                            break;
                        }

                        var newEffect = ApplicationServices.Get<IEffectModuleInstance>(effectId);
                        try
                        {
                            newEffects.Add(CreateEffectNode(newEffect, row, nextStartTime, eDialog.Duration));
                            nextStartTime = nextStartTime + eDialog.Duration + eDialog.DurationBetween;
                        }
                        catch (Exception ex)
                        {
                            string msg = "TimedSequenceEditor: <AddMultipleEffects> - error adding effect of type " + newEffect.Descriptor.TypeId + " to row " +
                                         ((row == null) ? "<null>" : row.Name);
                                Logging.Error(msg, ex);
                        }
                    }
                    AddEffectNodes(newEffects);
                    SequenceModified();
                    var act = new EffectsAddedUndoAction(this, newEffects);
                    _undoMgr.AddUndoAction(act);
                }
                if (newEffects.Count > 0)
                {
                    if (eDialog.SelectEffects) SelectEffectNodes(newEffects);
                }
            }
        }
        private List<EffectNode> AddEffectsToBeatMarks(ListView.CheckedListViewItemCollection checkedMarks, int effectCount, Guid effectGuid, TimeSpan startTime, TimeSpan duration, Row row, Boolean fillDuration, Boolean skipEoBeat)
        {
            bool skipThisBeat = false;

            List<TimeSpan> times = (from ListViewItem listItem in checkedMarks from mcItem in _sequence.MarkCollections where mcItem.Name == listItem.Text from mark in mcItem.Marks where mark >= startTime select mark).ToList();

            times.Sort();

            var newEffects = new List<EffectNode>();

            if (times.Count > 0)
            {
                foreach (TimeSpan mark in times)
                {
                    if (newEffects.Count < effectCount)
                    {
                        if (!skipThisBeat)
                        {
                            var newEffect = ApplicationServices.Get<IEffectModuleInstance>(effectGuid);
                            try
                            {
                                if (fillDuration)
                                {
                                    if (times.IndexOf(mark) == times.Count - 1) //The dialog hanles this, but just to make sure
                                        break; //We're done -- There are no more marks to fill, don't create it
                                    duration = times[times.IndexOf(mark) + 1] - mark;
                                    if (duration < TimeSpan.FromSeconds(.01)) duration = TimeSpan.FromSeconds(.01);
                                }
                                newEffects.Add(CreateEffectNode(newEffect, row, mark, duration));
                            }
                            catch (Exception ex)
                            {
                                string msg = "TimedSequenceEditor: <AddEffectsToBeatMarks> - error adding effect of type " + newEffect.Descriptor.TypeId + " to row " +
                                             ((row == null) ? "<null>" : row.Name);
                                Logging.Error(msg, ex);
                            }
                        }

                        if (skipEoBeat) skipThisBeat = (!skipThisBeat);
                    }
                    else
                        break; //We're done creating, we've matched counts
                }

                AddEffectNodes(newEffects);
                SequenceModified();
                var act = new EffectsAddedUndoAction(this, newEffects);
                _undoMgr.AddUndoAction(act);
            }

            return newEffects;
        }
        /// <summary>
        /// Wraps an effect instance in an EffectNode, adds it to the sequence, and an associated element to the timeline control.
        /// Adds a Undo record for the add as well.
        /// </summary>
        /// <param name="effectInstance">Effect instance</param>
        /// <param name="row">Common.Controls.Timeline.Row to add the effect instance to</param>
        /// <param name="startTime">The start time of the effect</param>
        /// <param name="timeSpan">The duration of the effect</param>
        /// <param name="select">Optional indicator to set as the sole selection in the timeline</param>
        private void AddEffectInstance(IEffectModuleInstance effectInstance, Row row, TimeSpan startTime, TimeSpan timeSpan, bool select = false)
        {
            try
            {
                //Debug.WriteLine("{0}   addEffectInstance(InstanceId={1})", (int)DateTime.Now.TimeOfDay.TotalMilliseconds, effectInstance.InstanceId);

                if ((startTime + timeSpan) > SequenceLength)
                {
                    timeSpan = SequenceLength - startTime;
                }

                var effectNode = CreateEffectNode(effectInstance, row, startTime, timeSpan);
                // put it in the sequence and in the timeline display
                Element element = AddEffectNode(effectNode);
                if (select)
                {
                    TimelineControl.grid.ClearSelectedElements();
                    TimelineControl.SelectElement(element);
                }
                SequenceModified();

                var act = new EffectsAddedUndoAction(this, new[] { effectNode });
                _undoMgr.AddUndoAction(act);
            }
            catch (Exception ex)
            {
                string msg = "TimedSequenceEditor: error adding effect of type " + effectInstance.Descriptor.TypeId + " to row " +
                             ((row == null) ? "<null>" : row.Name);
                Logging.Error(msg, ex);
            }
        }
		private List<Element> CloneElements(IEnumerable<Element> elements)
		{
			var newElements = new List<Element>();
			foreach (var element in elements)
			{
				var newEffect = ApplicationServices.Get<IEffectModuleInstance>(element.EffectNode.Effect.TypeId);
				newEffect.ModuleData = element.EffectNode.Effect.ModuleData.Clone();
				
				try
				{
					// get the target element
					if (element.Row != null)
					{
						var targetNode = (ElementNode) element.Row.Tag;

						// populate the given effect instance with the appropriate target node and times, and wrap it in an effectNode
						newEffect.TargetNodes = new[] {targetNode};
					}
					else
					{
						Logging.Error("TimedSequenceEditor: <CloneElements> - Skipping element; element.Row is null!");
						continue;
					}

					newEffect.TimeSpan = element.Duration;
					var effectNode = new EffectNode(newEffect, element.StartTime);

					// put it in the sequence and in the timeline display
					newElements.Add(AddEffectNode(effectNode));
					

				} catch (Exception ex)
				{
					string msg = "TimedSequenceEditor CloneElements: error adding effect of type " + newEffect.Descriptor.TypeId + " to row " +
								 ((element.Row == null) ? "<null>" : element.Row.Name);
					Logging.Error(msg, ex);
				}
			}

			SequenceModified();

			//Add elements as a group to undo
			var act = new EffectsAddedUndoAction(this, newElements.Select(x => x.EffectNode).ToArray());
			_undoMgr.AddUndoAction(act);

			return newElements;
		}