public void Dispose(JSWrapper et)
        {
            try
            {
                Element e = et.As <Element>();
                WAContext.SetAtomControl(e, null);
                WAContext.SetLogicalParent(e, null);
                WAContext.SetTemplateParent(e, null);

                //if (e is Page page)
                //{
                //    // we need to remove this page if the page is on the stack...
                //    try
                //    {
                //        // WAContext.(page);
                //    }
                //    catch (Exception ex)
                //    {
                //        System.Diagnostics.Debug.WriteLine(ex);
                //    }
                //}
            }
            catch (Exception ex) {
                System.Diagnostics.Debug.WriteLine(ex);
            }
        }
        public void VisitDescendents(JSWrapper target, JSFunction action)
        {
            Element element = target?.As <Element>();

            if (element == null)
            {
                throw new ObjectDisposedException("Cannot visit descendents of null");
            }

            var views = element as IViewContainer <View>;

            if (views == null)
            {
                return;
            }
            foreach (var e in views.Children)
            {
                var ac    = WAContext.GetAtomControl(e);
                var child = e.Wrap(Engine);
                var r     = action.Call(null, new Java.Lang.Object[] {
                    child,
                    (JSValue)ac
                });
                if ((bool)r.IsUndefined() || (bool)r.IsNull() || !((bool)r.ToBoolean()))
                {
                    continue;
                }
                VisitDescendents(JSWrapper.Register(e), action);
            }
        }
        public JSValue AtomParent(JSWrapper target, JSValue climbUp)
        {
            Element element = target.As <Element>();

            bool cu = !((bool)climbUp.IsUndefined()) && !((bool)climbUp.IsNull()) && (bool)climbUp.ToBoolean();

            if (cu)
            {
                element = element.Parent;
                if (element == null)
                {
                    return(null);
                }
            }
            do
            {
                var e = WAContext.GetAtomControl(element);
                if (e != null)
                {
                    return(e.Wrap(Engine));
                }
                element = element.Parent;
            } while (cu && element != null);
            return(null);
        }
        public void Broadcast(Page page, string str, object p = null)
        {
            var ac       = (WAContext.GetAtomControl(page) as JSValue)?.ToObject();
            var app      = ac?.GetJSPropertyValue("app")?.ToObject();
            var function = app?.GetJSPropertyValue("broadcast")?.ToFunction();

            function.Call(app, new Java.Lang.Object[] { str, p == null ? null : p.Wrap(Engine) });
        }
        public object ProvideValue(IServiceProvider serviceProvider)
        {
            var root = serviceProvider.GetService(typeof(IRootObjectProvider)) as IRootObjectProvider;

            var d = WAContext.GetImports(root.RootObject as Element);

            if (d.TryGetValue(Type, out Func <Element> f))
            {
                return(f());
            }

            throw new NotImplementedException();
        }
 public void DisposePage(Element e, bool disposeFromCLR)
 {
     if (disposeFromCLR)
     {
         var ac = (WAContext.GetAtomControl(e) as JSValue)?.ToObject();
         if (ac != null)
         {
             var func = ac.GetJSPropertyValue("dispose").ToFunction();
             func.Call(ac);
         }
         return;
     }
 }
        public JSValue TemplateParent(JSWrapper elementTarget)
        {
            Element element = elementTarget.As <Element>();

            do
            {
                var e = WAContext.GetTemplateParent(element);
                if (e != null)
                {
                    return(e.Wrap(Engine));
                }
                element = element.Parent;
            } while (element != null);
            return(null);
        }
        public void AttachControl(JSWrapper target, JSValue control)
        {
            Element element = target.As <Element>();
            var     ac      = WAContext.GetAtomControl(element);

            if (ac != null)
            {
                if (ac == control as object)
                {
                    return;
                }
                throw new InvalidOperationException("Control already attached");
            }
            WAContext.SetAtomControl(element, control);
        }
        public void SetImport(JSWrapper elementWrapper, string name, JSFunction factory)
        {
            var element = elementWrapper.As <Element>();
            var d       = WAContext.GetImports(element);

            if (d == null)
            {
                d = new Dictionary <string, Func <Element> >();
                WAContext.SetImports(element, d);
            }
            d[name] = () => {
                var t  = WAContext.GetAtomControl(element);
                var jv = factory.Call((JSObject)t.Wrap(Engine)) as JSValue;
                return(JSWrapper.FromKey(jv.ToObject().GetJSPropertyValue("element").ToString()).As <Element>());
            };
        }
        private void BindDisposer(Page page)
        {
            if (WAContext.GetDisappearHandler(page) != null)
            {
                return;
            }

            EventHandler handler = (s, e) =>
            {
                Device.BeginInvokeOnMainThread(async() =>
                {
                    await Task.Delay(100);

                    var id = WAContext.GetWAName(page);

                    if (!string.IsNullOrWhiteSpace(id))
                    {
                        AtomBridge.Instance.Broadcast(page, $"atom-window-cancel:{id}");

                        await Task.Delay(100);
                    }

                    if (page is PopupPage pp)
                    {
                        if (!Rg.Plugins.Popup.Services.PopupNavigation.Instance.PopupStack.Any(x => x == page))
                        {
                            AtomBridge.Instance.DisposePage(page, true);
                            page.Disappearing -= WAContext.GetDisappearHandler(page);
                            WAContext.SetDisappearHandler(page, null);
                        }
                        return;
                    }

                    if (!Navigation.NavigationStack.Any(x => x == page))
                    {
                        AtomBridge.Instance.DisposePage(page, true);
                        page.Disappearing -= WAContext.GetDisappearHandler(page);
                        WAContext.SetDisappearHandler(page, null);
                    }
                });
            };

            WAContext.SetDisappearHandler(page, handler);
            page.Disappearing += handler;
        }
        public static JSWrapper Register(object obj)
        {
            if (obj == null)
            {
                throw new ArgumentNullException("Cannot register null");
            }
            if (obj is JSWrapper w)
            {
                return(w);
            }
            JSWrapper wrapper = null;
            string    key     = null;

            if (obj is Element e)
            {
                key = WAContext.GetJSRefKey(e);
                if (key == null)
                {
                    key = GenerateKey(obj);
                    WAContext.SetJSRefKey(e, key);
                    lock (wrappers)
                    {
                        wrappers[key] = wrapper = new JSWrapper(new WeakReference(obj), key);
                    }
                }
                else
                {
                    wrapper = wrappers[key];
                }
                return(wrapper);
            }
            lock (wrappers)
            {
                key           = GenerateKey(obj, true);
                wrappers[key] = wrapper = new JSWrapper(new WeakReference(obj), key);
            }
            return(wrapper);
        }
        public void SetValue(JSWrapper target, string name, JSValue value)
        {
            Element view = target.As <Element>();

            if (view != null && name.Equals("name", StringComparison.OrdinalIgnoreCase))
            {
                WAContext.SetWAName(view, name);
                return;
            }

            bool isNull = (bool)value.IsNull() || (bool)value.IsUndefined();

            var pv = view.GetProperty(name);

            if (isNull)
            {
                pv.SetValue(view, null);
                return;
            }

            var pt = pv.PropertyType;



            if (pt == typeof(string))
            {
                pv.SetValue(view, value.ToString());
                return;
            }

            // check if it is an array
            if ((bool)value.IsArray())
            {
                var old = pv.GetValue(view);
                if (old is IDisposable d)
                {
                    d.Dispose();
                }
                var array = value.ToJSArray();
                pv.SetValue(view, new AtomEnumerable(array));
                return;
            }

            pt = Nullable.GetUnderlyingType(pt) ?? pt;

            if (value is JSDate date)
            {
                // conver to datetime and set...
                pv.SetValue(view, date.ToDateTime());
                return;
            }

            if (pt.IsValueType)
            {
                object clrValue = null;
                // convert...
                if (value.IsBoolean().BooleanValue())
                {
                    clrValue = value.ToBoolean().BooleanValue();
                }
                else if (value.IsNumber().BooleanValue())
                {
                    if (pt == typeof(double) || pt == typeof(float) || pt == typeof(short))
                    {
                        clrValue = value.ToNumber().DoubleValue();
                    }
                    else
                    {
                        clrValue = value.ToNumber().LongValue();
                    }
                }
                var v = Convert.ChangeType(clrValue, pt);
                pv.SetValue(view, v);
                return;
            }
            else
            {
                if (pv.PropertyType == typeof(ICommand))
                {
                    pv.SetValue(view, new AtomCommand(() => {
                        value.ToFunction().Call(null);
                    }));
                }
                else
                {
                    pv.SetValue(view, value.ToObject());
                }
            }
        }