//static Object GetNestedContextIfAny( Object context, String path )
		//{
		//	var segements = path.Split( new[] { '.' }, StringSplitOptions.RemoveEmptyEntries );
		//	if ( context != null && segements.Length > 1 )
		//	{

		//	}

		//	return context;
		//}

		/// <summary>
		/// Tries to generate command data.
		/// </summary>
		/// <param name="path">The path.</param>
		/// <param name="dataContext">The data context.</param>
		/// <param name="data">The data.</param>
		/// <returns></returns>
		public virtual Boolean TryGenerateCommandData( PropertyPath path, Object dataContext, out CommandData data )
		{
			var propertyPath = path.Path;
			var nestedProperties = propertyPath
				.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
			var propertyLevel = 0;
			while (dataContext != null && propertyLevel < nestedProperties.Length-1)
			{
				var currentProperty = nestedProperties[propertyLevel];
				var dataContextType = dataContext.GetType();
				var pi = dataContextType.GetProperty(currentProperty);
				if (pi == null)
				{
					logger.Error("Cannot find any property named: {0}.", currentProperty);
					dataContext = null;
					break;
				}
				dataContext = pi.GetValue(dataContext, null);
				propertyLevel++;
				propertyPath = nestedProperties[propertyLevel];
			}

			if ( dataContext == null )
			{
				data = null;
				return false;
			}

			var methodName = GetExpectedMethodName( propertyPath );
			var factName = String.Concat( "Can", methodName );
			var properties = dataContext.GetType().GetProperties();

			var commandData = dataContext.GetType()
				.GetMethods()
				.Where( mi => mi.Name.Equals( methodName ) )
				.Select( mi =>
				{
					var prms = mi.GetParameters();

					return new CommandData()
					{
						DataContext = dataContext,
						FastDelegate = mi.CreateVoidDelegate(),

						Fact = properties.Where( pi =>
						{
							return pi.PropertyType == typeof( Fact ) && pi.Name.Equals( factName );
						} )
						.Select( pi =>
						{
							var fact = ( Fact )pi.GetValue( dataContext, null );
							return fact;
						} )
						.SingleOrDefault(),

						BooleanFact = properties.Where( pi =>
						{
							return dataContext is INotifyPropertyChanged
								&& pi.PropertyType == typeof( Boolean )
								&& pi.Name.Equals( factName );
						} )
						.Select( pi => new BooleanFact
						{
							FastGetter = dataContext.CreateFastPropertyGetter<Boolean>( pi ),
							Name = pi.Name
						} )
						.SingleOrDefault(),

						HasParameter = prms.Length == 1,
						ParameterType = prms.Length != 1 ? null : prms[ 0 ].ParameterType,
						KeyBindings = mi.GetAttributes<KeyBindingAttribute>(),
						Description = mi.GetAttribute<CommandDescriptionAttribute>()
					};
				} )
				.SingleOrDefault();

			if ( commandData == null )
			{
				logger.Warning( "Cannot find any method named: {0}.", methodName );
			}

			data = commandData;

			return commandData != null;
		}
        //static Object GetNestedContextIfAny( Object context, String path )
        //{
        //	var segements = path.Split( new[] { '.' }, StringSplitOptions.RemoveEmptyEntries );
        //	if ( context != null && segements.Length > 1 )
        //	{

        //	}

        //	return context;
        //}

        /// <summary>
        /// Tries to generate command data.
        /// </summary>
        /// <param name="path">The path.</param>
        /// <param name="dataContext">The data context.</param>
        /// <param name="data">The data.</param>
        /// <returns></returns>
        public virtual Boolean TryGenerateCommandData(PropertyPath path, Object dataContext, out CommandData data)
        {
            var propertyPath     = path.Path;
            var nestedProperties = propertyPath
                                   .Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
            var propertyLevel = 0;

            while (dataContext != null && propertyLevel < nestedProperties.Length - 1)
            {
                var currentProperty = nestedProperties[propertyLevel];
                var dataContextType = dataContext.GetType();
                var pi = dataContextType.GetProperty(currentProperty);
                if (pi == null)
                {
                    logger.Error("Cannot find any property named: {0}.", currentProperty);
                    dataContext = null;
                    break;
                }
                dataContext = pi.GetValue(dataContext, null);
                propertyLevel++;
                propertyPath = nestedProperties[propertyLevel];
            }

            if (dataContext == null)
            {
                data = null;
                return(false);
            }

            var methodName = GetExpectedMethodName(propertyPath);
            var factName   = String.Concat("Can", methodName);
            var properties = dataContext.GetType().GetProperties();

            var commandData = dataContext.GetType()
                              .GetMethods()
                              .Where(mi => mi.Name.Equals(methodName))
                              .Select(mi =>
            {
                var prms = mi.GetParameters();

                return(new CommandData()
                {
                    DataContext = dataContext,
                    FastDelegate = mi.CreateVoidDelegate(),

                    Fact = properties.Where(pi =>
                    {
                        return pi.PropertyType == typeof(Fact) && pi.Name.Equals(factName);
                    })
                           .Select(pi =>
                    {
                        var fact = ( Fact )pi.GetValue(dataContext, null);
                        return fact;
                    })
                           .SingleOrDefault(),

                    BooleanFact = properties.Where(pi =>
                    {
                        return dataContext is INotifyPropertyChanged &&
                        pi.PropertyType == typeof(Boolean) &&
                        pi.Name.Equals(factName);
                    })
                                  .Select(pi => new BooleanFact
                    {
                        FastGetter = dataContext.CreateFastPropertyGetter <Boolean>(pi),
                        Name = pi.Name
                    })
                                  .SingleOrDefault(),

                    HasParameter = prms.Length == 1,
                    ParameterType = prms.Length != 1 ? null : prms[0].ParameterType,
                    KeyBindings = mi.GetAttributes <KeyBindingAttribute>(),
                    Description = mi.GetAttribute <CommandDescriptionAttribute>()
                });
            })
                              .SingleOrDefault();

            if (commandData == null)
            {
                logger.Warning("Cannot find any method named: {0}.", methodName);
            }

            data = commandData;

            return(commandData != null);
        }
		public virtual IDelegateCommand CreateCommand( CommandData commandData )
		{
			var text = ( commandData.Description == null ) ?
						String.Empty :
						commandData.Description.DisplayText;

			var command = ( DelegateCommand )DelegateCommand.Create( text );
			command.SetData( commandData );

			command.OnCanExecute( o =>
			{
				var data = command.GetData<CommandData>();
				if ( data.Fact != null )
				{
					return data.Fact.Eval( o );
				}
				else if ( data.BooleanFact != null )
				{
					var can = data.BooleanFact.FastGetter();
					return can;
				}

				return true;
			} )
				.OnExecute( o =>
				{
					var data = command.GetData<CommandData>();
					if ( data.HasParameter )
					{
						var prm = o;
						if ( o is IConvertible )
						{
							prm = Convert.ChangeType( o, data.ParameterType );
						}

						data.FastDelegate( data.DataContext, new[] { prm } );
					}
					else
					{
						data.FastDelegate( data.DataContext, null );
					}
				} );

			if ( commandData.KeyBindings != null )
			{
				commandData.KeyBindings
					.ForEach( kb => command.AddKeyGesture( kb.Key, kb.Modifiers ) );
			}

			IMonitor monitor = null;

			if ( commandData.Fact != null )
			{
				monitor = commandData.Fact;
			}
			else if ( commandData.BooleanFact != null )
			{
				monitor = PropertyObserver.For( ( INotifyPropertyChanged )commandData.DataContext )
						.Observe( commandData.BooleanFact.Name );
			}

			if ( command != null && monitor != null )
			{
				command.AddMonitor( monitor );
				commandData.Monitor = monitor;
			}

			return command;
		}
        public virtual IDelegateCommand CreateCommand(CommandData commandData)
        {
            var text = (commandData.Description == null) ?
                       String.Empty :
                       commandData.Description.DisplayText;

            var command = ( DelegateCommand )DelegateCommand.Create(text);

            command.SetData(commandData);

            command.OnCanExecute(o =>
            {
                var data = command.GetData <CommandData>();
                if (data.Fact != null)
                {
                    return(data.Fact.Eval(o));
                }
                else if (data.BooleanFact != null)
                {
                    var can = data.BooleanFact.FastGetter();
                    return(can);
                }

                return(true);
            })
            .OnExecute(o =>
            {
                var data = command.GetData <CommandData>();
                if (data.HasParameter)
                {
                    var prm = o;
                    if (o is IConvertible)
                    {
                        prm = Convert.ChangeType(o, data.ParameterType);
                    }

                    data.FastDelegate(data.DataContext, new[] { prm });
                }
                else
                {
                    data.FastDelegate(data.DataContext, null);
                }
            });

            if (commandData.KeyBindings != null)
            {
                commandData.KeyBindings
                .ForEach(kb => command.AddKeyGesture(kb.Key, kb.Modifiers));
            }

            IMonitor monitor = null;

            if (commandData.Fact != null)
            {
                monitor = commandData.Fact;
            }
            else if (commandData.BooleanFact != null)
            {
                monitor = PropertyObserver.For(( INotifyPropertyChanged )commandData.DataContext)
                          .Observe(commandData.BooleanFact.Name);
            }

            if (command != null && monitor != null)
            {
                command.AddMonitor(monitor);
                commandData.Monitor = monitor;
            }

            return(command);
        }