// Create new instance of plugin for given channel
        internal NKScriptValueNative(string ns, NKScriptChannelProtocol channel, int instanceid, object[] args, bool create) : base(ns, channel.context, null)
        {
            if (create != true)
            {
                throw new ArgumentException();
            }

            this._channel    = channel;
            this._instanceid = instanceid;

            Type cls         = channel.typeInfo.pluginType;
            var  constructor = channel.typeInfo.DefaultConstructor();

            if (constructor == null || !constructor.isConstructor())
            {
                throw new ArgumentException(String.Format("!Plugin class {0} is not a constructor"), cls.Name);
            }

            object[] argsWrapped = args.Select(wrapScriptObject).ToArray <object>();

            NKScriptValue promise = null;
            var           arity   = constructor.arity;

            if (arity == argsWrapped.Length - 1 || arity < 0)
            {
                promise = argsWrapped.Last() as NKScriptValue;
                argsWrapped.Take(argsWrapped.Length - 1).ToArray();
            }
            //   if (constructor.name == "initByScriptWithArguments:")
            //   {
            //       arguments = [arguments]
            //  }
            // TO DO map nulls to nulls if needed
            object instance = NKScriptInvocation.construct(cls, (ConstructorInfo)constructor.method, argsWrapped);

            if (instance == null)
            {
                throw new ArgumentException(String.Format("!Failed to create instance for plugin class {0}"), cls.Name);
            }
            proxy = bindObject(instance);
            syncProperties();
            if (promise != null)
            {
                promise.invokeMethod("resolve", new[] { this });
            }
        }
        private void unbindObject(object obj)
        {
            _channel.removeInstance(_instanceid);
            _nativeObject = null;
            obj.setNKScriptValue(null);

            var typeinfo = _channel.typeInfo;

            if (typeinfo.hasSettableProperties)
            {
                var observable = obj as System.ComponentModel.INotifyPropertyChanged;
                if (observable == null)
                {
                    throw new ArgumentException(String.Format("!Plugin class {0} has non private settable properties but does not implement INotifyPropertyChanged"), typeinfo.pluginType.Name);
                }
                observable.PropertyChanged -= Observable_PropertyChanged;
            }
            proxy = null;
        }
        private NKScriptInvocation bindObject(object obj)
        {
            _nativeObject = obj;
            var queue = _channel.queue;
            var proxy = new NKScriptInvocation(obj, queue);

            obj.setNKScriptValue(this);
            var typeinfo = _channel.typeInfo;

            if (typeinfo.hasSettableProperties)
            {
                var observable = obj as System.ComponentModel.INotifyPropertyChanged;
                if (observable == null)
                {
                    throw new ArgumentException(String.Format("!Plugin class {0} has non private settable properties but does not implement INotifyPropertyChanged"), typeinfo.pluginType.Name);
                }
                observable.PropertyChanged += Observable_PropertyChanged;
            }
            return(proxy);
        }
        internal NKScriptValueNative(object value, NKScriptContext context) : base()
        {
            Type t = value.GetType();
            NKScriptChannelProtocol channel = t.getNKScriptChannel();

            if (channel == null)
            {
                channel = t.GetTypeInfo().BaseType.getNKScriptChannel();
                if (channel == null)
                {
                    throw new MissingFieldException("Cannot find channel for NKScriptExport member " + t.Name);
                }
            }

            string pluginNS = channel.ns;
            int    id       = channel.getNativeSeq();

            _instanceid = id;
            string ns = string.Format("{0}[{1}]", pluginNS, id);

            this._channel = channel;

            // super.init(ns: ns, context: channel, origin: nil)
            _context = context;

            this.ns = ns;
            if (origin != null)
            {
                _origin = origin;
            }
            else
            {
                _origin = this;
            }
            // end super init

            channel.addInstance(id, this);
            proxy = bindObject(value);
            syncCreationWithProperties();
        }
 internal NKScriptValueNative(string ns, NKScriptChannelProtocol channel, int instanceid, object obj) : base(ns, channel.context, null)
 {
     this._channel    = channel;
     this._instanceid = instanceid;
     this.proxy       = bindObject(obj);
 }
        // Create new instance of plugin for given channel
        internal NKScriptValueNative(string ns, NKScriptChannelProtocol channel, int instanceid, object[] args, bool create) : base(ns, channel.context, null)
        {
            if (create != true)
                throw new ArgumentException();

            this._channel = channel;
            this._instanceid = instanceid;

            Type cls = channel.typeInfo.pluginType;
            var constructor = channel.typeInfo.DefaultConstructor();
            if (constructor == null || !constructor.isConstructor())
            {
                throw new ArgumentException(String.Format("!Plugin class {0} is not a constructor"), cls.Name);
            }

            object[] argsWrapped = args.Select(wrapScriptObject).ToArray<object>();

            NKScriptValue promise = null;
            var arity = constructor.arity;

            if (arity == argsWrapped.Length - 1 || arity < 0)
            {
                promise = argsWrapped.Last() as NKScriptValue;
                argsWrapped.Take(argsWrapped.Length - 1).ToArray();
            }
            //   if (constructor.name == "initByScriptWithArguments:")
            //   {
            //       arguments = [arguments]
            //  }
            // TO DO map nulls to nulls if needed
            object instance = NKScriptInvocation.construct(cls, (ConstructorInfo)constructor.method, argsWrapped);

            if (instance == null)
                throw new ArgumentException(String.Format("!Failed to create instance for plugin class {0}"), cls.Name);
            proxy = bindObject(instance);
            syncProperties();
            if (promise != null)
                promise.invokeMethod("resolve", new[] { this });
        }
        internal NKScriptValueNative(object value, NKScriptContext context) : base()
        {

            Type t = value.GetType();
            NKScriptChannelProtocol channel = t.getNKScriptChannel();
            if (channel == null)
            {
                channel = t.GetTypeInfo().BaseType.getNKScriptChannel();
                if (channel == null)
                    throw new MissingFieldException("Cannot find channel for NKScriptExport member " + t.Name);
            }

            string pluginNS = channel.ns;
            int id = channel.getNativeSeq();
            _instanceid = id;
            string ns = string.Format("{0}[{1}]", pluginNS, id);
            this._channel = channel;
          
            // super.init(ns: ns, context: channel, origin: nil)
            _context = context;

            this.ns = ns;
            if (origin != null)
                _origin = origin;
            else
                _origin = this;
            // end super init

            channel.addInstance(id, this);
            proxy = bindObject(value);
            syncCreationWithProperties();
        }
 internal NKScriptValueNative(string ns, NKScriptChannelProtocol channel, int instanceid, object obj) : base(ns, channel.context, null)
 {
     this._channel = channel;
      this._instanceid = instanceid;
      this.proxy = bindObject(obj);
 }
        private void unbindObject(object obj)
        {
            _channel.removeInstance(_instanceid);
             _nativeObject = null;
            obj.setNKScriptValue(null);

            var typeinfo = _channel.typeInfo;
            if (typeinfo.hasSettableProperties)
            {
                var observable = obj as System.ComponentModel.INotifyPropertyChanged;
                if (observable == null)
                {
                    throw new ArgumentException(String.Format("!Plugin class {0} has non private settable properties but does not implement INotifyPropertyChanged"), typeinfo.pluginType.Name);
                }
                observable.PropertyChanged -= Observable_PropertyChanged;
            }
            proxy = null;
        }
 private NKScriptInvocation bindObject(object obj) {
     _nativeObject = obj;
      var queue = _channel.queue;
     var proxy = new NKScriptInvocation(obj, queue);
     obj.setNKScriptValue(this);
     var typeinfo = _channel.typeInfo;
     if (typeinfo.hasSettableProperties)
     {
         var observable = obj as System.ComponentModel.INotifyPropertyChanged;
         if (observable == null)
         {
             throw new ArgumentException(String.Format("!Plugin class {0} has non private settable properties but does not implement INotifyPropertyChanged"), typeinfo.pluginType.Name);
         }
         observable.PropertyChanged += Observable_PropertyChanged;
     }
     return proxy;
 }