using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;

namespace CPF
{
    /// <summary>
    /// 简化绑定操作
    /// </summary>
    public class BindingDescribe
    {
        internal BindingDescribe() { }

        public BindingDescribe(string sourceProperty)
        {
            PropertyName = sourceProperty;
        }
        public BindingDescribe(string sourceProperty, BindingMode binding)
        {
            PropertyName = sourceProperty;
            BindingMode = binding;
        }
        public BindingDescribe(object source, string sourceProperty, BindingMode binding)
        {
            PropertyName = sourceProperty;
            BindingMode = binding;
            Source = source;
        }
        public BindingDescribe(object source, string sourceProperty)
        {
            PropertyName = sourceProperty;
            Source = source;
        }
        public BindingDescribe(object source, string sourceProperty, Func<object, object> convert)
        {
            PropertyName = sourceProperty;
            Source = source;
            Convert = convert;
        }
        public BindingDescribe(object source, string sourceProperty, BindingMode binding, Func<object, object> convert)
        {
            BindingMode = binding;
            PropertyName = sourceProperty;
            Source = source;
            Convert = convert;
        }
        public BindingDescribe(object source, string sourceProperty, BindingMode binding, Func<object, object> convert, Func<object, object> convertBack)
        {
            BindingMode = binding;
            PropertyName = sourceProperty;
            Source = source;
            Convert = convert;
            ConvertBack = convertBack;
        }
        public BindingDescribe(object source, string sourceProperty, BindingMode binding, Func<object, object> convert, Func<object, object> convertBack, Action<Binding, object, Exception> SourceToTargetError, Action<Binding, object, Exception> TargetToSourceError)
        {
            BindingMode = binding;
            PropertyName = sourceProperty;
            Source = source;
            Convert = convert;
            ConvertBack = convertBack;
            this.SourceToTargetError = SourceToTargetError;
            this.TargetToSourceError = TargetToSourceError;
        }

        public BindingDescribe(Action<CpfObject, object> command)
        {
            Command = command;
        }

        /// <summary>
        /// 数据绑定的转换
        /// </summary>
        public Func<object, object> Convert { get; internal set; }

        public string PropertyName { get; internal set; }
        /// <summary>
        /// 简化绑定命令的命令,如果设置了该属性,则使用命令绑定
        /// </summary>
        public Action<CpfObject, object> Command { get; set; }

        //public CpfObject Owner { get; internal set; }

        /// <summary>
        /// 双向绑定,如果加数据转换器,两个转换器要对称,否则可能出现死循环或者其他错误
        /// </summary>
        /// <param name="property1"></param>
        /// <param name="property2"></param>
        /// <returns></returns>
        public static Binding operator ==(BindingDescribe property1, BindingDescribe property2)
        {
            var b = new Binding(property2.Source, property2.PropertyName, property1.PropertyName, BindingMode.TwoWay) { Convert = property2.Convert, ConvertBack = property1.Convert };
            List<Binding> list;
            var target = property1.Source as CpfObject;
            if (target == null)
            {
                throw new Exception("property1.Source必须是CpfObject");
            }
            if (!target.Bindings.binds.TryGetValue(property1.PropertyName, out list))
            {
                list = new List<Binding>();
                target.Bindings.binds.Add(property1.PropertyName, list);
            }
            list.Add(b);
            b.Owner = target;
            var source = property2.Source as CpfObject;
            if (source == null)
            {
                throw new Exception("property2.Source必须是CpfObject");
            }
            b.RegisterPropertyChanged(source);
            return b;
        }


        /// <summary>
        /// 右边数据绑定到左边,只传递一次数据
        /// </summary>
        /// <param name="property1"></param>
        /// <param name="property2"></param>
        /// <returns></returns>
        public static Binding operator !=(BindingDescribe property1, BindingDescribe property2)
        {
            var b = new Binding(property2.Source, property2.PropertyName, property1.PropertyName, BindingMode.OneTime) { Convert = property2.Convert, ConvertBack = property1.Convert };
            List<Binding> list;
            var target = property1.Source as CpfObject;
            if (target == null)
            {
                throw new Exception("property1.Source必须是CpfObject");
            }
            if (!target.Bindings.binds.TryGetValue(property1.PropertyName, out list))
            {
                list = new List<Binding>();
                target.Bindings.binds.Add(property1.PropertyName, list);
            }
            list.Add(b);
            b.Owner = target;
            b.SourceToTarget();
            return b;
        }
        /// <summary>
        /// 右边数据绑定到左边
        /// </summary>
        /// <param name="property1"></param>
        /// <param name="property2"></param>
        /// <returns></returns>
        public static Binding operator <=(BindingDescribe property1, BindingDescribe property2)
        {//可重载一元运算符  +、-、!、~
            var b = new Binding(property2.Source, property2.PropertyName, property1.PropertyName, BindingMode.OneWay) { Convert = property2.Convert, ConvertBack = property1.Convert };
            List<Binding> list; var target = property1.Source as CpfObject;
            if (target == null)
            {
                throw new Exception("property1.Source必须是CpfObject");
            }
            if (!target.Bindings.binds.TryGetValue(property1.PropertyName, out list))
            {
                list = new List<Binding>();
                target.Bindings.binds.Add(property1.PropertyName, list);
            }
            list.Add(b);
            b.Owner = target;
            var source = property2.Source as CpfObject;
            if (source == null)
            {
                throw new Exception("property2.Source必须是CpfObject");
            }
            b.RegisterPropertyChanged(source);
            b.SourceToTarget();
            return b;
        }
        /// <summary>
        /// 左边数据绑定到右边
        /// </summary>
        /// <param name="property1"></param>
        /// <param name="property2"></param>
        /// <returns></returns>
        public static Binding operator >=(BindingDescribe property1, BindingDescribe property2)
        {//可重载一元运算符  +、-、!、~
            var b = new Binding(property2.Source, property2.PropertyName, property1.PropertyName, BindingMode.OneWayToSource) { Convert = property2.Convert, ConvertBack = property1.Convert };
            List<Binding> list;
            var target = property1.Source as CpfObject;
            if (target == null)
            {
                throw new Exception("property1.Source必须是CpfObject");
            }
            if (!target.Bindings.binds.TryGetValue(property1.PropertyName, out list))
            {
                list = new List<Binding>();
                target.Bindings.binds.Add(property1.PropertyName, list);
            }
            list.Add(b);
            b.Owner = target;
            b.TargetToSource();
            //property2.Owner.PropertyChanged += b.PropertyChanged;
            return b;
        }

        /// <summary>
        /// 和DataContext的对象的属性双向绑定
        /// </summary>
        /// <param name="property1"></param>
        /// <param name="property2">DataContext的对象的属性名</param>
        /// <returns></returns>
        public static Binding operator ==(BindingDescribe property1, string property2)
        {
            var b = new Binding(null, property2, property1.PropertyName, BindingMode.TwoWay) { ConvertBack = property1.Convert };
            List<Binding> list;
            var target = property1.Source as CpfObject;
            if (target == null)
            {
                throw new Exception("property1.Source必须是CpfObject");
            }
            if (!target.Bindings.binds.TryGetValue(property1.PropertyName, out list))
            {
                list = new List<Binding>();
                target.Bindings.binds.Add(property1.PropertyName, list);
            }
            list.Add(b);
            b.Owner = target;
            var dc = target.DataContext;
            if (dc != null)
            {
                INotifyPropertyChanged n = dc as INotifyPropertyChanged;
                if (n != null)
                {
                    //n.PropertyChanged += b.PropertyChanged;
                    b.RegisterPropertyChanged(n);
                }
                b.Source = new WeakReference(dc);
                b.SourceToTarget();
            }
            return b;
        }
        /// <summary>
        /// DataContext的对象的属性数据绑定到左边,只传递一次数据
        /// </summary>
        /// <param name="property1"></param>
        /// <param name="property2">DataContext的对象的属性名</param>
        /// <returns></returns>
        public static Binding operator !=(BindingDescribe property1, string property2)
        {
            var b = new Binding(null, property2, property1.PropertyName, BindingMode.OneTime) { ConvertBack = property1.Convert };
            List<Binding> list;
            var target = property1.Source as CpfObject;
            if (target == null)
            {
                throw new Exception("property1.Source必须是CpfObject");
            }
            if (!target.Bindings.binds.TryGetValue(property1.PropertyName, out list))
            {
                list = new List<Binding>();
                target.Bindings.binds.Add(property1.PropertyName, list);
            }
            list.Add(b);
            b.Owner = target;

            var dc = target.DataContext;
            if (dc != null)
            {
                b.Source = new WeakReference(dc);
                b.SourceToTarget();
            }
            return b;
        }
        /// <summary>
        /// DataContext的对象的属性数据绑定到左边
        /// </summary>
        /// <param name="property1"></param>
        /// <param name="property2">DataContext的对象的属性名</param>
        /// <returns></returns>
        public static Binding operator <=(BindingDescribe property1, string property2)
        {
            var b = new Binding(null, property2, property1.PropertyName, BindingMode.OneWay) { ConvertBack = property1.Convert };
            List<Binding> list;
            var target = property1.Source as CpfObject;
            if (target == null)
            {
                throw new Exception("property1.Source必须是CpfObject");
            }
            if (!target.Bindings.binds.TryGetValue(property1.PropertyName, out list))
            {
                list = new List<Binding>();
                target.Bindings.binds.Add(property1.PropertyName, list);
            }
            list.Add(b);
            b.Owner = target;
            var dc = target.DataContext;
            if (dc != null)
            {
                INotifyPropertyChanged n = dc as INotifyPropertyChanged;
                if (n != null)
                {
                    //n.PropertyChanged += b.PropertyChanged;
                    b.RegisterPropertyChanged(n);
                }
                b.Source = new WeakReference(dc);
                b.SourceToTarget();
            }
            return b;
        }
        /// <summary>
        /// 左边数据绑定到DataContext的对象的属性
        /// </summary>
        /// <param name="property1"></param>
        /// <param name="property2">DataContext的对象的属性名</param>
        /// <returns></returns>
        public static Binding operator >=(BindingDescribe property1, string property2)
        {
            var b = new Binding(null, property2, property1.PropertyName, BindingMode.OneWayToSource) { ConvertBack = property1.Convert };
            List<Binding> list;
            var target = property1.Source as CpfObject;
            if (target == null)
            {
                throw new Exception("property1.Source必须是CpfObject");
            }
            if (!target.Bindings.binds.TryGetValue(property1.PropertyName, out list))
            {
                list = new List<Binding>();
                target.Bindings.binds.Add(property1.PropertyName, list);
            }
            list.Add(b);
            b.Owner = target;

            var dc = target.DataContext;
            if (dc != null)
            {
                b.Source = new WeakReference(dc);
                b.TargetToSource();
            }
            return b;
        }
        //public static BindingDescribe operator *(BindingDescribe property1, string property2)
        //{
        //    return null;
        //}
        //public static BindingDescribe operator *(BindingDescribe property1, BindingDescribe property2)
        //{
        //    return null;
        //}
        public BindingMode BindingMode { get; set; } = BindingMode.OneWay;
        public object Source { get; set; }

        public Action<Binding, object, Exception> SourceToTargetError { get; set; }
        public Action<Binding, object, Exception> TargetToSourceError { get; set; }
        public Func<object, object> ConvertBack { get; set; }

        public static implicit operator BindingDescribe(string sourceProperty)
        {
            return new BindingDescribe { PropertyName = sourceProperty };
        }
        public static explicit operator BindingDescribe(Action<CpfObject, object> command)
        {
            return new BindingDescribe { Command = command };
        }
        public static implicit operator BindingDescribe((string sourceProperty, BindingMode binding) item)
        {
            return new BindingDescribe { PropertyName = item.sourceProperty, BindingMode = item.binding };
        }
        public static implicit operator BindingDescribe((object source, string sourceProperty, BindingMode binding) item)
        {
            return new BindingDescribe { PropertyName = item.sourceProperty, Source = item.source, BindingMode = item.binding };
        }
        public static implicit operator BindingDescribe((object source, string sourceProperty) item)
        {
            return new BindingDescribe { Source = item.source, PropertyName = item.sourceProperty };
        }
        public static implicit operator BindingDescribe((object source, string sourceProperty, Func<object, object> convert) item)
        {
            return new BindingDescribe { Source = item.source, PropertyName = item.sourceProperty, Convert = item.convert };
        }
        public static implicit operator BindingDescribe((object source, string sourceProperty, BindingMode binding, Func<object, object> convert) item)
        {
            return new BindingDescribe { PropertyName = item.sourceProperty, Source = item.source, BindingMode = item.binding, Convert = item.convert };
        }
        public static implicit operator BindingDescribe((object source, string sourceProperty, BindingMode binding, Func<object, object> convert, Func<object, object> convertBack) item)
        {
            return new BindingDescribe { PropertyName = item.sourceProperty, Source = item.source, BindingMode = item.binding, Convert = item.convert, ConvertBack = item.convertBack };
        }
        public static implicit operator BindingDescribe((object source, string sourceProperty, BindingMode binding, Func<object, object> convert, Func<object, object> convertBack, Action<Binding, object, Exception> SourceToTargetError, Action<Binding, object, Exception> TargetToSourceError) item)
        {
            return new BindingDescribe { PropertyName = item.sourceProperty, Source = item.source, BindingMode = item.binding, Convert = item.convert, ConvertBack = item.convertBack, SourceToTargetError = item.SourceToTargetError, TargetToSourceError = item.TargetToSourceError };
        }

        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
    }

}