#pragma warning disable 1634, 1691
namespace System.Workflow.ComponentModel.Design
{
    using System;
    using System.IO;
    using System.Drawing;
    using System.CodeDom;
    using System.Diagnostics;
    using System.Collections;
    using System.Collections.Generic;
    using System.Windows.Forms;
    using System.ComponentModel;
    using System.Globalization;
    using System.Drawing.Design;
    using System.Drawing.Imaging;
    using System.Drawing.Drawing2D;
    using System.Windows.Forms.Design;
    using System.ComponentModel.Design;
    using System.Collections.Specialized;
    using System.ComponentModel.Design.Serialization;
    using System.Workflow.ComponentModel.Compiler;
    using System.Workflow.ComponentModel.Serialization;
    using System.Collections.ObjectModel;
    using System.Reflection;
    using System.Workflow.ComponentModel.Design;
    using System.Runtime.Serialization.Formatters.Binary;

    //

    #region CompositeActivityDesigner Class
    /// <summary>
    /// CompositeActivityDesigner provides a designer which allows user to visually design composite activities in the design mode. 
    /// CompositeActivityDesigner enables the user to customize layouting, drawing associated with the CompositeActivity, it also allows
    /// managing the layouting, drawing and eventing for the contained activity designers.
    /// </summary>
    [ActivityDesignerTheme(typeof(CompositeDesignerTheme))]
    [SRCategory("CompositeActivityDesigners", "System.Workflow.ComponentModel.Design.DesignerResources")]
    [DesignerSerializer(typeof(CompositeActivityDesignerLayoutSerializer), typeof(WorkflowMarkupSerializer))]
    [Obsolete("The System.Workflow.* types are deprecated.  Instead, please use the new types from System.Activities.*")]
    public abstract class CompositeActivityDesigner : ActivityDesigner
    {
        #region Fields
        private const string CF_DESIGNER = "CF_WINOEDESIGNERCOMPONENTS";
        private const string CF_DESIGNERSTATE = "CF_WINOEDESIGNERCOMPONENTSSTATE";
        private const int MaximumCharsPerLine = 8;
        private const int MaximumTextLines = 1;

        private Size actualTextSize = Size.Empty;
        private CompositeDesignerAccessibleObject accessibilityObject;
        private List<ActivityDesigner> containedActivityDesigners;
        private bool expanded = true;
        #endregion

        #region Construction / Destruction
        /// <summary>
        /// Default constructor for CompositeActivityDesigner
        /// </summary>
        protected CompositeActivityDesigner()
        {
        }
        #endregion

        #region Properties

        #region Public Properties
        /// <summary>
        /// Gets if the activity associated with designer is structurally locked that is no activities can be added to it.
        /// </summary>
        public bool IsEditable
        {
            get
            {
                if (!(Activity is CompositeActivity))
                    return false;

                if (IsLocked)
                    return false;

                if (Helpers.IsCustomActivity(Activity as CompositeActivity))
                    return false;

                return true;
            }
        }

        /// <summary>
        /// Gets if the designer can be collapsed, collapsed designer has expand/collapse button added to it
        /// </summary>
        public virtual bool CanExpandCollapse
        {
            get
            {
                return !IsRootDesigner;
            }
        }

        /// <summary>
        /// Gets or Sets if the designer currently in expanded state
        /// </summary>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public virtual bool Expanded
        {
            get
            {
                if (!CanExpandCollapse && !this.expanded)
                    Expanded = true;
                return this.expanded;
            }

            set
            {
                if (this.expanded == value)
                    return;

                //If the designer can not expand or collapse then we need to make sure that
                //user does not collapse it
                if (!CanExpandCollapse && !value)
                    return;

                this.expanded = value;

                PerformLayout();
            }
        }

        /// <summary>
        /// Gets the array of activity designer contained within.
        /// </summary>
        public virtual ReadOnlyCollection<ActivityDesigner> ContainedDesigners
        {
            get
            {
                List<ActivityDesigner> designers = new List<ActivityDesigner>();

                CompositeActivity compositeActivity = Activity as CompositeActivity;
                if (compositeActivity != null)
                {
                    if (this.containedActivityDesigners == null)
                    {
                        bool foundAllDesigners = true;

                        //In certain cases users might try to access the activity designers
                        //in Initialize method of composite activity. In that case the child activities
                        //might not be inserted in the container. If this happens then we might not get the 
                        //designer of the contained activity. When such a case happens we should not buffer the
                        //designers as it might lead to erroneous results
                        foreach (Activity activity in compositeActivity.Activities)
                        {
                            ActivityDesigner activityDesigner = ActivityDesigner.GetDesigner(activity);
                            if (activityDesigner != null)
                                designers.Add(activityDesigner);
                            else
                                foundAllDesigners = false;
                        }

                        if (foundAllDesigners)
                            this.containedActivityDesigners = designers;
                    }
                    else
                    {
                        designers = this.containedActivityDesigners;
                    }
                }

                return designers.AsReadOnly();
            }
        }

        /// <summary>
        /// Gets the first selectable object in the navigation order.
        /// </summary>
        public virtual object FirstSelectableObject
        {
            get
            {
                return null;
            }
        }

        /// <summary>
        /// Gets the last selected object in the navigation order
        /// </summary>
        public virtual object LastSelectableObject
        {
            get
            {
                return null;
            }
        }

        public override AccessibleObject AccessibilityObject
        {
            get
            {
                if (this.accessibilityObject == null)
                    this.accessibilityObject = new CompositeDesignerAccessibleObject(this);
                return this.accessibilityObject;
            }
        }

        public override Point Location
        {
            get
            {
                return base.Location;
            }

            set
            {
                ///If designers's location changes then we need to change location of children
                if (base.Location == value)
                    return;

                Size moveDelta = new Size(value.X - base.Location.X, value.Y - base.Location.Y);
                foreach (ActivityDesigner activityDesigner in ContainedDesigners)
                    activityDesigner.Location = new Point(activityDesigner.Location.X + moveDelta.Width, activityDesigner.Location.Y + moveDelta.Height);

                base.Location = value;
            }
        }
        #endregion

        #region Protected Properties
        /// <summary>
        /// Gets the rectangle associated with expand/collapse button
        /// </summary>
        protected virtual Rectangle ExpandButtonRectangle
        {
            get
            {
                if (!CanExpandCollapse)
                    return Rectangle.Empty;

                CompositeDesignerTheme designerTheme = DesignerTheme as CompositeDesignerTheme;
                if (designerTheme == null)
                    return Rectangle.Empty;

                Size textSize = TextRectangle.Size;
                Size imageSize = (Image != null) ? designerTheme.ImageSize : Size.Empty;
                Rectangle bounds = Bounds;

                Size anchorSize = (!textSize.IsEmpty) ? textSize : imageSize;
                Rectangle expandButtonRectangle = new Rectangle(bounds.Location, designerTheme.ExpandButtonSize);
                expandButtonRectangle.X += (bounds.Width - ((3 * designerTheme.ExpandButtonSize.Width / 2) + anchorSize.Width)) / 2;
                expandButtonRectangle.Y += 2 * WorkflowTheme.CurrentTheme.AmbientTheme.Margin.Height;
                if (anchorSize.Height > expandButtonRectangle.Height)
                    expandButtonRectangle.Y += (anchorSize.Height - expandButtonRectangle.Height) / 2;
                return expandButtonRectangle;
            }
        }

        /// <summary>
        /// Gets the height for the title area of the designer, typically this can contain the heading, icon and expand/collapse button
        /// </summary>
        protected virtual int TitleHeight
        {
            get
            {
                Size margin = WorkflowTheme.CurrentTheme.AmbientTheme.Margin;
                Rectangle expandButtonRectangle = ExpandButtonRectangle;
                Rectangle textRectangle = TextRectangle;
                Rectangle imageRectangle = ImageRectangle;

                int titleHeight = 0;
                if (!textRectangle.Size.IsEmpty)
                {
                    titleHeight = Math.Max(expandButtonRectangle.Height, textRectangle.Height);
                    titleHeight += imageRectangle.Height;
                }
                else
                {
                    titleHeight = Math.Max(expandButtonRectangle.Height, imageRectangle.Height);
                }

                if (!expandButtonRectangle.Size.IsEmpty || !textRectangle.Size.IsEmpty || !imageRectangle.Size.IsEmpty)
                    titleHeight += (Expanded ? 2 : 3) * margin.Height;

                if (!imageRectangle.Size.IsEmpty && !textRectangle.Size.IsEmpty)
                    titleHeight += margin.Height;

                return titleHeight;
            }
        }

        protected override Rectangle ImageRectangle
        {
            get
            {
                if (Image == null)
                    return Rectangle.Empty;

                CompositeDesignerTheme designerTheme = DesignerTheme as CompositeDesignerTheme;
                if (designerTheme == null)
                    return Rectangle.Empty;

                Rectangle bounds = Bounds;
                Size expandButtonSize = ExpandButtonRectangle.Size;
                Size imageSize = designerTheme.ImageSize;
                Size textSize = TextRectangle.Size;
                Size margin = WorkflowTheme.CurrentTheme.AmbientTheme.Margin;

                Rectangle imageRectangle = new Rectangle(bounds.Location, imageSize);
                if (textSize.Width > 0)
                {
                    imageRectangle.X += (bounds.Width - imageSize.Width) / 2;
                }
                else
                {
                    imageRectangle.X += (bounds.Width - (imageSize.Width + 3 * expandButtonSize.Width / 2)) / 2;
                    imageRectangle.X += 3 * expandButtonSize.Width / 2;
                }

                imageRectangle.Y += 2 * margin.Height;
                if (textSize.Height > 0)
                    imageRectangle.Y += textSize.Height + margin.Height;
                return imageRectangle;
            }
        }

        protected override Rectangle TextRectangle
        {
            get
            {
                if (String.IsNullOrEmpty(Text))
                    return Rectangle.Empty;

                CompositeDesignerTheme designerTheme = DesignerTheme as CompositeDesignerTheme;
                if (designerTheme == null)
                    return Rectangle.Empty;

                Rectangle bounds = Bounds;
                Size margin = WorkflowTheme.CurrentTheme.AmbientTheme.Margin;
                Size expandButtonSize = (CanExpandCollapse) ? designerTheme.ExpandButtonSize : Size.Empty;

                //Calculate the text size
                int maxAvailableWidth = bounds.Width - (2 * margin.Width + 3 * expandButtonSize.Width / 2);

                Size requestedLineSize = this.actualTextSize;
                requestedLineSize.Width /= Text.Length;
                requestedLineSize.Width += ((requestedLineSize.Width % Text.Length) > 0) ? 1 : 0;
                requestedLineSize.Width *= Math.Min(Text.Length, CompositeActivityDesigner.MaximumCharsPerLine - 1);

                Size textSize = Size.Empty;
                textSize.Width = Math.Min(maxAvailableWidth, this.actualTextSize.Width);
                textSize.Width = Math.Max(1, Math.Max(textSize.Width, requestedLineSize.Width));

                textSize.Height = requestedLineSize.Height;
                int textLines = this.actualTextSize.Width / textSize.Width;
                textLines += ((this.actualTextSize.Width % textSize.Width) > 0) ? 1 : 0;
                textLines = Math.Min(textLines, CompositeActivityDesigner.MaximumTextLines);
                textSize.Height *= textLines;

                //Calculate the text rectangle
                Rectangle textRectangle = new Rectangle(bounds.Location, textSize);
                textRectangle.X += (bounds.Width - (3 * expandButtonSize.Width / 2 + textSize.Width)) / 2;
                textRectangle.X += 3 * expandButtonSize.Width / 2;
                textRectangle.Y += 2 * margin.Height;
                if (expandButtonSize.Height > textSize.Height)
                    textRectangle.Y += (expandButtonSize.Height - textSize.Height) / 2;
                textRectangle.Size = textSize;
                return textRectangle;
            }
        }

        protected internal override ActivityDesignerGlyphCollection Glyphs
        {
            get
            {
                ActivityDesignerGlyphCollection glyphs = new ActivityDesignerGlyphCollection();
                glyphs.AddRange(base.Glyphs);

                CompositeDesignerTheme compositeTheme = DesignerTheme as CompositeDesignerTheme;
                if (compositeTheme != null && compositeTheme.ShowDropShadow)
                    glyphs.Add(ShadowGlyph.Default);

                return glyphs;
            }
        }
        #endregion

        #region Private Properties

        #region Properties used during serialization only
        //NOTE THAT THIS WILL ONLY BE USED FOR SERIALIZATION PURPOSES
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        internal List<ActivityDesigner> Designers
        {
            get
            {
                List<ActivityDesigner> childDesigners = new List<ActivityDesigner>();
                CompositeActivity compositeActivity = Activity as CompositeActivity;
                IDesignerHost host = GetService(typeof(IDesignerHost)) as IDesignerHost;
                if (host != null && compositeActivity != null)
                {
                    foreach (Activity childActivity in compositeActivity.Activities)
                    {
                        ActivityDesigner designer = host.GetDesigner(childActivity) as ActivityDesigner;
                        if (designer != null)
                            childDesigners.Add(designer);
                    }
                }

                return childDesigners;
            }
        }
        #endregion

        #endregion

        #endregion

        #region Methods

        #region Public Static Methods
        /// <summary>
        /// Inserts activities in specified composite activity designer by creating transaction
        /// </summary>
        /// <param name="compositeActivityDesigner">Designer in which to insert the activities</param>
        /// <param name="insertLocation">Insertion location</param>
        /// <param name="activitiesToInsert">Array of activities to insert</param>
        /// <param name="undoTransactionDescription">Text for the designer transaction which will be created</param>
        public static void InsertActivities(CompositeActivityDesigner compositeActivityDesigner, HitTestInfo insertLocation, ReadOnlyCollection<Activity> activitiesToInsert, string undoTransactionDescription)
        {
            if (compositeActivityDesigner == null)
                throw new ArgumentNullException("compositeActivityDesigner");

            if (compositeActivityDesigner.Activity == null ||
                compositeActivityDesigner.Activity.Site == null ||
                !(compositeActivityDesigner.Activity is CompositeActivity))
                throw new ArgumentException("compositeActivityDesigner");

            if (insertLocation == null)
                throw new ArgumentNullException("insertLocation");

            if (activitiesToInsert == null)
                throw new ArgumentNullException("activitiesToInsert");

            ISite site = compositeActivityDesigner.Activity.Site;

            // now insert the actual activities
            IDesignerHost designerHost = site.GetService(typeof(IDesignerHost)) as IDesignerHost;
            DesignerTransaction trans = null;
            if (designerHost != null && !string.IsNullOrEmpty(undoTransactionDescription))
                trans = designerHost.CreateTransaction(undoTransactionDescription);

            bool moveCase = false;
            try
            {
                //Detect if the activities are being moved or inserted
                foreach (Activity activity in activitiesToInsert)
                {
                    if (activity == null)
                        throw new ArgumentException("activitiesToInsert", SR.GetString(SR.Error_CollectionHasNullEntry));

                    moveCase = ((IComponent)activity).Site != null;
                    break;
                }

                //We purposely create a new instance of activities list so that we do not modify the original one
                if (moveCase)
                    compositeActivityDesigner.MoveActivities(insertLocation, activitiesToInsert);
                else
                    compositeActivityDesigner.InsertActivities(insertLocation, activitiesToInsert);

                if (trans != null)
                    trans.Commit();
            }
            catch (Exception e)
            {
                if (trans != null)
                    trans.Cancel();

                throw e;
            }

            //If we are just moving the activities then we do not need to emit the class
            //for scopes; only when we are adding the activities the class needs to be emitted for
            //scope in code beside file
            if (!moveCase)
            {
                // if everything was successful then generate classes correposnding to new scopes
                // get all the activities underneath the child activities
                ArrayList allActivities = new ArrayList();
                foreach (Activity activity in activitiesToInsert)
                {
                    allActivities.Add(activity);
                    if (activity is CompositeActivity)
                        allActivities.AddRange(Helpers.GetNestedActivities((CompositeActivity)activity));
                }
            }
        }

        /// <summary>
        /// Removes activities from designer by creating designer transaction
        /// </summary>
        /// <param name="serviceProvider">Service Provider associated to providing services</param>
        /// <param name="activitiesToRemove">Array of activities to remove</param>
        /// <param name="transactionDescription">Transaction text used to name the designer transaction</param>
        public static void RemoveActivities(IServiceProvider serviceProvider, ReadOnlyCollection<Activity> activitiesToRemove, string transactionDescription)
        {
            if (serviceProvider == null)
                throw new ArgumentNullException();

            if (activitiesToRemove == null)
                throw new ArgumentNullException("activitiesToRemove");

            Activity nextSelectableActivity = null;

            IDesignerHost designerHost = serviceProvider.GetService(typeof(IDesignerHost)) as IDesignerHost;
            DesignerTransaction trans = null;
            if (designerHost != null && !string.IsNullOrEmpty(transactionDescription))
                trans = designerHost.CreateTransaction(transactionDescription);

            try
            {
                foreach (Activity activity in activitiesToRemove)
                {
                    ActivityDesigner designer = ActivityDesigner.GetDesigner(activity);
                    if (designer != null)
                    {
                        CompositeActivityDesigner parentDesigner = designer.ParentDesigner;
                        if (parentDesigner != null)
                        {
                            nextSelectableActivity = DesignerHelpers.GetNextSelectableActivity(activity);
                            parentDesigner.RemoveActivities(new List<Activity>(new Activity[] { activity }).AsReadOnly());
                        }
                    }
                }

                if (trans != null)
                    trans.Commit();
            }
            catch
            {
                if (trans != null)
                    trans.Cancel();
                throw;
            }

            if (nextSelectableActivity != null && nextSelectableActivity.Site != null)
            {
                ISelectionService selectionService = nextSelectableActivity.Site.GetService(typeof(ISelectionService)) as ISelectionService;
                if (selectionService != null)
                    selectionService.SetSelectedComponents(new Activity[] { nextSelectableActivity }, SelectionTypes.Replace);
            }
        }

        public static IDataObject SerializeActivitiesToDataObject(IServiceProvider serviceProvider, Activity[] activities)
        {
            if (serviceProvider == null)
                throw new ArgumentNullException("serviceProvider");

            if (activities == null)
                throw new ArgumentNullException("activities");

            // get component serialization service
            ComponentSerializationService css = (ComponentSerializationService)serviceProvider.GetService(typeof(ComponentSerializationService));
            if (css == null)
                throw new InvalidOperationException(SR.GetString(SR.General_MissingService, typeof(ComponentSerializationService).Name));

            // serialize all activities to the store
            SerializationStore store = css.CreateStore();
            using (store)
            {
                foreach (Activity activity in activities)
                    css.Serialize(store, activity);
            }

            // wrap it with clipboard style object
            Stream stream = new MemoryStream();
            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(stream, store);
            stream.Seek(0, SeekOrigin.Begin);
            DataObject dataObject = new DataObject(CF_DESIGNER, stream);
            dataObject.SetData(CF_DESIGNERSTATE, Helpers.SerializeDesignersToStream(activities));
            return dataObject;
        }

        public static Activity[] DeserializeActivitiesFromDataObject(IServiceProvider serviceProvider, IDataObject dataObj)
        {
            return DeserializeActivitiesFromDataObject(serviceProvider, dataObj, false);
        }

        internal static Activity[] DeserializeActivitiesFromDataObject(IServiceProvider serviceProvider, IDataObject dataObj, bool addAssemblyReference)
        {
            if (serviceProvider == null)
                throw new ArgumentNullException("serviceProvider");

            if (dataObj == null)
                return new Activity[] { };

            IDesignerHost designerHost = (IDesignerHost)serviceProvider.GetService(typeof(IDesignerHost));
            if (designerHost == null)
                throw new InvalidOperationException(SR.GetString(SR.General_MissingService, typeof(IDesignerHost).Name));

            object data = dataObj.GetData(CF_DESIGNER);
            ICollection activities = null;

            if (data is Stream)
            {
                BinaryFormatter formatter = new BinaryFormatter();
                ((Stream)data).Seek(0, SeekOrigin.Begin);
                object serializationData = formatter.Deserialize((Stream)data);
                if (serializationData is SerializationStore)
                {
                    // get component serialization service
                    ComponentSerializationService css = serviceProvider.GetService(typeof(ComponentSerializationService)) as ComponentSerializationService;
                    if (css == null)
                        throw new Exception(SR.GetString(SR.General_MissingService, typeof(ComponentSerializationService).Name));

                    // deserialize data
                    activities = css.Deserialize((SerializationStore)serializationData);
                }
            }
            else
            {
                // Now check for a toolbox item.
                IToolboxService ts = (IToolboxService)serviceProvider.GetService(typeof(IToolboxService));
                if (ts != null && ts.IsSupported(dataObj, designerHost))
                {
                    ToolboxItem toolBoxItem = ts.DeserializeToolboxItem(dataObj, designerHost);
                    if (toolBoxItem != null)
                    {
                        activities = GetActivitiesFromToolboxItem(serviceProvider, addAssemblyReference, designerHost, activities, toolBoxItem);
                    }
                }
            }

            if (activities != null && Helpers.AreAllActivities(activities))
                return (Activity[])new ArrayList(activities).ToArray(typeof(Activity));
            else
                return new Activity[] { };
        }

        private static ICollection GetActivitiesFromToolboxItem(IServiceProvider serviceProvider, bool addAssemblyReference, IDesignerHost designerHost, ICollection activities, ToolboxItem toolBoxItem)
        {
            // this will make sure that we add the assembly reference to project
            if (addAssemblyReference && toolBoxItem.AssemblyName != null)
            {
                ITypeResolutionService trs = serviceProvider.GetService(typeof(ITypeResolutionService)) as ITypeResolutionService;
                if (trs != null)
                    trs.ReferenceAssembly(toolBoxItem.AssemblyName);
            }

            ActivityToolboxItem ActivityToolboxItem = toolBoxItem as ActivityToolboxItem;
            if (addAssemblyReference && ActivityToolboxItem != null)
                activities = ActivityToolboxItem.CreateComponentsWithUI(designerHost);
            else
                activities = toolBoxItem.CreateComponents(designerHost);
            return activities;
        }

        internal static Activity[] DeserializeActivitiesFromToolboxItem(IServiceProvider serviceProvider, ToolboxItem toolboxItem, bool addAssemblyReference)
        {
            if (serviceProvider == null)
                throw new ArgumentNullException("serviceProvider");

            IDesignerHost designerHost = (IDesignerHost)serviceProvider.GetService(typeof(IDesignerHost));
            if (designerHost == null)
                throw new InvalidOperationException(SR.GetString(SR.General_MissingService, typeof(IDesignerHost).Name));

            ICollection activities = null;

            if (toolboxItem != null)
            {
                activities = GetActivitiesFromToolboxItem(serviceProvider, addAssemblyReference, designerHost, activities, toolboxItem);
            }

            if (activities != null && Helpers.AreAllActivities(activities))
                return (Activity[])new ArrayList(activities).ToArray(typeof(Activity));
            else
                return new Activity[] { };
        }

        public static ActivityDesigner[] GetIntersectingDesigners(ActivityDesigner topLevelDesigner, Rectangle rectangle)
        {
            if (topLevelDesigner == null)
                throw new ArgumentNullException("topLevelDesigner");

            List<ActivityDesigner> intersectingDesigners = new List<ActivityDesigner>();

            if (!rectangle.IntersectsWith(topLevelDesigner.Bounds))
                return intersectingDesigners.ToArray();

            if (!topLevelDesigner.Bounds.Contains(rectangle))
                intersectingDesigners.Add(topLevelDesigner);

            if (topLevelDesigner is CompositeActivityDesigner)
            {
                Queue compositeDesigners = new Queue();
                compositeDesigners.Enqueue(topLevelDesigner);
                while (compositeDesigners.Count > 0)
                {
                    CompositeActivityDesigner compositeDesigner = compositeDesigners.Dequeue() as CompositeActivityDesigner;
                    if (compositeDesigner != null)
                    {
                        bool bDrawingVisibleChildren = false;

                        foreach (ActivityDesigner activityDesigner in compositeDesigner.ContainedDesigners)
                        {
                            if (activityDesigner.IsVisible && rectangle.IntersectsWith(activityDesigner.Bounds))
                            {
                                bDrawingVisibleChildren = true;

                                if (!activityDesigner.Bounds.Contains(rectangle))
                                    intersectingDesigners.Add(activityDesigner);

                                if (activityDesigner is CompositeActivityDesigner)
                                    compositeDesigners.Enqueue(activityDesigner);
                            }
                            else
                            {
                                if ((!(compositeDesigner is FreeformActivityDesigner)) && bDrawingVisibleChildren)
                                    break;
                            }
                        }
                    }
                }
            }
            return intersectingDesigners.ToArray();
        }
        #endregion

        #region Public Methods
        /// <summary>
        /// Checks if the activities can be inserted into the composite activity associated with the designer
        /// </summary>
        /// <param name="insertLocation">Location at which to insert activities</param>
        /// <param name="activitiesToInsert">Array of activities to be inserted</param>
        /// <returns>True of activities can be inserted, false otherwise</returns>
        public virtual bool CanInsertActivities(HitTestInfo insertLocation, ReadOnlyCollection<Activity> activitiesToInsert)
        {
            if (insertLocation == null)
                throw new ArgumentNullException("insertLocation");

            if (activitiesToInsert == null)
                throw new ArgumentNullException("activitiesToInsert");

            CompositeActivity compositeActivity = Activity as CompositeActivity;
            if (compositeActivity == null)
                return false;

            //If the activity state is locked then we can not insert activities.
            if (!IsEditable)
                return false;

            IExtendedUIService2 extendedUIService = this.GetService(typeof(IExtendedUIService2)) as IExtendedUIService2;

            foreach (Activity activity in activitiesToInsert)
            {
                if (activity == null)
                    throw new ArgumentException("activitiesToInsert", SR.GetString(SR.Error_CollectionHasNullEntry));

                if (extendedUIService != null)
                {
                    if (!extendedUIService.IsSupportedType(activity.GetType()))
                    {
                        return false;
                    }
                }

                if (activity is CompositeActivity && Helpers.IsAlternateFlowActivity(activity))
                    return false;

                ActivityDesigner designerToInsert = null;
#pragma warning disable 56506//bug in presharp, activity has already been checked for null value
                if (activity.Site != null)
                {
                    //get an existing designer
                    IDesignerHost designerHost = activity.Site.GetService(typeof(IDesignerHost)) as IDesignerHost;
                    designerToInsert = (designerHost != null) ? designerHost.GetDesigner((IComponent)activity) as ActivityDesigner : null;
                }
                else
                {
                    //we dont want to create a designer instance every time, so we'll cache it
                    //this is a fix for a perf issue - this function gets called in a loop when doing drag'n'drop operation
                    //from a toolbox
                    if (activity.UserData.Contains(typeof(ActivityDesigner)))
                    {
                        designerToInsert = activity.UserData[typeof(ActivityDesigner)] as ActivityDesigner;
                    }
                    else
                    {
                        //create a new one
                        designerToInsert = ActivityDesigner.CreateDesigner(Activity.Site, activity);
                        activity.UserData[typeof(ActivityDesigner)] = designerToInsert;
                    }
                }
#pragma warning restore 56506//bug in presharp

                if (designerToInsert == null)
                    return false;

                if (!designerToInsert.CanBeParentedTo(this))
                    return false;
            }

            return true;
        }

        /// <summary>
        /// Inserts activity at specified location within designer
        /// </summary>
        /// <param name="insertLocation">Location at which to insert activities</param>
        /// <param name="activitiesToInsert">Array of activities to insert</param>
        public virtual void InsertActivities(HitTestInfo insertLocation, ReadOnlyCollection<Activity> activitiesToInsert)
        {
            if (insertLocation == null)
                throw new ArgumentNullException("insertLocation");

            if (activitiesToInsert == null)
                throw new ArgumentNullException("activitiesToInsert");

            CompositeActivity compositeActivity = Activity as CompositeActivity;
            if (compositeActivity == null)
                throw new Exception(SR.GetString(SR.Error_DragDropInvalid));

            int index = insertLocation.MapToIndex();

            IIdentifierCreationService identifierCreationService = GetService(typeof(IIdentifierCreationService)) as IIdentifierCreationService;
            if (identifierCreationService != null)
                identifierCreationService.EnsureUniqueIdentifiers(compositeActivity, activitiesToInsert);
            else
                throw new InvalidOperationException(SR.GetString(SR.General_MissingService, typeof(IIdentifierCreationService).FullName));

            foreach (Activity activity in activitiesToInsert)
            {
                if (activity == null)
                    throw new ArgumentException("activitiesToInsert", SR.GetString(SR.Error_CollectionHasNullEntry));

                if (activity.Parent == null)
                {
                    compositeActivity.Activities.Insert(index++, activity);
                    WorkflowDesignerLoader.AddActivityToDesigner(Activity.Site, activity);
                }
            }

            // filter out unsupported Dependency properties
            foreach (Activity activity in activitiesToInsert)
            {
                Walker walker = new Walker();
                walker.FoundActivity += delegate(Walker w, WalkerEventArgs walkerEventArgs)
                {
                    ExtenderHelpers.FilterDependencyProperties(this.Activity.Site, walkerEventArgs.CurrentActivity);
                };
                walker.Walk(activity);
            }

        }

        /// <summary>
        /// Checks if the activities can be moved out from the composite activity associated with designer
        /// </summary>
        /// <param name="moveLocation">Location from which to move the activities</param>
        /// <param name="activitiesToMove">Array of activities to move</param>
        /// <returns></returns>
        public virtual bool CanMoveActivities(HitTestInfo moveLocation, ReadOnlyCollection<Activity> activitiesToMove)
        {
            if (moveLocation == null)
                throw new ArgumentNullException("moveLocation");

            if (activitiesToMove == null)
                throw new ArgumentNullException("activitiesToMove");

            //If the activity has locked structure then we do not allow user to move the activity out
            if (!IsEditable)
                return false;

            //Now go through all the movable activities and check if their position is locked
            foreach (Activity activity in activitiesToMove)
            {
                ActivityDesigner designer = ActivityDesigner.GetDesigner(activity);
                if (designer == null || designer.IsLocked)
                    return false;
            }

            return true;
        }

        /// <summary>
        /// Moves activities from one designer to other
        /// </summary>
        /// <param name="moveLocation">Location at which to move the activities</param>
        /// <param name="activitiesToMove">Array of activities to move</param>
        public virtual void MoveActivities(HitTestInfo moveLocation, ReadOnlyCollection<Activity> activitiesToMove)
        {
            if (moveLocation == null)
                throw new ArgumentNullException("moveLocation");

            if (activitiesToMove == null)
                throw new ArgumentNullException("activitiesToMove");

            //Make sure that we get the composite activity
            CompositeActivity compositeActivity = Activity as CompositeActivity;
            if (compositeActivity == null)
                throw new Exception(SR.GetString(SR.Error_DragDropInvalid));

            IIdentifierCreationService identifierCreationService = GetService(typeof(IIdentifierCreationService)) as IIdentifierCreationService;
            if (identifierCreationService == null)
                throw new InvalidOperationException(SR.GetString(SR.General_MissingService, typeof(IIdentifierCreationService).FullName));

            IDesignerHost designerHost = GetService(typeof(IDesignerHost)) as IDesignerHost;
            if (designerHost == null)
                throw new InvalidOperationException(SR.GetString(SR.General_MissingService, typeof(IDesignerHost).FullName));

            int index = moveLocation.MapToIndex();
            foreach (Activity activity in activitiesToMove)
            {
                ActivityDesigner designer = ActivityDesigner.GetDesigner(activity);
                if (designer != null)
                {
                    CompositeActivityDesigner parentDesigner = designer.ParentDesigner;
                    if (parentDesigner == this)
                    {
                        int originalIndex = compositeActivity.Activities.IndexOf(activity);
                        if (index > originalIndex)
                            index--;
                    }
                }

                //In some cases we might get activities which are added newly, in such cases we check if the activity
                //is existing activity or new one based on this decision we add it to the designer host.
                Debug.Assert(activity.Parent != null);
                CompositeActivity parentActivity = activity.Parent;
                int positionInParent = parentActivity.Activities.IndexOf(activity);
                activity.Parent.Activities.Remove(activity);

                //We need to make sure that the activity is going to have unique identifier
                //This might just cause problems
                identifierCreationService.EnsureUniqueIdentifiers(compositeActivity, new Activity[] { activity });

                //We do not need to read the activity in the designer host as this is move operation
                //assign unique temporary name to avoid conflicts 
                DesignerHelpers.UpdateSiteName(activity, "_activityonthemove_");
                CompositeActivity compositeActivityMoved = activity as CompositeActivity;
                if (compositeActivityMoved != null)
                {
                    int i = 1;
                    foreach (Activity nestedActivity in Helpers.GetNestedActivities(compositeActivityMoved))
                    {
                        DesignerHelpers.UpdateSiteName(nestedActivity, "_activityonthemove_" + i.ToString(CultureInfo.InvariantCulture));
                        i += 1;
                    }
                }

                try
                {
                    compositeActivity.Activities.Insert(index++, activity);
                }
                catch (Exception ex)
                {
                    // reconnect the activity
                    parentActivity.Activities.Insert(positionInParent, activity);

                    //

                    throw ex;
                }

                DesignerHelpers.UpdateSiteName(activity, activity.Name);
                if (compositeActivityMoved != null)
                {
                    foreach (Activity nestedActivity in Helpers.GetNestedActivities(compositeActivityMoved))
                        DesignerHelpers.UpdateSiteName(nestedActivity, nestedActivity.Name);
                }
            }

            // filter out unsupported Dependency properties and refresh propertyDescriptors
            foreach (Activity activity in activitiesToMove)
            {
                Walker walker = new Walker();
                walker.FoundActivity += delegate(Walker w, WalkerEventArgs walkerEventArgs)
                {
                    ExtenderHelpers.FilterDependencyProperties(this.Activity.Site, walkerEventArgs.CurrentActivity);
                    TypeDescriptor.Refresh(walkerEventArgs.CurrentActivity);
                };
                walker.Walk(activity);
            }
        }

        /// <summary>
        /// Checks if activities can be removed from the activity associated with the designer
        /// </summary>
        /// <param name="activitiesToRemove">Array of activities to remove</param>
        /// <returns>True of the activities can be removed, False otherwise.</returns>
        public virtual bool CanRemoveActivities(ReadOnlyCollection<Activity> activitiesToRemove)
        {
            if (activitiesToRemove == null)
                throw new ArgumentNullException("activitiesToRemove");

            if (!IsEditable)
                return false;

            foreach (Activity activity in activitiesToRemove)
            {
                ActivityDesigner designer = ActivityDesigner.GetDesigner(activity);
                if (designer == null || designer.IsLocked)
                    return false;
            }

            return true;
        }

        /// <summary>
        /// Removes activities from composite activity associated with the designer
        /// </summary>
        /// <param name="activitiesToRemove">Array of activities to remove</param>
        public virtual void RemoveActivities(ReadOnlyCollection<Activity> activitiesToRemove)
        {
            if (activitiesToRemove == null)
                throw new ArgumentNullException("activitiesToRemove");

            CompositeActivity compositeActivity = Activity as CompositeActivity;
            if (compositeActivity == null)
                throw new Exception(SR.GetString(SR.Error_DragDropInvalid));

            foreach (Activity activity in activitiesToRemove)
            {
                compositeActivity.Activities.Remove(activity);

                //Before we destroy the activity make sure that the references it and its child activities store to its parent
                //are set to null or else an undo unit will be created
                //For details look at,
                //\\cpvsbuild\drops\whidbey\pd6\raw\40903.19\sources\ndp\fx\src\Designer\Host\UndoEngine.cs
                //OnComponentRemoving function which retains the references we hold to the parent
                //This bug can be reproed by deleting a compositeactivity from design surface and then doing an undo
                //VSWhidbey #312230
                activity.SetParent(null);
                if (activity is CompositeActivity)
                {
                    foreach (Activity nestedActivity in Helpers.GetNestedActivities(activity as CompositeActivity))
                        nestedActivity.SetParent(null);
                }

                WorkflowDesignerLoader.RemoveActivityFromDesigner(Activity.Site, activity);
            }
        }

        /// <summary>
        /// Checks if the contained designer is to be made visible
        /// </summary>
        /// <param name="containedDesigner">Contained designer to check for visibility</param>
        /// <returns></returns>
        public virtual bool IsContainedDesignerVisible(ActivityDesigner containedDesigner)
        {
            if (containedDesigner == null)
                throw new ArgumentNullException("containedDesigner");

            return true;
        }

        /// <summary>
        /// Makes sure that the child designer will be made visible
        /// </summary>
        /// <param name="containedDesigner">Contained designer to make visible</param>
        public virtual void EnsureVisibleContainedDesigner(ActivityDesigner containedDesigner)
        {
            if (containedDesigner == null)
                throw new ArgumentNullException("containedDesigner");

            Expanded = true;
        }

        /// <summary>
        /// Gets the object which is next in the order of navigation
        /// </summary>
        /// <param name="current">Current object in the navigation order</param>
        /// <param name="navigate">Navigation direction</param>
        /// <returns></returns>
        public virtual object GetNextSelectableObject(object current, DesignerNavigationDirection direction)
        {
            return null;
        }

        public override HitTestInfo HitTest(Point point)
        {
            HitTestInfo hitInfo = HitTestInfo.Nowhere;

            if (ExpandButtonRectangle.Contains(point))
            {
                hitInfo = new HitTestInfo(this, HitTestLocations.Designer | HitTestLocations.ActionArea);
            }
            else if (Expanded && Bounds.Contains(point))
            {
                //First check if any of our children are hit.
                ReadOnlyCollection<ActivityDesigner> containedDesigners = ContainedDesigners;
                for (int i = containedDesigners.Count - 1; i >= 0; i--)
                {
                    ActivityDesigner activityDesigner = containedDesigners[i] as ActivityDesigner;
                    if (activityDesigner != null && activityDesigner.IsVisible)
                    {
                        hitInfo = activityDesigner.HitTest(point);
                        if (hitInfo.HitLocation != HitTestLocations.None)
                            break;
                    }
                }
            }

            //If no children are hit then call base class's hittest
            if (hitInfo == HitTestInfo.Nowhere)
                hitInfo = base.HitTest(point);

            //This is to create default hittest info in case the drawing state is invalid
            if (hitInfo.AssociatedDesigner != null && hitInfo.AssociatedDesigner.DrawingState != DrawingStates.Valid)
                hitInfo = new HitTestInfo(hitInfo.AssociatedDesigner, HitTestLocations.Designer | HitTestLocations.ActionArea);

            return hitInfo;
        }
        #endregion

        #region Protected Methods
        /// <summary>
        /// Notifies that the activity associated with contained designer has changed.
        /// </summary>
        /// <param name="e">ActivityChangedEventArgs containing information about the change.</param>
        protected virtual void OnContainedActivityChanged(ActivityChangedEventArgs e)
        {
            if (e == null)
                throw new ArgumentNullException("e");
        }

        /// <summary>
        /// Notifies that number of activities contained within the designers are changing
        /// </summary>
        /// <param name="listChangeArgs">ActivityCollectionChangeEventArgs containing information about what is about to change</param>
        protected virtual void OnContainedActivitiesChanging(ActivityCollectionChangeEventArgs listChangeArgs)
        {
            if (listChangeArgs == null)
                throw new ArgumentNullException("listChangeArgs");
        }

        /// <summary>
        /// Notifies that number of activities contained within the designers have changed
        /// </summary>
        /// <param name="listChangeArgs">ItemListChangeEventArgs containing information about what has changed</param>
        protected virtual void OnContainedActivitiesChanged(ActivityCollectionChangeEventArgs listChangeArgs)
        {
            if (listChangeArgs == null)
                throw new ArgumentNullException("listChangeArgs");

            // Update the status of all the designers
            foreach (ActivityDesigner activityDesigner in ContainedDesigners)
            {
                foreach (DesignerVerb designerVerb in ((IDesigner)activityDesigner).Verbs)
                {
                    int status = designerVerb.OleStatus;
                    status = 0;
                }
            }

            RefreshDesignerVerbs();

            //clear the list of activity designers (force to create the new list the next time it is requested)
            this.containedActivityDesigners = null;

            PerformLayout();
        }

        protected override void Initialize(Activity activity)
        {
            base.Initialize(activity);

            ///

            CompositeActivity compositeActivity = activity as CompositeActivity;
            if (compositeActivity != null)
            {
                compositeActivity.Activities.ListChanging += new EventHandler<ActivityCollectionChangeEventArgs>(OnActivityListChanging);
                compositeActivity.Activities.ListChanged += new EventHandler<ActivityCollectionChangeEventArgs>(OnActivityListChanged);
            }

            if (IsRootDesigner)
            {
                IComponentChangeService componentChangeService = GetService(typeof(IComponentChangeService)) as IComponentChangeService;
                if (componentChangeService != null)
                {
                    componentChangeService.ComponentAdded += new ComponentEventHandler(OnComponentAdded);
                    componentChangeService.ComponentChanged += new ComponentChangedEventHandler(OnComponentChanged);
                }
            }
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                CompositeActivity compositeActivity = Activity as CompositeActivity;
                if (compositeActivity != null)
                {
                    compositeActivity.Activities.ListChanging -= new EventHandler<ActivityCollectionChangeEventArgs>(OnActivityListChanging);
                    compositeActivity.Activities.ListChanged -= new EventHandler<ActivityCollectionChangeEventArgs>(OnActivityListChanged);
                }

                if (IsRootDesigner)
                {
                    IComponentChangeService componentChangeService = GetService(typeof(IComponentChangeService)) as IComponentChangeService;
                    if (componentChangeService != null)
                    {
                        componentChangeService.ComponentAdded -= new ComponentEventHandler(OnComponentAdded);
                        componentChangeService.ComponentChanged -= new ComponentChangedEventHandler(OnComponentChanged);
                    }
                }
            }

            base.Dispose(disposing);
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);

            if (ExpandButtonRectangle.Contains(new Point(e.X, e.Y)))
            {
                //In order to property update the menu items for expand collapse, rather than setting the property
                //directly we go thru menu command service
                IMenuCommandService menuCommandService = GetService(typeof(IMenuCommandService)) as IMenuCommandService;
                if (menuCommandService != null)
                    menuCommandService.GlobalInvoke((Expanded) ? WorkflowMenuCommands.Collapse : WorkflowMenuCommands.Expand);
                else
                    Expanded = !Expanded;
            }
        }

        protected override void OnPaint(ActivityDesignerPaintEventArgs e)
        {
            base.OnPaint(e);

            CompositeDesignerTheme compositeDesignerTheme = e.DesignerTheme as CompositeDesignerTheme;
            if (compositeDesignerTheme == null)
                return;

            //Draw the expand collapse button and the connection
            if (CanExpandCollapse)
            {
                Rectangle expandButtonRectangle = ExpandButtonRectangle;
                if (!expandButtonRectangle.Size.IsEmpty)
                {
                    ActivityDesignerPaint.DrawExpandButton(e.Graphics, expandButtonRectangle, !Expanded, compositeDesignerTheme);
                }
            }

            if (Expanded)
                PaintContainedDesigners(e);
        }

        protected override void OnLayoutPosition(ActivityDesignerLayoutEventArgs e)
        {
            if (e == null)
                throw new ArgumentNullException("e");

            base.OnLayoutPosition(e);

            foreach (ActivityDesigner activityDesigner in ContainedDesigners)
            {
                try
                {
                    ((IWorkflowDesignerMessageSink)activityDesigner).OnLayoutPosition(e.Graphics);
                    activityDesigner.DrawingState &= (~DrawingStates.InvalidPosition);
                }
                catch
                {
                    //Eat the exception thrown
                    activityDesigner.DrawingState |= DrawingStates.InvalidPosition;
                }
            }
        }

        protected override Size OnLayoutSize(ActivityDesignerLayoutEventArgs e)
        {
            Size containerSize = base.OnLayoutSize(e);

            //Calculate the size of internal designers
            foreach (ActivityDesigner activityDesigner in ContainedDesigners)
            {
                try
                {
                    ((IWorkflowDesignerMessageSink)activityDesigner).OnLayoutSize(e.Graphics);
                    activityDesigner.DrawingState &= (~DrawingStates.InvalidSize);
                }
                catch
                {
                    //Eat the exception thrown
                    activityDesigner.Size = activityDesigner.DesignerTheme.Size;
                    activityDesigner.DrawingState |= DrawingStates.InvalidSize;
                }
            }

            if (!String.IsNullOrEmpty(Text))
                this.actualTextSize = ActivityDesignerPaint.MeasureString(e.Graphics, e.DesignerTheme.BoldFont, Text, StringAlignment.Center, Size.Empty);
            else
                this.actualTextSize = Size.Empty;

            if (Expanded)
                containerSize.Height = TitleHeight;
            else
                containerSize.Height = TitleHeight + WorkflowTheme.CurrentTheme.AmbientTheme.Margin.Height;

            return containerSize;
        }

        protected override void SaveViewState(BinaryWriter writer)
        {
            if (writer == null)
                throw new ArgumentNullException("writer");

            writer.Write(Expanded);
            base.SaveViewState(writer);
        }

        protected override void LoadViewState(BinaryReader reader)
        {
            if (reader == null)
                throw new ArgumentNullException("reader");

            Expanded = reader.ReadBoolean();
            base.LoadViewState(reader);
        }

        protected override void OnThemeChange(ActivityDesignerTheme designerTheme)
        {
            base.OnThemeChange(designerTheme);

            CompositeActivity compositeActivity = Activity as CompositeActivity;
            if (compositeActivity != null)
            {
                foreach (Activity activity in compositeActivity.Activities)
                {
                    IWorkflowDesignerMessageSink containedDesigner = ActivityDesigner.GetDesigner(activity) as IWorkflowDesignerMessageSink;
                    if (containedDesigner != null)
                        containedDesigner.OnThemeChange();
                }
            }
        }

        /// <summary>
        /// Call the OnPaint on the contained designers
        /// </summary>
        /// <param name="e">EventArgs to be used for painting</param>
        protected void PaintContainedDesigners(ActivityDesignerPaintEventArgs e)
        {
            OnPaintContainedDesigners(e);
        }

        protected override void OnKeyDown(KeyEventArgs e)
        {
            if (e == null)
                throw new ArgumentNullException("e");

            ISelectionService selectionService = GetService(typeof(ISelectionService)) as ISelectionService;
            object selectedObject = (selectionService != null) ? selectionService.PrimarySelection : null;
            if (selectedObject == null)
                return;

            //handling of the key move events for all designers
            //the freeform designer will override that to allow moving of the designers vs moving selection
            object nextSelectedObject = null;

            if (e.KeyCode == Keys.Down ||
                (e.KeyCode == Keys.Tab && !e.Shift))
            {
                CompositeActivityDesigner selectedDesigner = ActivityDesigner.GetDesigner(selectedObject as Activity) as CompositeActivityDesigner;
                if (selectedDesigner != null)
                    nextSelectedObject = selectedDesigner.FirstSelectableObject;

                if (nextSelectedObject == null)
                {
                    do
                    {
                        // get parent designer
                        CompositeActivityDesigner parentDesigner = ActivityDesigner.GetParentDesigner(selectedObject);
                        if (parentDesigner == null)
                        {
                            // IMPORTANT: This will only happen when the focus is on the last connector in ServiceDesigner
                            nextSelectedObject = selectedObject;
                            break;
                        }

                        nextSelectedObject = parentDesigner.GetNextSelectableObject(selectedObject, DesignerNavigationDirection.Down);
                        if (nextSelectedObject != null)
                            break;

                        selectedObject = parentDesigner.Activity;
                    } while (true);
                }
            }
            else if (e.KeyCode == Keys.Up ||
                    (e.KeyCode == Keys.Tab && e.Shift))
            {
                // get parent designer
                CompositeActivityDesigner parentDesigner = ActivityDesigner.GetParentDesigner(selectedObject);
                if (parentDesigner == null)
                {
                    // IMPORTANT: This will only happen when the focus is on the ServiceDesigner it self
                    CompositeActivityDesigner selectedDesigner = ActivityDesigner.GetDesigner(selectedObject as Activity) as CompositeActivityDesigner;
                    if (selectedDesigner != null)
                        nextSelectedObject = selectedDesigner.LastSelectableObject;
                }
                else
                {
                    // ask for previous component
                    nextSelectedObject = parentDesigner.GetNextSelectableObject(selectedObject, DesignerNavigationDirection.Up);
                    if (nextSelectedObject != null)
                    {
                        CompositeActivityDesigner nextSelectedDesigner = ActivityDesigner.GetDesigner(nextSelectedObject as Activity) as CompositeActivityDesigner;
                        // when we go up, and then upper selection is parent designer then we look for last component
                        if (nextSelectedDesigner != null)
                        {
                            object lastObject = nextSelectedDesigner.LastSelectableObject;
                            if (lastObject != null)
                                nextSelectedObject = lastObject;
                        }
                    }
                    else
                    {
                        nextSelectedObject = parentDesigner.Activity;
                    }
                }
            }
            else if (e.KeyCode == Keys.Left)
            {
                do
                {
                    CompositeActivityDesigner parentDesigner = ActivityDesigner.GetParentDesigner(selectedObject);
                    if (parentDesigner == null)
                        break;

                    nextSelectedObject = parentDesigner.GetNextSelectableObject(selectedObject, DesignerNavigationDirection.Left);
                    if (nextSelectedObject != null)
                        break;

                    selectedObject = parentDesigner.Activity;
                } while (true);
            }
            else if (e.KeyCode == Keys.Right)
            {
                do
                {
                    CompositeActivityDesigner parentDesigner = ActivityDesigner.GetParentDesigner(selectedObject);
                    if (parentDesigner == null)
                        break;

                    nextSelectedObject = parentDesigner.GetNextSelectableObject(selectedObject, DesignerNavigationDirection.Right);
                    if (nextSelectedObject != null)
                        break;

                    selectedObject = parentDesigner.Activity;
                } while (true);
            }

            // now select the component
            if (nextSelectedObject != null)
            {
                selectionService.SetSelectedComponents(new object[] { nextSelectedObject }, SelectionTypes.Replace);

                // make the selected designer visible
                ParentView.EnsureVisible(nextSelectedObject);
            }
        }
        #endregion

        #region Private Methods
        internal virtual void OnPaintContainedDesigners(ActivityDesignerPaintEventArgs e)
        {
            foreach (ActivityDesigner activityDesigner in ContainedDesigners)
            {
                using (PaintEventArgs paintEventArgs = new PaintEventArgs(e.Graphics, e.ViewPort))
                {
                    ((IWorkflowDesignerMessageSink)activityDesigner).OnPaint(paintEventArgs, e.ViewPort);
                }
            }
        }

        private void OnComponentAdded(object sender, ComponentEventArgs e)
        {
            ActivityDesigner designer = ActivityDesigner.GetDesigner(e.Component as Activity);
            if (Activity != e.Component && designer != null && designer.IsLocked)
                DesignerHelpers.MakePropertiesReadOnly(e.Component.Site, designer.Activity);
        }

        private void OnComponentChanged(object sender, ComponentChangedEventArgs e)
        {
            IReferenceService referenceService = GetService(typeof(IReferenceService)) as IReferenceService;
            Activity changedActivity = (referenceService != null) ? referenceService.GetComponent(e.Component) as Activity : e.Component as Activity;
            if (changedActivity != null)
            {
                ActivityDesigner designer = ActivityDesigner.GetDesigner(changedActivity);
                if (designer != null)
                {
                    CompositeActivityDesigner parentDesigner = designer.ParentDesigner;
                    if (parentDesigner != null)
                        parentDesigner.OnContainedActivityChanged(new ActivityChangedEventArgs(changedActivity, e.Member, e.OldValue, e.NewValue));
                }
            }
        }

        private void OnActivityListChanging(object sender, ActivityCollectionChangeEventArgs e)
        {
            OnContainedActivitiesChanging(e);
        }

        private void OnActivityListChanged(object sender, ActivityCollectionChangeEventArgs e)
        {
            OnContainedActivitiesChanged(e);
        }
        #endregion

        #endregion

        #region Properties and Methods
        //
        public static void MoveDesigners(ActivityDesigner activityDesigner, bool moveBack)
        {
            if (activityDesigner == null)
                throw new ArgumentNullException("activityDesigner");

            Activity activity = activityDesigner.Activity as Activity;
            if (activity == null || activity.Parent == null)
                return;

            CompositeActivity compositeActivity = activity.Parent as CompositeActivity;
            if (compositeActivity == null || !compositeActivity.Activities.Contains(activity))
                return;

            int index = compositeActivity.Activities.IndexOf(activity);
            index += (moveBack) ? -1 : 1;
            if (index < 0 || index >= compositeActivity.Activities.Count)
                return;

            IDesignerHost designerHost = compositeActivity.Site.GetService(typeof(IDesignerHost)) as IDesignerHost;
            if (designerHost == null)
                return;

            DesignerTransaction trans = designerHost.CreateTransaction(SR.GetString(SR.MovingActivities));
            try
            {
                compositeActivity.Activities.Remove(activity);
                compositeActivity.Activities.Insert(index, activity);

                ISelectionService selectionService = compositeActivity.Site.GetService(typeof(ISelectionService)) as ISelectionService;
                if (selectionService != null)
                    selectionService.SetSelectedComponents(new object[] { activity });

                if (trans != null)
                    trans.Commit();
            }
            catch
            {
                if (trans != null)
                    trans.Cancel();
                throw;
            }

            CompositeActivityDesigner compositeDesigner = ActivityDesigner.GetDesigner(compositeActivity) as CompositeActivityDesigner;
            if (compositeDesigner != null)
                compositeDesigner.PerformLayout();
        }
        #endregion
    }
    #endregion

}
