using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Text;
using System.Windows;
using System.Windows.Media;

namespace HandyControl.Interactivity
{
    public class SetPropertyAction : TriggerAction<FrameworkElement>
    {
        // PropertyName DependencyProperty.

        /// <summary>
        /// The property to be executed in response to the trigger.
        /// </summary>
        public string PropertyName
        {
            get { return (string)GetValue(PropertyNameProperty); }
            set { SetValue(PropertyNameProperty, value); }
        }

        public static readonly DependencyProperty PropertyNameProperty
            = DependencyProperty.Register("PropertyName", typeof(string),
            typeof(SetPropertyAction));


        // PropertyValue DependencyProperty.

        /// <summary>
        /// The value to set the property to.
        /// </summary>
        public object PropertyValue
        {
            get { return GetValue(PropertyValueProperty); }
            set { SetValue(PropertyValueProperty, value); }
        }

        public static readonly DependencyProperty PropertyValueProperty
            = DependencyProperty.Register("PropertyValue", typeof(object),
            typeof(SetPropertyAction));


        // TargetObject DependencyProperty.

        /// <summary>
        /// Specifies the object upon which to set the property.
        /// </summary>
        public object TargetObject
        {
            get { return GetValue(TargetObjectProperty); }
            set { SetValue(TargetObjectProperty, value); }
        }

        public static readonly DependencyProperty TargetObjectProperty
            = DependencyProperty.Register("TargetObject", typeof(object),
            typeof(SetPropertyAction));


        // Private Implementation.

        protected override void Invoke(object parameter)
        {
            object target = TargetObject ?? AssociatedObject;

            PropertyInfo propertyInfo = target.GetType().GetProperty(
                PropertyName,
                BindingFlags.Instance | BindingFlags.Public
                | BindingFlags.NonPublic | BindingFlags.InvokeMethod);

            if (propertyInfo == null) return;
            object tempvalue = null;

            if (propertyInfo.PropertyType == typeof(bool))
            {
                tempvalue = bool.Parse(PropertyValue.ToString());
            }
            else if (propertyInfo.PropertyType == typeof(int))
            {
                tempvalue = int.Parse(PropertyValue.ToString());
            }
            else if (propertyInfo.PropertyType == typeof(uint))
            {
                tempvalue = uint.Parse(PropertyValue.ToString());
            }
            else if (propertyInfo.PropertyType == typeof(byte))
            {
                tempvalue = byte.Parse(PropertyValue.ToString());
            }
            else if (propertyInfo.PropertyType == typeof(sbyte))
            {
                tempvalue = sbyte.Parse(PropertyValue.ToString());
            }
            else if (propertyInfo.PropertyType == typeof(ushort))
            {
                tempvalue = ushort.Parse(PropertyValue.ToString());
            }
            else if (propertyInfo.PropertyType == typeof(short))
            {
                tempvalue = short.Parse(PropertyValue.ToString());
            }
            else if (propertyInfo.PropertyType == typeof(long))
            {
                tempvalue = long.Parse(PropertyValue.ToString());
            }
            else if (propertyInfo.PropertyType == typeof(ulong))
            {
                tempvalue = ulong.Parse(PropertyValue.ToString());
            }
            else if (propertyInfo.PropertyType == typeof(float))
            {
                tempvalue = float.Parse(PropertyValue.ToString());
            }
            else if (propertyInfo.PropertyType == typeof(double))
            {
                tempvalue = double.Parse(PropertyValue.ToString());
            }
            else if(propertyInfo.PropertyType == typeof(Brush))
            {
                tempvalue = new SolidColorBrush((Color)ColorConverter.ConvertFromString(PropertyValue.ToString()));
            }
            else tempvalue = PropertyValue;
            propertyInfo.SetValue(target, tempvalue);
        }
    }

    public class InvokeAction : TriggerAction<FrameworkElement>
    {
        // PropertyName DependencyProperty.

        /// <summary>
        /// The property to be executed in response to the trigger.
        /// </summary>
        public string MethodName
        {
            get { return (string)GetValue(MethodNameProperty); }
            set { SetValue(MethodNameProperty, value); }
        }

        public static readonly DependencyProperty MethodNameProperty
            = DependencyProperty.Register("MethodName", typeof(string),
            typeof(SetPropertyAction));


        // PropertyValue DependencyProperty.

        /// <summary>
        /// The value to set the property to.
        /// </summary>
        public object ArgumentValue
        {
            get { return GetValue(ArgumentValueProperty); }
            set { SetValue(ArgumentValueProperty, value); }
        }

        public static readonly DependencyProperty ArgumentValueProperty
            = DependencyProperty.Register("ArgumentValue", typeof(object),
            typeof(SetPropertyAction));


        // TargetObject DependencyProperty.

        /// <summary>
        /// Specifies the object upon which to set the property.
        /// </summary>
        public object TargetObject
        {
            get { return GetValue(TargetObjectProperty); }
            set { SetValue(TargetObjectProperty, value); }
        }

        public static readonly DependencyProperty TargetObjectProperty
            = DependencyProperty.Register("TargetObject", typeof(object),
            typeof(SetPropertyAction));


        // Private Implementation.

        protected override void Invoke(object parameter)
        {
            object target = TargetObject ?? AssociatedObject;

            var propertyInfo = target.GetType().GetMethod(
                MethodName,
                BindingFlags.Instance | BindingFlags.Public
                | BindingFlags.NonPublic | BindingFlags.InvokeMethod);

            if (propertyInfo == null) return;
            if(propertyInfo.GetGenericArguments().Length==0)
            {
                propertyInfo.Invoke(target,new object[0]);
            }
            else if(propertyInfo.GetGenericArguments().Length == 1)
            {
                propertyInfo.Invoke(target, new object[] { ArgumentValue });
            }
            else
            {
                throw new NotSupportedException();
            }
        }
    }
}
