namespace Caliburn.Micro.Core {
    using System;
    using System.Collections.Generic;
    /// 
    /// A base implementation of  
    public class ViewAware : PropertyChangedBase, IViewAware {
        readonly IDictionary views;
        /// 
        /// The default view context.
        ///  
        public static readonly object DefaultContext = new object();
        /// 
        /// The view chache for this instance.
        ///  
        protected IDictionary Views {
            get { return views; }
        }
        /// 
        /// Creates an instance of  
        public ViewAware() {
            views = new WeakValueDictionary();
        }
        /// 
        /// Raised when a view is attached.
        ///  
        public event EventHandler ViewAttached = delegate { };
        void IViewAware.AttachView(object view, object context) {
            Views[context ?? DefaultContext] = view;
            var nonGeneratedView = PlatformProvider.Current.GetFirstNonGeneratedView(view);
            PlatformProvider.Current.ExecuteOnFirstLoad(nonGeneratedView, OnViewLoaded);
            OnViewAttached(nonGeneratedView, context);
            ViewAttached(this, new ViewAttachedEventArgs {View = nonGeneratedView, Context = context});
            var activatable = this as IActivate;
            if (activatable == null || activatable.IsActive) {
                PlatformProvider.Current.ExecuteOnLayoutUpdated(nonGeneratedView, OnViewReady);
            }
            else {
                AttachViewReadyOnActivated(activatable, nonGeneratedView);
            }
        }
        static void AttachViewReadyOnActivated(IActivate activatable, object nonGeneratedView) {
            var viewReference = new WeakReference(nonGeneratedView);
            EventHandler handler = null;
            handler = (s, e) => {
                ((IActivate)s).Activated -= handler;
                var view = viewReference.Target;
                if (view != null) {
                    PlatformProvider.Current.ExecuteOnLayoutUpdated(view, ((ViewAware)s).OnViewReady);
                }
            };
            activatable.Activated += handler;
        }
        /// 
        /// Called when a view is attached.
        ///  
        /// 
        /// Called when an attached view's Loaded event fires.
        ///  
        /// 
        /// Called the first time the page's LayoutUpdated event fires after it is navigated to.
        ///  
        /// 
        /// Gets a view previously attached to this instance.
        ///  
        /// The view. 
        public virtual object GetView(object context = null) {
            object view;
            Views.TryGetValue(context ?? DefaultContext, out view);
            return view;
        }
    }
}