﻿namespace Caliburn.Micro
{
    using System.Windows;

    /// <summary>
    /// Hosts dependency properties for binding.
    /// </summary>
    public static class Bind
    {
        /// <summary>
        /// Allows binding on an existing view.
        /// </summary>
        public static DependencyProperty ModelProperty =
            DependencyProperty.RegisterAttached(
                "Model",
                typeof(object),
                typeof(Bind),
                new PropertyMetadata(new PropertyChangedCallback(ModelChanged))
                );

        /// <summary>
        /// Gets the model to bind to.
        /// </summary>
        /// <param name="dependencyObject">The dependency object to bind to.</param>
        /// <returns>The model.</returns>
        public static object GetModel(DependencyObject dependencyObject)
        {
            return dependencyObject.GetValue(ModelProperty);
        }

        /// <summary>
        /// Sets the model to bind to.
        /// </summary>
        /// <param name="dependencyObject">The dependency object to bind to.</param>
        /// <param name="value">The model.</param>
        public static void SetModel(DependencyObject dependencyObject, object value)
        {
            dependencyObject.SetValue(ModelProperty, value);
        }

        static void ModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (Execute.InDesignMode || e.NewValue == null || e.NewValue == e.OldValue)
                return;

            var fe = d as FrameworkElement;
            if (fe == null)
                return;

            View.ExecuteOnLoad(fe, delegate {
                var target = e.NewValue;
                var containerKey = e.NewValue as string;

                if(containerKey != null)
                    target = IoC.GetInstance(null, containerKey);

                d.SetValue(View.IsScopeRootProperty, true);

                string context = string.IsNullOrEmpty(fe.Name)
                    ? fe.GetHashCode().ToString()
                    : fe.Name;

                ViewModelBinder.Bind(target, d, context);
            });
        }
    }
}