/// <summary>
        /// Initializes a new instance of the <see cref="OneInTwoOutExpressionNode"/> class.
        /// </summary>
        /// <param name="diagramViewModel">
        /// The diagram view model.
        /// </param>
        /// <param name="expressionObject">
        /// The expression object.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// The <paramref name="expressionObject"/> parameter is null.
        /// </exception>
        public OneInTwoOutExpressionNode(IDiagramViewModel diagramViewModel, OneInTwoOutExpression expressionObject)
            : base(expressionObject)
        {
            if (expressionObject == null)
                throw new ArgumentNullException("expressionObject");

            _diagramViewModel = diagramViewModel;

            ConnectorIn = new ExpressionConnectorViewModel(new ExpressionConnector(ConnectorType.In, expressionObject.ConnectorIn), _diagramViewModel);
            Connector1Out = new ExpressionConnectorViewModel(new ExpressionConnector(ConnectorType.Out, expressionObject.Connector1Out), _diagramViewModel);
            Connector2Out = new ExpressionConnectorViewModel(new ExpressionConnector(ConnectorType.Out, expressionObject.Connector2Out), _diagramViewModel);
        }
        public ConverterExpressionNode(IDiagramViewModel diagramViewModel, ConverterExpression expressionObject)
            : base(expressionObject)
        {
            if (expressionObject == null) throw new ArgumentNullException("expressionObject");

            _diagramViewModel = diagramViewModel;
            IsValidFunc = n => true;
            UpdateAction = n => { };

            ConnectorIn = new ExpressionConnectorViewModel(new ExpressionConnector(ConnectorType.In, expressionObject.ConnectorIn), _diagramViewModel);
            ConnectorOut = new ExpressionConnectorViewModel(new ExpressionConnector(ConnectorType.Out, expressionObject.ConnectorOut), _diagramViewModel);
            RaisePropertyChanged("ConvertDirection");
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="TwoInOneOutExpressionNode"/> class.
        /// </summary>
        /// <param name="diagramViewModel">The diagram view model.</param>
        /// <param name="expressionObject">The expression object.</param>
        /// <exception cref="System.ArgumentNullException">expressionObject</exception>
        public TwoInOneOutExpressionNode(IDiagramViewModel diagramViewModel, TwoInOneOutExpression expressionObject)
            : base(expressionObject)
        {
            if (expressionObject == null) throw new ArgumentNullException("expressionObject");

            _diagramViewModel = diagramViewModel;
            IsValidFunc = n => true;
            UpdateAction = n => { };

            SetConnector1In(new ExpressionConnectorViewModel(new ExpressionConnector(ConnectorType.In, expressionObject.Connector1In), _diagramViewModel));
            SetConnector2In(new ExpressionConnectorViewModel(new ExpressionConnector(ConnectorType.In, expressionObject.Connector2In), _diagramViewModel));
            ConnectorOut = new ExpressionConnectorViewModel(new ExpressionConnector(ConnectorType.Out, expressionObject.ConnectorOut), _diagramViewModel);
        }
        /// <summary>
        /// Inserts the subconnectors.
        /// </summary>
        /// <param name="connector">The connector.</param>
        /// <param name="loadWhenNecessary">if set to <c>true</c> [load when necessary].</param>
        /// <param name="recursiveExpand">if set to <c>true</c> [recursive expand].</param>
        /// <param name="item">The item.</param>
        private void InsertSubconnectors(ExpressionConnectorViewModel connector, bool loadWhenNecessary, bool recursiveExpand, ExpressionConnector item)
        {
            var idx = ConnectorsOut.IndexOf(connector);
            var newConnectors = new List<ExpressionConnectorViewModel>();
            foreach (var sc in item.GetSubconnectors().OrderBy(x => x.Name))
            {
                item.SubconnectorsLoaded = true;
                var newConnector = new ExpressionConnectorViewModel(new ExpressionConnector(ConnectorType.Out, sc), _diagramViewModel) { IndentLevel = connector.IndentLevel + 1 };
                ConnectorsOut.Insert(++idx, newConnector);
                newConnectors.Add(newConnector);                
            }
            
            if (recursiveExpand)
            {                
                foreach (var newConnector in newConnectors)
                {
                    var connectorItem = newConnector.Item as ExpressionConnector;
                    if (connectorItem != null && 
                        connectorItem.IsConnectorsGroup && 
                        connectorItem.IsConnectorsGroupCollapsed)
                    {
                        continue;
                    }

                    ExpandSubconnectors(newConnector, loadWhenNecessary, true);
                }
            }

            item.Refresh();
            _diagramViewModel.RaiseForceRelayout();
        }
        /// <summary>
        /// Expands the subconnectors.
        /// </summary>
        /// <param name="connector">The connector.</param>
        /// <param name="loadWhenNecessary">if set to <c>true</c> [load when necessary].</param>
        /// <param name="recursiveExpand">if set to <c>true</c> [recursive expand].</param>
        private void ExpandSubconnectors(ExpressionConnectorViewModel connector, bool loadWhenNecessary, bool recursiveExpand)
        {
            var item = (ExpressionConnector)connector.Item;
            if (item.HasSubconnectors)
            {
                if (loadWhenNecessary && !item.IsConnectorsGroup)
                {
                    _diagramViewModel.IsBusy = true;
                    item.LoadSubconnectors(() =>
                    {
                        InsertSubconnectors(connector, true, recursiveExpand, item);
                        item.IsConnectorsGroupCollapsed = !item.SubconnectorsLoaded;

                        _diagramViewModel.IsBusy = false;
                    });
                }
                else
                {
                    InsertSubconnectors(connector, false, recursiveExpand, item);
                    item.IsConnectorsGroupCollapsed = !item.SubconnectorsLoaded;
                }
            }
            _diagramViewModel.RaiseForceRelayout();
        }
        /// <summary>
        /// Deletes the subconnectors.
        /// </summary>
        /// <param name="connector">The connector.</param>
        /// <param name="loadWhenNecessary">if set to <c>true</c> [load when necessary].</param>
        /// <param name="item">The item.</param>
        private void DeleteSubconnectors(ExpressionConnectorViewModel connector, bool loadWhenNecessary, ExpressionConnector item)
        {
            foreach (var sc in item.GetSubconnectors().OrderBy(x => x.Name))
            {
                var node = ConnectorsOut.FirstOrDefault(x => x.Item.Id == sc.Id);
                if (node != null)
                {
                    if (sc.HasSubfields)
                    {
                        var newConnector = new ExpressionConnectorViewModel(new ExpressionConnector(ConnectorType.Out, sc), _diagramViewModel) { IndentLevel = connector.IndentLevel };
                        CollapseSubconnectors(newConnector, loadWhenNecessary);
                    }
                    item.SubconnectorsLoaded = false;
                    ConnectorsOut.Remove(node);
                }
            }

            item.IsConnectorsGroupCollapsed = !item.SubconnectorsLoaded;

            item.ClearSubconnectors();
        }
        /// <summary>
        /// Determines whether the specified connector has connection.
        /// </summary>
        /// <param name="connector">The connector.</param>
        private bool HasConnection(ExpressionConnectorViewModel connector)
        {
            var item = (ExpressionConnector)connector.Item;

            if (item.HasSubconnectors)
            {
                foreach (var sc in item.GetSubconnectors().OrderBy(x => x.Name))
                {
                    var node = ConnectorsOut.FirstOrDefault(x => x.Item.Id == sc.Id);
                    if (node != null)
                    {
                        if (node.IsConnected) return true;

                        if (sc.HasSubfields)
                        {
                            var newConnector = new ExpressionConnectorViewModel(new ExpressionConnector(ConnectorType.Out, sc), _diagramViewModel) { IndentLevel = connector.IndentLevel };
                            if (HasConnection(newConnector))
                            {
                                return true;
                            }
                        }
                    }
                }
            }

            return false;
        }
        /// <summary>
        /// Collapses the subconnectors.
        /// </summary>
        /// <param name="connector">The connector.</param>
        /// <param name="loadWhenNecessary">if set to <c>true</c> [load when necessary].</param>
        private void CollapseSubconnectors(ExpressionConnectorViewModel connector, bool loadWhenNecessary)
        {
            var item = (ExpressionConnector)connector.Item;

            if (item.HasSubconnectors && loadWhenNecessary)
            {
                DeleteSubconnectors(connector, true, item);
            }
            
        }
 /// <summary>
 /// Expands the subconnectors command execute.
 /// </summary>
 /// <param name="connector">The connector.</param>
 private void ExpandSubconnectorsCommandExecute(ExpressionConnectorViewModel connector)
 {
     ExpandSubconnectors(connector, true, false);
 }
 /// <summary>
 /// Collapses the subconnectors command execute.
 /// </summary>
 /// <param name="connector">The connector.</param>
 private void CollapseSubconnectorsCommandExecute(ExpressionConnectorViewModel connector)
 {
     if (HasConnection(connector))
     {
         _diagramViewModel.ThePopupFactory.NotifyFailure("Can not collapse.\nOne or more connections are used");
         return;
     }
     CollapseSubconnectors(connector, true);
     _diagramViewModel.RaiseForceRelayout();
 }
        /// <summary>
        /// Adds the fields as connectors.
        /// </summary>
        /// <param name="diagramViewModel">The diagram view model.</param>
        /// <param name="expressionObject">The expression object.</param>
        private void AddFieldsAsConnectors(IDiagramViewModel diagramViewModel, SourceFieldList expressionObject)
        {
            ConnectorsOut.Clear();
            foreach (var node in expressionObject.Fields.OrderBy(x => x.Name))
            {
                var connector = new ExpressionConnectorViewModel(new ExpressionConnector(ConnectorType.Out, node), diagramViewModel);
                ConnectorsOut.Add(connector);

                ExpandSubconnectors(connector, false, true);
            }
        }
        public void CanConnectTo_WhenConnectionValidatorIsUsed_Disallow()
        {
            var diagramViewModel = Mock.Create<IDiagramViewModel>();
            var sourceConnector = new ExpressionConnector(ConnectorType.Out, new ConnectorOut(Mock.Create<ExpressionObjectBase>()));
            sourceConnector.DataType = NodeDataType.CrossReference;
            Mock.Arrange(() => sourceConnector.Connector).Returns(Mock.Create<IConnectorOut>);

            var vm = new ExpressionConnectorViewModel(sourceConnector, diagramViewModel);

            var destinationItemMock = Mock.Create<IConnectorViewModel>();
            var destinationConnector = new ExpressionConnector(ConnectorType.In, new ConnectorIn(Mock.Create<ExpressionObjectBase>()));
            destinationConnector.DataType = NodeDataType.CrossReference;
            var connector = Mock.Create<IConnectorIn>();
            var validator = new CommonConnectionValidator();
            Mock.Arrange(() => validator.CanConnect(Arg.IsAny<IConnectorOut>(), Arg.IsAny<IConnectorIn>()))
                .Returns(ConnectivityState.Define(false, "Validation failed"));
            Mock.Arrange(() => connector.Validator).Returns(validator);
            Mock.Arrange(() => destinationConnector.Connector).Returns(connector);
            Mock.Arrange(() => destinationItemMock.Item).Returns(destinationConnector);

            var state = vm.CanConnectTo(destinationItemMock, Mock.Create<ICollection<IDiagramItemViewModel>>());

            Assert.IsFalse(state.CanConnect);
            Assert.AreEqual("Validation failed", state.JustificationMessage);
        }
        public void CanConnectTo_WhenTypeMismatch_Disallow()
        {
            var diagramViewModel = Mock.Create<IDiagramViewModel>();
            var sourceConnector = new ExpressionConnector(ConnectorType.Out, new ConnectorOut(Mock.Create<ExpressionObjectBase>()));
            sourceConnector.DataType = NodeDataType.Choice;

            var vm = new ExpressionConnectorViewModel(sourceConnector, diagramViewModel);

            var destinationItemMock = Mock.Create<IConnectorViewModel>();
            var destinationConnector = new ExpressionConnector(ConnectorType.In, new ConnectorIn(Mock.Create<ExpressionObjectBase>()));
            destinationConnector.DataType = NodeDataType.CrossReference;
            Mock.Arrange(() => destinationItemMock.Item).Returns(destinationConnector);

            var state = vm.CanConnectTo(destinationItemMock, Mock.Create<ICollection<IDiagramItemViewModel>>());

            Assert.IsFalse(state.CanConnect);
            Assert.AreEqual(
                string.Format(CultureInfo.InvariantCulture,
                    LanguageService.Translate("Warn_ExpressionBuilder_TypesAreIncompatible"),
                    sourceConnector.DataType, destinationConnector.DataType),
                state.JustificationMessage);
        }
 public void PropertiesTests()
 {
     var diagramViewModel = Mock.Create<IDiagramViewModel>();
     //var expressionConnectorMock = Mock.Create<ExpressionConnector>();
     var vm = new ExpressionConnectorViewModel(new ExpressionConnector(ConnectorType.In, new ConnectorIn(Mock.Create<ExpressionObjectBase>())), diagramViewModel);
     
     TestsHelper.TestPublicDeclaredPropertiesGetSet(vm, true, x=>x.Item, x=>x.IsConnected, x=>x.Left, x=>x.Top, x=>x.IsKey);
 }
        /// <summary>
        /// Initializes a new instance of the <see cref="ConstantExpressionNode"/> class.
        /// </summary>
        /// <param name="diagramViewModel">The diagram view model.</param>
        /// <param name="expressionObject">The expression object.</param>
        /// <exception cref="System.ArgumentNullException">expressionObject</exception>
        public ConstantExpressionNode(IDiagramViewModel diagramViewModel, ConstantExpression expressionObject)
            : base(expressionObject)
        {
            if (expressionObject == null) throw new ArgumentNullException("expressionObject");
            _diagramViewModel = diagramViewModel;

            IsValidFunc = n => true;
            UpdateAction = n => { };

            Value = expressionObject.Value;

            ConnectorOut = new ExpressionConnectorViewModel(new ExpressionConnector(ConnectorType.Out, expressionObject.ConnectorOut), _diagramViewModel);
        }