#pragma warning disable 1634, 1691
namespace System.Workflow.ComponentModel
{
    #region Imports

    using System;
    using System.Collections;
    using System.Collections.Specialized;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Globalization;
    using System.ComponentModel;
    using System.ComponentModel.Design;
    using System.ComponentModel.Design.Serialization;
    using System.Reflection;
    using System.Workflow.ComponentModel.Compiler;
    using System.Workflow.ComponentModel.Serialization;
    using System.Workflow.ComponentModel.Design;
    using System.Xml;
    using System.IO;

    #endregion

    [Obsolete("The System.Workflow.* types are deprecated.  Instead, please use the new types from System.Activities.*")]
    public sealed class WorkflowChanges
    {
        #region Data members
        public static readonly DependencyProperty ConditionProperty = DependencyProperty.RegisterAttached("Condition", typeof(ActivityCondition), typeof(WorkflowChanges), new PropertyMetadata(DependencyPropertyOptions.Metadata));
        internal static DependencyProperty WorkflowChangeActionsProperty = DependencyProperty.RegisterAttached("WorkflowChangeActions", typeof(IList), typeof(WorkflowChanges), new PropertyMetadata(DependencyPropertyOptions.NonSerialized));
        internal static DependencyProperty WorkflowChangeVersionProperty = DependencyProperty.RegisterAttached("WorkflowChangeVersion", typeof(Guid), typeof(WorkflowChanges), new PropertyMetadata(Guid.Empty, DependencyPropertyOptions.NonSerialized));

        private Activity originalRootActivity = null;
        private Activity clonedRootActivity = null;

        private List<WorkflowChangeAction> modelChangeActions = new List<WorkflowChangeAction>();
        private bool saved = false;

        #endregion

        #region Constuctor & Destructor

        public WorkflowChanges(Activity rootActivity)
        {
            if (rootActivity == null)
                throw new ArgumentNullException("rootActivity");
            if (!(rootActivity is CompositeActivity) || rootActivity.Parent != null)
                throw new ArgumentException(SR.GetString(SR.Error_RootActivityTypeInvalid2), "rootActivity");
#pragma warning suppress 56506
            if (rootActivity.DesignMode)
                throw new InvalidOperationException(SR.GetString(SR.Error_NoRuntimeAvailable));

            // get the original activity
            this.originalRootActivity = (Activity)((Activity)rootActivity).GetValue(Activity.WorkflowDefinitionProperty);
            if (this.originalRootActivity == null)
                this.originalRootActivity = rootActivity;

            // Work around: for dynamic update create a clone, without calling initialize for runtime
            this.clonedRootActivity = (Activity)CloneRootActivity(originalRootActivity);

            // make the tree readonly
            ApplyDynamicUpdateMode((Activity)this.clonedRootActivity);
        }

        #endregion

        #region Public members
        // WhenConditionProperty Get and Set Accessors
        public static object GetCondition(object dependencyObject)
        {
            if (dependencyObject == null)
                throw new ArgumentNullException("dependencyObject");
            if (!(dependencyObject is DependencyObject))
                throw new ArgumentException(SR.GetString(SR.Error_UnexpectedArgumentType, typeof(DependencyObject).FullName), "dependencyObject");

            return (dependencyObject as DependencyObject).GetValue(ConditionProperty);
        }

        public static void SetCondition(object dependencyObject, object value)
        {
            if (dependencyObject == null)
                throw new ArgumentNullException("dependencyObject");
            if (!(dependencyObject is DependencyObject))
                throw new ArgumentException(SR.GetString(SR.Error_UnexpectedArgumentType, typeof(DependencyObject).FullName), "dependencyObject");

            (dependencyObject as DependencyObject).SetValue(ConditionProperty, value);
        }

        public CompositeActivity TransientWorkflow
        {
            get
            {
                return this.clonedRootActivity as CompositeActivity;
            }
        }

        public ValidationErrorCollection Validate()
        {
            TypeProvider typeProvider = CreateTypeProvider(this.originalRootActivity);

            // create service provider
            ServiceContainer serviceContainer = new ServiceContainer();
            serviceContainer.AddService(typeof(ITypeProvider), typeProvider);

            ValidationManager validationManager = new ValidationManager(serviceContainer);
            ValidationErrorCollection errors;
            using (WorkflowCompilationContext.CreateScope(validationManager))
            {
                errors = ValidationHelpers.ValidateObject(validationManager, this.clonedRootActivity);
            }
            return XomlCompilerHelper.MorphIntoFriendlyValidationErrors(errors);
        }

        private void Save()
        {
            ValidationErrorCollection errors = Validate();
            if (errors.HasErrors)
                throw new WorkflowValidationFailedException(SR.GetString(SR.Error_CompilerValidationFailed), errors);

            //work around !!!for conditions we do diff 
            object originalConditions = ((Activity)this.originalRootActivity).GetValue(ConditionTypeConverter.DeclarativeConditionDynamicProp);
            object changedConditions = ((Activity)this.clonedRootActivity).GetValue(ConditionTypeConverter.DeclarativeConditionDynamicProp);
            if (null != originalConditions)
                this.modelChangeActions.AddRange(((IWorkflowChangeDiff)originalConditions).Diff(originalConditions, changedConditions));
            else if (null != changedConditions)
                this.modelChangeActions.AddRange(((IWorkflowChangeDiff)changedConditions).Diff(originalConditions, changedConditions));

            // diff the process model
            this.modelChangeActions.AddRange(DiffTrees(this.originalRootActivity as CompositeActivity, this.clonedRootActivity as CompositeActivity));

            // always call it after diff tree, otherwise it turns on the Locked.
            ReleaseDynamicUpdateMode((Activity)this.clonedRootActivity);

            // cache the change actions into the new workflow definition
            ArrayList workflowChanges = (ArrayList)((Activity)this.clonedRootActivity).GetValue(WorkflowChanges.WorkflowChangeActionsProperty);
            if (workflowChanges == null)
            {
                workflowChanges = new ArrayList();
                ((Activity)this.clonedRootActivity).SetValue(WorkflowChanges.WorkflowChangeActionsProperty, workflowChanges);
            }

            workflowChanges.AddRange(this.modelChangeActions);
            ((Activity)this.clonedRootActivity).SetValue(WorkflowChanges.WorkflowChangeVersionProperty, Guid.NewGuid());
            this.saved = true;

            // now initialize for runtime
            ((IDependencyObjectAccessor)this.clonedRootActivity).InitializeDefinitionForRuntime(null);
        }

        internal void ApplyTo(Activity activity)
        {
            if (activity == null)
                throw new ArgumentNullException("activity");

            if (activity.Parent != null)
                throw new ArgumentException(SR.GetString(SR.Error_RootActivityTypeInvalid), "activity");

            if (activity.RootActivity == null)
                throw new InvalidOperationException(SR.GetString(SR.Error_MissingRootActivity));

            if (activity.WorkflowCoreRuntime == null)
                throw new InvalidOperationException(SR.GetString(SR.Error_NoRuntimeAvailable));

            if (this.saved)
                throw new InvalidOperationException(SR.GetString(SR.Error_TransactionAlreadyApplied));

            if (!CompareWorkflowDefinition((Activity)this.originalRootActivity, (Activity)activity.RootActivity.GetValue(Activity.WorkflowDefinitionProperty)))
                throw new ArgumentException(SR.GetString(SR.Error_WorkflowDefinitionModified), "activity");

            this.Save();

            // go up in the chain and then apply changes
            IWorkflowCoreRuntime workflowCoreRuntime = activity.WorkflowCoreRuntime;
            if (workflowCoreRuntime.CurrentAtomicActivity != null)
                throw new InvalidOperationException(SR.GetString(SR.Error_InsideAtomicScope));
            bool suspended = workflowCoreRuntime.SuspendInstance(SR.GetString(SR.SuspendReason_WorkflowChange));
            try
            {
                // collect all context Activities
                List<Activity> contextActivities = new List<Activity>();
                Queue<Activity> contextActivitiesQueue = new Queue<Activity>();
                contextActivitiesQueue.Enqueue(workflowCoreRuntime.RootActivity);
                while (contextActivitiesQueue.Count > 0)
                {
                    Activity contextActivity = contextActivitiesQueue.Dequeue();
                    contextActivities.Add(contextActivity);

                    // enqueue child context Activities
                    IList<Activity> nestedContextActivities = (IList<Activity>)contextActivity.GetValue(Activity.ActiveExecutionContextsProperty);
                    if (nestedContextActivities != null)
                    {
                        foreach (Activity nestedContextActivity in nestedContextActivities)
                            contextActivitiesQueue.Enqueue(nestedContextActivity);
                    }
                }

                // run instance level validations
                ValidationErrorCollection validationErrors = new ValidationErrorCollection();
                foreach (WorkflowChangeAction changeAction in this.modelChangeActions)
                {
                    if (changeAction is ActivityChangeAction)
                    {
                        foreach (Activity contextActivity in contextActivities)
                        {
                            // WinOE Bug 16903: Ask the contextActivity itself whether or not it can be removed.
                            // An activity can not be removed if it's in the executing mode.
                            if (changeAction is RemovedActivityAction &&
                                contextActivity.DottedPath == ((RemovedActivityAction)changeAction).OriginalRemovedActivity.DottedPath)
                                validationErrors.AddRange(changeAction.ValidateChanges(contextActivity));

                            // Ask the parent context activity whether or not this child activity can be added or removed.
                            // The call to TraverseDottedPathFromRoot here should return the parent context activity for this change action.
                            if (contextActivity.TraverseDottedPathFromRoot(((ActivityChangeAction)changeAction).OwnerActivityDottedPath) != null)
                                validationErrors.AddRange(changeAction.ValidateChanges(contextActivity));
                        }
                    }
                }

                // if errors then return
                if (validationErrors.HasErrors)
                    throw new WorkflowValidationFailedException(SR.GetString(SR.Error_RuntimeValidationFailed), validationErrors);

                // verify if workflow can be changed
                VerifyWorkflowCanBeChanged(workflowCoreRuntime);

                // inform workflow runtime
                workflowCoreRuntime.OnBeforeDynamicChange(this.modelChangeActions);

                // set the new Workflow Definition
                workflowCoreRuntime.RootActivity.SetValue(Activity.WorkflowDefinitionProperty, this.clonedRootActivity);

                // apply changes to all context Activities
                foreach (Activity contextActivity in contextActivities)
                {
                    // apply change to state reader
                    foreach (WorkflowChangeAction changeAction in this.modelChangeActions)
                    {
                        if (changeAction is ActivityChangeAction)
                        {
                            if (contextActivity.TraverseDottedPathFromRoot(((ActivityChangeAction)changeAction).OwnerActivityDottedPath) != null)
                            {
                                bool result = changeAction.ApplyTo(contextActivity);
                                Debug.Assert(result, "ApplyTo failed");
                            }
                        }
                    }
                    // fixup meta properties and notify changes
                    // if the context activity is the one that's being removed, we do not fixup the meta properties.
                    Activity clonedActivity = ((Activity)this.clonedRootActivity).GetActivityByName(contextActivity.QualifiedName);
                    if (clonedActivity != null)
                        contextActivity.FixUpMetaProperties(clonedActivity);
                    NotifyChangesToChildExecutors(workflowCoreRuntime, contextActivity, this.modelChangeActions);
                    NotifyChangesCompletedToChildExecutors(workflowCoreRuntime, contextActivity);
                }

                // inform workflow runtime
                workflowCoreRuntime.OnAfterDynamicChange(true, this.modelChangeActions);
            }
            catch
            {
                workflowCoreRuntime.OnAfterDynamicChange(false, this.modelChangeActions);
                throw;
            }
            finally
            {
                if (suspended)
                    workflowCoreRuntime.Resume();
            }
        }


        #endregion

        #region Internal Helpers
        private void OnActivityListChanged(object sender, ActivityCollectionChangeEventArgs e)
        {
            if (e.RemovedItems != null)
            {
                foreach (Activity removedActivity in e.RemovedItems)
                {
                    if (removedActivity.Readonly)
                        ReleaseDynamicUpdateMode(removedActivity);
                }
            }
        }
        private void ApplyDynamicUpdateMode(Activity seedActivity)
        {
            Queue<Activity> queue = new Queue<Activity>();
            queue.Enqueue(seedActivity);
            while (queue.Count > 0)
            {
                Activity activity = queue.Dequeue();
                activity.Readonly = true;
                activity.DynamicUpdateMode = true;
                foreach (DependencyProperty dependencyProperty in activity.MetaDependencyProperties)
                {
                    if (activity.IsBindingSet(dependencyProperty))
                    {
                        ActivityBind activityBind = activity.GetBinding(dependencyProperty);
                        if (activityBind != null)
                            activityBind.DynamicUpdateMode = true;
                    }
                }

                if (activity is CompositeActivity)
                {
                    CompositeActivity compositeActivity = activity as CompositeActivity;
                    compositeActivity.Activities.ListChanged += new EventHandler<ActivityCollectionChangeEventArgs>(this.OnActivityListChanged);
                    foreach (Activity activity2 in ((CompositeActivity)activity).Activities)
                        queue.Enqueue(activity2);
                }
            }
        }
        private void ReleaseDynamicUpdateMode(Activity seedActivity)
        {
            Queue<Activity> queue = new Queue<Activity>();
            queue.Enqueue(seedActivity);
            while (queue.Count > 0)
            {
                Activity activity = queue.Dequeue() as Activity;
                activity.Readonly = false;
                activity.DynamicUpdateMode = false;
                foreach (DependencyProperty dependencyProperty in activity.MetaDependencyProperties)
                {
                    if (activity.IsBindingSet(dependencyProperty))
                    {
                        ActivityBind activityBind = activity.GetBinding(dependencyProperty);
                        if (activityBind != null)
                            activityBind.DynamicUpdateMode = false;
                    }
                }
                if (activity is CompositeActivity)
                {
                    CompositeActivity compositeActivity = activity as CompositeActivity;
                    compositeActivity.Activities.ListChanged -= new EventHandler<ActivityCollectionChangeEventArgs>(this.OnActivityListChanged);
                    foreach (Activity activity2 in ((CompositeActivity)activity).Activities)
                        queue.Enqueue(activity2);
                }
            }
        }
        private void VerifyWorkflowCanBeChanged(IWorkflowCoreRuntime workflowCoreRuntime)
        {
            // check if the update is allowed on this root-activity.
            ActivityCondition dynamicUpdateCondition = ((Activity)workflowCoreRuntime.RootActivity).GetValue(WorkflowChanges.ConditionProperty) as ActivityCondition;
            if (dynamicUpdateCondition != null)
            {
                using (workflowCoreRuntime.SetCurrentActivity(workflowCoreRuntime.RootActivity))
                {
                    if (!dynamicUpdateCondition.Evaluate(workflowCoreRuntime.RootActivity, workflowCoreRuntime))
                        throw new InvalidOperationException(SR.GetString(CultureInfo.CurrentCulture, SR.Error_DynamicUpdateEvaluation, new object[] { workflowCoreRuntime.InstanceID.ToString() }));
                }
            }
        }
        private void NotifyChangesCompletedToChildExecutors(IWorkflowCoreRuntime workflowCoreRuntime, Activity contextActivity)
        {
            Queue compositeActivities = new Queue();
            compositeActivities.Enqueue(contextActivity);
            while (compositeActivities.Count > 0)
            {
                CompositeActivity compositeActivity = compositeActivities.Dequeue() as CompositeActivity;
                if (compositeActivity == null || !WorkflowChanges.IsActivityExecutable(compositeActivity))
                    continue;

                ISupportWorkflowChanges compositeActivityExecutor = ActivityExecutors.GetActivityExecutor(compositeActivity) as ISupportWorkflowChanges;
                if (compositeActivityExecutor != null)
                {
                    using (workflowCoreRuntime.SetCurrentActivity(compositeActivity))
                    {
                        using (ActivityExecutionContext executionContext = new ActivityExecutionContext(compositeActivity))
                            compositeActivityExecutor.OnWorkflowChangesCompleted(executionContext);
                    }
                }
                foreach (Activity activity in compositeActivity.Activities)
                {
                    if (activity is CompositeActivity)
                        compositeActivities.Enqueue(activity);
                }
            }
        }

        //
        internal static bool IsActivityExecutable(Activity activity)
        {
            if (!activity.Enabled)
                return false;
            if (activity.Parent != null)
                return IsActivityExecutable(activity.Parent);
            return activity.Enabled;
        }

        private void NotifyChangesToChildExecutors(IWorkflowCoreRuntime workflowCoreRuntime, Activity contextActivity, IList<WorkflowChangeAction> changeActions)
        {
            foreach (WorkflowChangeAction action in changeActions)
            {
                if (!(action is ActivityChangeAction))
                    continue;

                CompositeActivity ownerActivity = contextActivity.TraverseDottedPathFromRoot(((ActivityChangeAction)action).OwnerActivityDottedPath) as CompositeActivity;
                if (ownerActivity == null || !WorkflowChanges.IsActivityExecutable(ownerActivity))
                    continue;

                ISupportWorkflowChanges compositeActivityExecutor = ActivityExecutors.GetActivityExecutor(ownerActivity) as ISupportWorkflowChanges;
                if (compositeActivityExecutor == null)
                    throw new ApplicationException(SR.GetString(SR.Error_WorkflowChangesNotSupported, ownerActivity.GetType().FullName));

                using (workflowCoreRuntime.SetCurrentActivity(ownerActivity))
                {
                    using (ActivityExecutionContext executionContext = new ActivityExecutionContext(ownerActivity))
                    {
                        if (action is AddedActivityAction)
                        {
                            Activity addedActivity = ownerActivity.Activities[((AddedActivityAction)action).Index];
                            if (WorkflowChanges.IsActivityExecutable(addedActivity))
                            {
                                addedActivity.OnActivityExecutionContextLoad(executionContext.Activity.RootActivity.WorkflowCoreRuntime);
                                executionContext.InitializeActivity(addedActivity);
                                compositeActivityExecutor.OnActivityAdded(executionContext, addedActivity);
                            }
                        }
                        else if (action is RemovedActivityAction)
                        {
                            RemovedActivityAction removedActivityAction = (RemovedActivityAction)action;
                            if (WorkflowChanges.IsActivityExecutable(removedActivityAction.OriginalRemovedActivity))
                            {
                                compositeActivityExecutor.OnActivityRemoved(executionContext, removedActivityAction.OriginalRemovedActivity);
                                if (removedActivityAction.OriginalRemovedActivity.ExecutionResult != ActivityExecutionResult.Uninitialized)
                                {
                                    removedActivityAction.OriginalRemovedActivity.Uninitialize(executionContext.Activity.RootActivity.WorkflowCoreRuntime);
                                    removedActivityAction.OriginalRemovedActivity.SetValue(Activity.ExecutionResultProperty, ActivityExecutionResult.Uninitialized);
                                }
                                removedActivityAction.OriginalRemovedActivity.OnActivityExecutionContextUnload(executionContext.Activity.RootActivity.WorkflowCoreRuntime);
                                removedActivityAction.OriginalRemovedActivity.Dispose();
                            }
                        }
                    }
                }
            }
        }
        #endregion

        #region Static helpers

        private static bool CompareWorkflowDefinition(Activity originalWorkflowDefinition, Activity currentWorkflowDefinition)
        {
            if (originalWorkflowDefinition == currentWorkflowDefinition)
                return true;

            if (originalWorkflowDefinition.GetType() != currentWorkflowDefinition.GetType())
                return false;

            Guid originalChangeVersion = (Guid)originalWorkflowDefinition.GetValue(WorkflowChanges.WorkflowChangeVersionProperty);
            Guid currentChangeVersion = (Guid)currentWorkflowDefinition.GetValue(WorkflowChanges.WorkflowChangeVersionProperty);
            return (originalChangeVersion == currentChangeVersion);
        }

        private static List<WorkflowChangeAction> DiffTrees(CompositeActivity originalCompositeActivity, CompositeActivity clonedCompositeActivity)
        {
            List<WorkflowChangeAction> listChanges = new List<WorkflowChangeAction>();
            IEnumerator<Activity> clonedActivitiesEnum = clonedCompositeActivity.Activities.GetEnumerator();
            IEnumerator<Activity> originalActivitiesEnum = originalCompositeActivity.Activities.GetEnumerator();
            int currentRemoveIndex = 0;
            while (originalActivitiesEnum.MoveNext())
            {
                bool foundMatching = false;
                Activity originalActivity = originalActivitiesEnum.Current;
                while (clonedActivitiesEnum.MoveNext())
                {
                    Activity clonedActivity = clonedActivitiesEnum.Current;
                    if (clonedActivity.Readonly)
                    {
                        if (originalActivity.DottedPath == clonedActivity.CachedDottedPath)
                        {
                            currentRemoveIndex++;
                            foundMatching = true;
                            if (originalActivity is CompositeActivity)
                                listChanges.AddRange(DiffTrees(originalActivity as CompositeActivity, clonedActivity as CompositeActivity));
                            break;
                        }
                        else
                        {
                            listChanges.Add(new RemovedActivityAction(currentRemoveIndex, originalActivity, clonedCompositeActivity));
                            while (originalActivitiesEnum.MoveNext())
                            {
                                originalActivity = originalActivitiesEnum.Current;
                                if (originalActivity.DottedPath == clonedActivity.CachedDottedPath)
                                {
                                    currentRemoveIndex++;
                                    foundMatching = true;
                                    if (originalActivity is CompositeActivity)
                                        listChanges.AddRange(DiffTrees(originalActivity as CompositeActivity, clonedActivity as CompositeActivity));
                                    break;
                                }
                                else
                                {
                                    listChanges.Add(new RemovedActivityAction(currentRemoveIndex, originalActivity, clonedCompositeActivity));
                                }
                            }
                        }
                        break;
                    }
                    else
                    {
                        listChanges.Add(new AddedActivityAction(clonedCompositeActivity, clonedActivity));
                        currentRemoveIndex++;
                    }
                }
                if (!foundMatching)
                {
                    listChanges.Add(new RemovedActivityAction(currentRemoveIndex, originalActivity, clonedCompositeActivity));
                }
            }
            while (clonedActivitiesEnum.MoveNext())
                listChanges.Add(new AddedActivityAction(clonedCompositeActivity, clonedActivitiesEnum.Current));
            return listChanges;
        }

        private static Activity CloneRootActivity(Activity originalRootActivity)
        {
            // create new definition root
            string xomlText = originalRootActivity.GetValue(Activity.WorkflowXamlMarkupProperty) as string;
            string rulesText = null;
            Activity clonedRootActivity = null;
            IServiceProvider serviceProvider = originalRootActivity.GetValue(Activity.WorkflowRuntimeProperty) as IServiceProvider;
            Debug.Assert(serviceProvider != null);
            if (!string.IsNullOrEmpty(xomlText))
            {
                rulesText = originalRootActivity.GetValue(Activity.WorkflowRulesMarkupProperty) as string;
                clonedRootActivity = Activity.OnResolveActivityDefinition(null, xomlText, rulesText, true, false, serviceProvider);
            }
            else
                clonedRootActivity = Activity.OnResolveActivityDefinition(originalRootActivity.GetType(), null, null, true, false, serviceProvider);

            if (clonedRootActivity == null)
                throw new NullReferenceException(SR.GetString(SR.Error_InvalidRootForWorkflowChanges));

            // deserialize change history and apply it to new definition tree
            ArrayList workflowChanges = (ArrayList)((Activity)originalRootActivity).GetValue(WorkflowChanges.WorkflowChangeActionsProperty);
            if (workflowChanges != null)
            {
                workflowChanges = CloneWorkflowChangeActions(workflowChanges, originalRootActivity);
                if (workflowChanges != null)
                {
                    // apply changes to the shared schedule Defn to get the instance specific copy
                    foreach (WorkflowChangeAction action in workflowChanges)
                    {
                        bool result = action.ApplyTo((Activity)clonedRootActivity);
                        Debug.Assert(result, "ApplyTo Failed");
                    }
                    ((Activity)clonedRootActivity).SetValue(WorkflowChanges.WorkflowChangeActionsProperty, workflowChanges);
                }
            }
            return clonedRootActivity;
        }

        private static ArrayList CloneWorkflowChangeActions(ArrayList workflowChanges, Activity rootActivity)
        {
            if (workflowChanges == null)
                throw new ArgumentNullException("workflowChanges");

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

            string dynamicUpdateHistory = null;
            TypeProvider typeProvider = CreateTypeProvider(rootActivity);
            ServiceContainer serviceContainer = new ServiceContainer();
            serviceContainer.AddService(typeof(ITypeProvider), typeProvider);
            DesignerSerializationManager manager = new DesignerSerializationManager(serviceContainer);
            WorkflowMarkupSerializer xomlSerializer = new WorkflowMarkupSerializer();

            ArrayList clonedWorkflowChanges = null;
            // serialize dynamic updates
            using (manager.CreateSession())
            {
                using (StringWriter sw = new StringWriter(CultureInfo.InvariantCulture))
                {
                    using (XmlWriter xmlWriter = Helpers.CreateXmlWriter(sw))
                    {
                        WorkflowMarkupSerializationManager xomlSerializationManager = new WorkflowMarkupSerializationManager(manager);
                        xomlSerializer.Serialize(xomlSerializationManager, xmlWriter, workflowChanges);
                        dynamicUpdateHistory = sw.ToString();
                    }
                }

                // deserialize those
                using (StringReader sr = new StringReader(dynamicUpdateHistory))
                {
                    using (XmlReader xmlReader = XmlReader.Create(sr))
                    {
                        WorkflowMarkupSerializationManager xomlSerializationManager = new WorkflowMarkupSerializationManager(manager);
                        clonedWorkflowChanges = xomlSerializer.Deserialize(xomlSerializationManager, xmlReader) as ArrayList;
                    }
                }
            }
            return clonedWorkflowChanges;
        }

        internal static TypeProvider CreateTypeProvider(Activity rootActivity)
        {
            TypeProvider typeProvider = new TypeProvider(null);

            Type companionType = rootActivity.GetType();
            typeProvider.SetLocalAssembly(companionType.Assembly);
            typeProvider.AddAssembly(companionType.Assembly);

            foreach (AssemblyName assemblyName in companionType.Assembly.GetReferencedAssemblies())
            {
                Assembly referencedAssembly = null;
                try
                {
                    referencedAssembly = Assembly.Load(assemblyName);
                    if (referencedAssembly != null)
                        typeProvider.AddAssembly(referencedAssembly);
                }
                catch
                {
                }

                if (referencedAssembly == null && assemblyName.CodeBase != null)
                    typeProvider.AddAssemblyReference(assemblyName.CodeBase);
            }
            return typeProvider;
        }
        #endregion
    }

    #region WorkflowChangeAction classes

    [DesignerSerializer(typeof(WorkflowMarkupSerializer), typeof(WorkflowMarkupSerializer))]
    [Obsolete("The System.Workflow.* types are deprecated.  Instead, please use the new types from System.Activities.*")]
    public abstract class WorkflowChangeAction
    {
        protected internal abstract bool ApplyTo(Activity rootActivity);
        protected internal abstract ValidationErrorCollection ValidateChanges(Activity activity);
    }

    [DesignerSerializer(typeof(ActivityChangeActionMarkupSerializer), typeof(WorkflowMarkupSerializer))]
    [Obsolete("The System.Workflow.* types are deprecated.  Instead, please use the new types from System.Activities.*")]
    public abstract class ActivityChangeAction : WorkflowChangeAction
    {
        private string ownerActivityDottedPath = string.Empty;

        protected ActivityChangeAction()
        {
        }

        protected ActivityChangeAction(CompositeActivity compositeActivity)
        {
            if (compositeActivity == null)
                throw new ArgumentNullException("compositeActivity");

            this.ownerActivityDottedPath = compositeActivity.DottedPath;
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public string OwnerActivityDottedPath
        {
            get
            {
                return this.ownerActivityDottedPath;
            }
            internal set
            {
                this.ownerActivityDottedPath = value;
            }
        }

        protected internal override ValidationErrorCollection ValidateChanges(Activity contextActivity)
        {
            if (contextActivity == null)
                throw new ArgumentNullException("contextActivity");

            ValidationErrorCollection errors = new ValidationErrorCollection();

            CompositeActivity ownerActivity = contextActivity.TraverseDottedPathFromRoot(this.OwnerActivityDottedPath) as CompositeActivity;
            if (ownerActivity != null && WorkflowChanges.IsActivityExecutable(ownerActivity))
            {
                foreach (Validator validator in ComponentDispenser.CreateComponents(ownerActivity.GetType(), typeof(ActivityValidatorAttribute)))
                {
                    ValidationError error = validator.ValidateActivityChange(ownerActivity, this);
                    if (error != null)
                        errors.Add(error);
                }
            }

            return errors;
        }
    }

    [Obsolete("The System.Workflow.* types are deprecated.  Instead, please use the new types from System.Activities.*")]
    public sealed class AddedActivityAction : ActivityChangeAction
    {
        private int index = 0;
        private Activity addedActivity = null;

        public AddedActivityAction()
        {
        }

        public AddedActivityAction(CompositeActivity compositeActivity, Activity activityAdded)
            : base(compositeActivity)
        {
            if (compositeActivity == null)
                throw new ArgumentNullException("compositeActivity");

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

            this.index = (compositeActivity.Activities != null) ? compositeActivity.Activities.IndexOf(activityAdded) : -1;
            this.addedActivity = activityAdded;
        }
        public int Index
        {
            get
            {
                return this.index;
            }
            internal set
            {
                this.index = value;
            }
        }

        public Activity AddedActivity
        {
            get
            {
                return this.addedActivity;
            }
            internal set
            {
                this.addedActivity = value;
            }
        }

        protected internal override bool ApplyTo(Activity rootActivity)
        {
            if (rootActivity == null)
                throw new ArgumentNullException("rootActivity");
            if (!(rootActivity is CompositeActivity))
                throw new ArgumentException(SR.GetString(SR.Error_RootActivityTypeInvalid), "rootActivity");

            CompositeActivity ownerActivity = rootActivity.TraverseDottedPathFromRoot(this.OwnerActivityDottedPath) as CompositeActivity;
            if (ownerActivity == null)
                return false;

            // !!!work around: 
            ownerActivity.DynamicUpdateMode = true;
            CompositeActivity addedActivityOwner = this.addedActivity.Parent;
            try
            {
                this.addedActivity.SetParent(ownerActivity);
                Activity clonedAddedActivity = this.addedActivity;
                if (!this.addedActivity.DesignMode)
                    clonedAddedActivity = this.addedActivity.Clone();
                // We need to serialize and deserialize in order to clone during design mode
                else
                {
                    TypeProvider typeProvider = WorkflowChanges.CreateTypeProvider(rootActivity);
                    ServiceContainer serviceContainer = new ServiceContainer();
                    serviceContainer.AddService(typeof(ITypeProvider), typeProvider);
                    DesignerSerializationManager manager = new DesignerSerializationManager(serviceContainer);
                    WorkflowMarkupSerializer xomlSerializer = new WorkflowMarkupSerializer();
                    string addedActivityText = string.Empty;
                    // serialize dynamic updates
                    using (manager.CreateSession())
                    {
                        using (StringWriter sw = new StringWriter(CultureInfo.InvariantCulture))
                        {
                            using (XmlWriter xmlWriter = Helpers.CreateXmlWriter(sw))
                            {
                                WorkflowMarkupSerializationManager xomlSerializationManager = new WorkflowMarkupSerializationManager(manager);
                                xomlSerializer.Serialize(xomlSerializationManager, xmlWriter, this.addedActivity);
                                addedActivityText = sw.ToString();
                            }
                        }

                        // deserialize those
                        using (StringReader sr = new StringReader(addedActivityText))
                        {
                            using (XmlReader xmlReader = XmlReader.Create(sr))
                            {
                                WorkflowMarkupSerializationManager xomlSerializationManager = new WorkflowMarkupSerializationManager(manager);
                                clonedAddedActivity = xomlSerializer.Deserialize(xomlSerializationManager, xmlReader) as Activity;
                            }
                        }
                    }
                    if (clonedAddedActivity == null)
                        throw new InvalidOperationException(SR.GetString(SR.Error_ApplyDynamicChangeFailed));
                }
                if (ownerActivity.WorkflowCoreRuntime != null)
                    ((IDependencyObjectAccessor)clonedAddedActivity).InitializeInstanceForRuntime(ownerActivity.WorkflowCoreRuntime);

                clonedAddedActivity.SetParent(null);
                ownerActivity.Activities.Insert(this.index, clonedAddedActivity);
            }
            finally
            {
                this.addedActivity.SetParent(addedActivityOwner);
                ownerActivity.DynamicUpdateMode = false;
            }
            return true;
        }
    }

    [Obsolete("The System.Workflow.* types are deprecated.  Instead, please use the new types from System.Activities.*")]
    public sealed class RemovedActivityAction : ActivityChangeAction
    {
        private int removedActivityIndex = -1;
        private Activity originalRemovedActivity = null;

        public RemovedActivityAction()
        {
        }
        public RemovedActivityAction(int removedActivityIndex, Activity originalActivity, CompositeActivity clonedParentActivity)
            : base(clonedParentActivity)
        {
            if (originalActivity == null)
                throw new ArgumentNullException("originalActivity");
            if (clonedParentActivity == null)
                throw new ArgumentNullException("clonedParentActivity");

            this.originalRemovedActivity = originalActivity;
            this.removedActivityIndex = removedActivityIndex;
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public int RemovedActivityIndex
        {
            get
            {
                return this.removedActivityIndex;
            }
            internal set
            {
                this.removedActivityIndex = value;
            }
        }
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public Activity OriginalRemovedActivity
        {
            get
            {
                return this.originalRemovedActivity;
            }
            internal set
            {
                this.originalRemovedActivity = value;
            }
        }
        protected internal override ValidationErrorCollection ValidateChanges(Activity contextActivity)
        {
            ValidationErrorCollection errors = base.ValidateChanges(contextActivity);
            Activity removedActivityInContext = contextActivity.TraverseDottedPathFromRoot(this.originalRemovedActivity.DottedPath);
            if (WorkflowChanges.IsActivityExecutable(removedActivityInContext) && removedActivityInContext.ExecutionStatus == ActivityExecutionStatus.Executing)
                errors.Add(new ValidationError(SR.GetString(SR.Error_RemoveExecutingActivity, this.originalRemovedActivity.QualifiedName), ErrorNumbers.Error_RemoveExecutingActivity));
            return errors;
        }
        protected internal override bool ApplyTo(Activity rootActivity)
        {
            if (rootActivity == null)
                throw new ArgumentNullException("rootActivity");
            if (!(rootActivity is CompositeActivity))
                throw new ArgumentException(SR.GetString(SR.Error_RootActivityTypeInvalid), "rootActivity");


            CompositeActivity ownerActivity = rootActivity.TraverseDottedPathFromRoot(this.OwnerActivityDottedPath) as CompositeActivity;
            if (ownerActivity == null)
                return false;

            if (this.removedActivityIndex >= ownerActivity.Activities.Count)
                return false;

            // !!!work around: 
            ownerActivity.DynamicUpdateMode = true;
            try
            {
                this.originalRemovedActivity = ownerActivity.Activities[this.removedActivityIndex];
                ownerActivity.Activities.RemoveAt(this.removedActivityIndex);
            }
            finally
            {
                ownerActivity.DynamicUpdateMode = false;
            }
            return true;
        }
    }
    #endregion

    #region Class ActivityChangeActionMarkupSerializer
    internal sealed class ActivityChangeActionMarkupSerializer : WorkflowMarkupSerializer
    {
        protected internal override PropertyInfo[] GetProperties(WorkflowMarkupSerializationManager serializationManager, object obj)
        {
            List<PropertyInfo> properties = new List<PropertyInfo>(base.GetProperties(serializationManager, obj));

            //Collect the internal properties, we do this so that activity change action apis don't need to expose unnecessary setters
            foreach (PropertyInfo property in obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy))
            {
                DesignerSerializationVisibility visibility = Helpers.GetSerializationVisibility(property);
                if (visibility != DesignerSerializationVisibility.Hidden && property.GetSetMethod() == null && property.GetSetMethod(true) != null)
                    properties.Add(property);
            }

            return properties.ToArray();
        }
    }
    #endregion
}
