private void InitializeContext(CefBrowser browser, CefFrame frame, CefV8Context context)
        {
            if (_pluginContext == null)
            {
                Logger.Error("Could not locate plugin context for V8. Browser {0} Frame {1}", browser.Identifier, frame.Identifier);
                return;
            }

            // TODO : Put in an optimization to not create the JS Object model if the current browser is a DEV TOOLS instance
            var window = context.GetGlobal();

            foreach (var pluginId in _pluginContext.GetPluginIds())
            {
                var pluginPath = pluginId.Split('.');

                var pluginV8HostObject = window;
                var clashDetected      = false;
                for (var pluginPathSectionIndex = 0; pluginPathSectionIndex < pluginPath.Length; pluginPathSectionIndex++)
                {
                    var pathSection = pluginPath[pluginPathSectionIndex];
                    if (pluginPathSectionIndex == 0 && pathSection == "window")
                    {
                        // Fully scoped path - parent should stay as the root/global object until next section
                        continue;
                    }

                    if (pluginV8HostObject.HasValue(pathSection))
                    {
                        pluginV8HostObject = pluginV8HostObject.GetValue(pathSection);
                        if (!pluginV8HostObject.IsObject)
                        {
                            // Most likely a clash of JS paths between plugins
                            // TODO: warn that this current plugin could not be added
                            clashDetected = true;
                            break;
                        }
                    }
                    else
                    {
                        var child = CefV8Value.CreateObject(null);
                        pluginV8HostObject.SetValue(pathSection, child,
                                                    CefV8PropertyAttribute.DontEnum |
                                                    CefV8PropertyAttribute.DontDelete);
                        pluginV8HostObject = child;
                    }
                }
                if (clashDetected)
                {
                    continue;
                }

                V8PluginAdapter.Create(_pluginContext.GetPluginById(pluginId), pluginV8HostObject);
            }
        }
        /// <summary>
        /// Create an adapter for a local (in-process) plugin.
        /// </summary>
        /// <param name="router"></param>
        /// <param name="pluginContext"></param>
        /// <param name="jsPlugin"></param>
        /// <returns></returns>
        public static V8PluginAdapter CreateLocal(IV8PluginRouter router, IPluginContext pluginContext, JavaScriptPlugin jsPlugin)
        {
            if (jsPlugin == null)
            {
                return(null);
            }

            var plugin        = new LocalV8Plugin(router, pluginContext, jsPlugin);
            var pluginAdapter = new V8PluginAdapter(plugin);

            return(pluginAdapter);
        }
        /// <summary>
        /// Create an adapter for a remote (out-of-process) plugin.
        /// </summary>
        /// <param name="router"></param>
        /// <param name="pluginContext"></param>
        /// <param name="descriptor"></param>
        /// <returns></returns>
        public static V8PluginAdapter CreateRemote(IV8PluginRouter router, IPluginContext pluginContext, PluginDescriptor descriptor)
        {
            V8PluginAdapter adapter;

            if (!RemotePluginAdapterCache.TryGetValue(descriptor.PluginId, out adapter))
            {
                lock (RemotePluginAdapterCache)
                {
                    if (!RemotePluginAdapterCache.TryGetValue(descriptor.PluginId, out adapter))
                    {
                        var plugin = new RemoteV8Plugin(router, pluginContext, descriptor);
                        adapter = new V8PluginAdapter(plugin);
                        RemotePluginAdapterCache.Add(descriptor.PluginId, adapter);
                    }
                }
            }

            return(adapter);
        }
        protected CefV8Value ToCefV8Value(IV8PluginRouter router, object result)
        {
            if (result == null)
            {
                return(CefV8Value.CreateNull());
            }

            // VALUES FROM REMOTE PLUGINS
            var remoteResult = result as ResultData;

            if (remoteResult != null)
            {
                switch (remoteResult.DataType)
                {
                case ResultDataType.Scalar:
                    if (remoteResult.Items != null && remoteResult.Items.Count != 0)
                    {
                        return(ToCefV8Value(router, remoteResult.Items[0]));
                    }
                    return(CefV8Value.CreateNull());

                case ResultDataType.Array:
                {
                    var cefArray = CefV8Value.CreateArray(remoteResult.Items.Count);
                    if (remoteResult.Items != null)
                    {
                        for (var resultIndex = 0; resultIndex < remoteResult.Items.Count; ++resultIndex)
                        {
                            var cefValue = ToCefV8Value(router, remoteResult.Items[resultIndex]);
                            cefArray.SetValue(resultIndex, cefValue);
                        }
                    }
                    return(cefArray);
                }

                case ResultDataType.Dictionary:
                {
                    var cefObject = CefV8Value.CreateObject(null);
                    if (remoteResult.Items != null)
                    {
                        foreach (var dictionaryItem in remoteResult.Items)
                        {
                            if (string.IsNullOrEmpty(dictionaryItem.Name))
                            {
                                continue;
                            }
                            var cefValue = ToCefV8Value(router, dictionaryItem);
                            cefObject.SetValue(dictionaryItem.Name, cefValue, CefV8PropertyAttribute.None);
                        }
                    }
                    return(cefObject);
                }
                }
            }
            var resultItem = result as ResultItem;

            if (resultItem != null)
            {
                return(ToCefV8Value(router, (object)resultItem.DynamicPlugin ?? resultItem.PlainData));
            }
            var pluginObjectDescriptor = result as PluginDescriptor;

            if (pluginObjectDescriptor != null)
            {
                return(V8PluginAdapter.CreateRemote(router, _plugin.PluginContext, pluginObjectDescriptor).V8Object);
            }

            // VALUES FROM REMOTE OR LOCAL PLUGINS
            var plainData = result as JToken;

            if (plainData != null)
            {
                return(CefJsonValueConverter.ToCef(plainData));
            }

            // VALUES FROM LOCAL PLUGINS
            var localArray = result as object[];

            if (localArray != null)
            {
                var cefArray = CefV8Value.CreateArray(localArray.Length);
                for (var resultIndex = 0; resultIndex < localArray.Length; ++resultIndex)
                {
                    var cefValue = ToCefV8Value(router, localArray[resultIndex]);
                    cefArray.SetValue(resultIndex, cefValue);
                }
                return(cefArray);
            }
            var localPlugin = result as JavaScriptPlugin;

            if (localPlugin != null)
            {
                return(V8PluginAdapter.CreateLocal(router, _plugin.PluginContext, localPlugin).V8Object);
            }
            if (JavaScriptPlugin.IsDynamicPlugin(result))
            {
                var dynPlugin = JavaScriptPlugin.CreateFromObject(PluginProcess.Renderer, result);
                _plugin.PluginContext.PluginManager.AddLocalPlugin(dynPlugin);
                return(V8PluginAdapter.CreateLocal(router, _plugin.PluginContext, dynPlugin).V8Object);
            }

            // local C# POCO
            return(CefNativeValueConverter.ToCef(result));
        }