/// <summary>
        /// Opens an expression designer window and initializes the designer with the specified expression.
        /// </summary>
        /// <param name="parentWindow">The parent window.</param>
        /// <param name="process">The source process.</param>
        /// <param name="resultType">The result type.</param>
        /// <param name="expression">The expression.</param>
        /// <param name="saveAction">The save action.</param>
        /// <param name="cancelAction">The cancel action.</param>
        /// <param name="removeAction">The remove action.</param>
        protected void EditExpression(
            ITopLevelWindow parentWindow,
            IProcessEdit process,
            Type resultType,
            string expression,
            Action saveAction,
            Action cancelAction,
            Action removeAction)
        {
            SaveAction = saveAction;
            CancelAction = cancelAction;
            RemoveAction = removeAction;

            ExpressionDesigner.Value.LoadFromExpressionObjects(new List<IExpressionObjectBase>());

            WindowManager.Value.ShowStatus(new Status { IsBusy = true });

            var expressions = new List<IExpressionObjectBase>();
            var newExpressions = new List<IExpressionObjectBase>();

            var syncContext = new NotifyClientAction(
                () =>
                    {
                        ExpressionDesigner.Value.LoadFromExpressionObjects(expressions);
                        WindowManager.Value.ShowStatus(new Status());
                    });

            syncContext.OperationStarted();

            newExpressions.Add(CreateSourceItem(process));
            newExpressions.Add(CreateUserInformationItem(CurrentUserInformationItemName, 10, 400));
            newExpressions.Add(CreateDestinationItem(resultType));

            if (!string.IsNullOrWhiteSpace(expression))
            {
                try
                {
                    var expressionsContainer = Serializer.Deserialize(expression);
                    expressions.AddRange(expressionsContainer.Expressions);
                }
                catch
                {
                    // Do nothing, new expressions will be used.
                }
            }

            UpdateStateList(process);

            UpdateStoredExpressions(expressions, newExpressions, syncContext);

            syncContext.OperationCompleted();
            WindowManager.Value.ShowChildWindow(parentWindow, this);
        }
        /// <summary>
        /// Updates the destination fields.
        /// </summary>
        /// <param name="storedFields">The stored fields.</param>
        /// <param name="destinationFields">The destination fields.</param>
        /// <param name="syncContext">The synchronize context.</param>
        private static void UpdateDestinationFields(
            IList<IExpressionField> storedFields,
            IEnumerable<IExpressionField> destinationFields,
            NotifyClientAction syncContext)
        {
            var newDestinationFields = destinationFields.ToArray();

            foreach (var field in newDestinationFields)
            {
                var exField =
                    (from f in storedFields
                     where ((DestinationField)f).SystemName == ((DestinationField)field).SystemName
                     select f).
                        FirstOrDefault();
                if (exField == null)
                {
                    storedFields.Add(field);
                }
                else
                {
                    //ensure that old script is updated
                    var exf = (DestinationField)exField;
                    var df = (DestinationField)field;
                    exf.SetName = df.SetName;
                    exf.Name = df.Name;
                    exf.InnerName = df.InnerName;
                    exf.SystemName = df.SystemName;
                    exf.DataType = df.DataType;
                    exf.SubfieldsRetriever = df.SubfieldsRetriever;
                    exf.IsKeyVisible = df.IsKeyVisible;
                    exf.IsKeyEnabled = df.IsKeyEnabled;
                    exf.MarkAsKeyWhenConnected = df.MarkAsKeyWhenConnected;

                    exf.ConnectorIn.Name = df.ConnectorIn.Name;
                    exf.ConnectorIn.DataType = df.ConnectorIn.DataType;
                    exf.ConnectorIn.IsNullable = df.ConnectorIn.IsNullable;

                    if (!exf.IsKeyEnabled)
                    {
                        exf.IsKey = exf.MarkAsKeyWhenConnected && exf.IsConnected();
                    }

                    if (exField.Subfields.Count > 0 && field.SubfieldsRetriever != null)
                    {
                        syncContext.OperationStarted();
                        field.SubfieldsRetriever.BeginLoad(exField, (f, l) =>
                        {
                            UpdateDestinationFields(exField.Subfields, l, syncContext);
                            syncContext.OperationCompleted();
                        });
                    }
                    else
                    {
                        UpdateDestinationFields(exField.Subfields, field.Subfields, syncContext);
                    }
                }
            }

            for (var i = storedFields.Count - 1; i >= 0; --i)
            {
                var newField = (from f in newDestinationFields
                                where ((DestinationField)f).SystemName == ((DestinationField)storedFields[i]).SystemName
                                select f).FirstOrDefault();

                if (newField == null)
                {
                    storedFields.RemoveAt(i);
                }
            }
        }
        /// <summary>
        /// Updates the stored expressions.
        /// </summary>
        /// <param name="storedExpressions">The stored expressions.</param>
        /// <param name="newExpressions">The new expressions.</param>
        /// <param name="syncContext">The synchronize context.</param>
        private void UpdateStoredExpressions(
            IList<IExpressionObjectBase> storedExpressions,
            IList<IExpressionObjectBase> newExpressions,
            NotifyClientAction syncContext)
        {
            // Update source nodes.
            var newSource = newExpressions.OfType<SourceFieldList>().First();
            var oldSource = storedExpressions.OfType<SourceFieldList>().FirstOrDefault();

            if (oldSource != null)
            {
                var fieldList = oldSource.Fields.Cast<IExpressionField>().ToList();

                UpdateSourceFields(fieldList, newSource.Fields);
                oldSource.Fields.Clear();

                foreach (var field in fieldList)
                    oldSource.Fields.Add((SourceField)field);
            }
            else
                storedExpressions.Add(newSource);

            // Update destination nodes.
            var newDestination = newExpressions.OfType<DestinationFieldList>().First();
            var oldDestination = storedExpressions.OfType<DestinationFieldList>().FirstOrDefault();

            if (oldDestination != null)
            {
                var fieldList = oldDestination.Fields.Cast<IExpressionField>().ToList();

                UpdateDestinationFields(fieldList, newDestination.Fields, syncContext);
                oldDestination.Fields.Clear();

                foreach (var field in fieldList)
                    oldDestination.Fields.Add((DestinationField)field);
            }
            else
                storedExpressions.Add(newDestination);

            foreach (var expression in storedExpressions.OfType<ConstantExpression>())
            {
                UpdateConstantExpression(expression);
            }
        }
        /// <summary>
        /// Loads the expression items.
        /// </summary>
        /// <param name="process">The process.</param>
        /// <param name="syncProcess">The synchronize process.</param>
        private void LoadExpressionItems(ProcessEdit process, ESyncProcessEdit syncProcess)
        {
            WindowManager.Value.ShowStatus(new Status { IsBusy = true });

            var expressions = new List<IExpressionObjectBase>();
            var newExpressions = new List<IExpressionObjectBase>();

            var syncContext = new NotifyClientAction(
                () =>
                    {
                        _expressionDesigner.LoadFromExpressionObjects(expressions);
                        WindowManager.Value.ShowStatus(new Status());
                    });

            syncContext.OperationStarted();

            var source = new SourceFieldList { ExpressionName = "Source", Top = 10, Left = 10 };

            foreach (var providerField in syncProcess.Endpoints.Source.ProviderFields)
            {
                var sourceField = CreateSourceField(providerField, source);

                if (sourceField != null)
                    source.Fields.Add(sourceField);
            }

            newExpressions.Add(source);

            var destination = new DestinationFieldList { ExpressionName = process.Name, Top = 10, Left = 600 };

            AddIdFields(destination);
            AddStateFields(process, destination);
            AddVersionFields(process, destination);

            foreach (var field in process.GetAllFields().Where(CanBeDestinationField))
            {
                var destinationField = CreateDestinationField(field, destination);

                if (destinationField != null)
                    destination.Fields.Add(destinationField);
            }

            newExpressions.Add(destination);

            if (!string.IsNullOrWhiteSpace(syncProcess.Map.Designer))
            {
                try
                {
                    var expressionsContainer = ExpressionsSerializer.Deserialize(syncProcess.Map.Designer);
                    ExpressionNodeFactory.RestoreConnections(expressionsContainer.Expressions);
                    expressions.AddRange(expressionsContainer.Expressions);
                }
                catch
                {
                    // Do nothing, new expressions will be used.
                }
            }

            UpdateStateList(process);

            UpdateStoredExpressions(expressions, newExpressions, syncContext);

            syncContext.OperationCompleted();
        }
        /// <summary>
        /// Initializes the expression designer and opens the expression designer window.
        /// </summary>
        /// <param name="parentWindow">The parent window.</param>
        /// <param name="process">The parent process.</param>
        /// <param name="method">The service method.</param>
        /// <param name="serviceTypes">The collection of known service types.</param>
        /// <param name="saveAction">The save action.</param>
        /// <param name="cancelAction">The cancel action.</param>
        /// <param name="removeAction">The remove action.</param>
        public void EditExpression(
            ITopLevelWindow parentWindow,
            IProcessEdit process,
            ServiceMethodEdit method,
            IEnumerable<ServiceExposedTypeEdit> serviceTypes,
            Action saveAction,
            Action cancelAction,
            Action removeAction)
        {
            SaveAction = saveAction;
            CancelAction = cancelAction;
            RemoveAction = removeAction;
            _knownTypes = serviceTypes.ToArray();

            ExpressionDesigner.Value.LoadFromExpressionObjects(new List<IExpressionObjectBase>());

            WindowManager.Value.ShowStatus(new Status { IsBusy = true });

            var expressions = new List<IExpressionObjectBase>();
            var newExpressions = new List<IExpressionObjectBase>();

            var syncContext = new NotifyClientAction(
                () =>
                {
                    ExpressionDesigner.Value.LoadFromExpressionObjects(expressions);
                    WindowManager.Value.ShowStatus(new Status());
                });

            syncContext.OperationStarted();

            newExpressions.Add(CreateSourceItem(method.InputParameters));
            newExpressions.Add(CreateDestinationItem(process));

            if (!string.IsNullOrWhiteSpace(method.EndpointMapping))
            {
                try
                {
                    var expressionsContainer = Serializer.Deserialize(method.EndpointMapping);
                    expressions.AddRange(expressionsContainer.Expressions);
                }
                catch
                {
                    // Do nothing, new expressions will be used.
                }
            }

            UpdateStateList(process);

            UpdateStoredExpressions(expressions, newExpressions, syncContext);

            syncContext.OperationCompleted();
            WindowManager.Value.ShowChildWindow(parentWindow, this);
        }
        /// <summary>
        /// Opens the expression designer window.
        /// </summary>
        /// <param name="parentWindow">
        /// The parent window.
        /// </param>
        /// <param name="process">
        /// The process.
        /// </param>
        /// <param name="method">
        /// The method.
        /// </param>
        /// <param name="serviceTypes">
        /// The service types.
        /// </param>
        public void EditExpression(
            ITopLevelWindow parentWindow,
            IProcessEdit process,
            ServiceMethodEdit method,
            IEnumerable<ServiceExposedTypeEdit> serviceTypes)
        {
            if (parentWindow == null)
                throw new ArgumentNullException("parentWindow");

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

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

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

            _method = method;
            _knownTypes = serviceTypes.ToArray();

            ExpressionDesigner.Value.LoadFromExpressionObjects(new List<IExpressionObjectBase>());

            WindowManager.Value.ShowStatus(new Status { IsBusy = true });

            var expressions = new List<IExpressionObjectBase>();
            var newExpressions = new List<IExpressionObjectBase>();

            var syncContext = new NotifyClientAction(
                () =>
                {
                    ExpressionDesigner.Value.LoadFromExpressionObjects(expressions);
                    WindowManager.Value.ShowStatus(new Status());
                });

            syncContext.OperationStarted();

            newExpressions.Add(CreateSourceItem(process));
            newExpressions.Add(CreateDestinationItem(method.ResultTypeGuid));

            if (!string.IsNullOrWhiteSpace(method.ResultMapping))
            {
                try
                {
                    var expressionsContainer = Serializer.Deserialize(method.ResultMapping);
                    expressions.AddRange(expressionsContainer.Expressions);
                }
                catch
                {
                    // Do nothing, new expressions will be used.
                }
            }

            UpdateStateList(process);

            UpdateStoredExpressions(expressions, newExpressions, syncContext);

            syncContext.OperationCompleted();
            WindowManager.Value.ShowChildWindow(parentWindow, this);
        }
        /// <summary>
        /// Edits the <see cref="WebMethodCallSettingsEdit.ResultMapping"/> expression.
        /// </summary>
        /// <param name="parentWindow">
        /// The parent window.
        /// </param>
        /// <param name="method">
        /// The method.
        /// </param>
        /// <param name="process">
        /// The process.
        /// </param>
        /// <param name="callSettings">
        /// The call settings.
        /// </param>
        public void EditExpression(
            ITopLevelWindow parentWindow,
            IWebServiceMethodDescription method,
            IProcessEdit process,
            WebMethodCallSettingsEdit callSettings)
        {
            SaveAction = CreateSaveAction(callSettings);
            RemoveAction = CreateRemoveAction(callSettings);

            ExpressionDesigner.Value.LoadFromExpressionObjects(new List<IExpressionObjectBase>());
            WindowManager.Value.ShowStatus(new Status { IsBusy = true });

            var expressions = new List<IExpressionObjectBase>();
            var newExpressions = new List<IExpressionObjectBase>();

            var syncContext = new NotifyClientAction(
                () =>
                {
                    ExpressionDesigner.Value.LoadFromExpressionObjects(expressions);
                    WindowManager.Value.ShowStatus(new Status());
                });

            syncContext.OperationStarted();

            newExpressions.Add(
                CreateSourceItem(
                    "Soap Headers",
                    Constants.WebMethodCallOutputHeadersExpressionName,
                    10,
                    10,
                    method.OutputParameters.Where(p => p.IsSoapHeader),
                    callSettings.ResultFields));
            newExpressions.Add(
                CreateSourceItem(
                    "Output Parameters",
                    Constants.WebMethodCallOutputParametersExpressionName,
                    160,
                    10,
                    method.OutputParameters.Where(p => !p.IsSoapHeader),
                    callSettings.ResultFields));
            newExpressions.Add(CreateUserInformationItem(CurrentUserInformationItemName, 310, 10));
            newExpressions.Add(CreateDestinationItem(process));

            if (!string.IsNullOrWhiteSpace(callSettings.ResultMapping))
            {
                try
                {
                    var expressionsContainer = Serializer.Deserialize(callSettings.ResultMapping);
                    expressions.AddRange(expressionsContainer.Expressions);
                }
                catch
                {
                    // Do nothing, new expressions will be used.
                }
            }

            UpdateStateList(process);

            UpdateStoredExpressions(expressions, newExpressions, syncContext);

            syncContext.OperationCompleted();
            WindowManager.Value.ShowChildWindow(parentWindow, this);
        }