/// <summary>
        /// http://www.ecma-international.org/ecma-262/5.1/#sec-15.2.2.1
        /// </summary>
        /// <param name="arguments"></param>
        /// <returns></returns>
        public ObjectInstance Construct(JsValue[] arguments)
        {
            if (arguments.Length > 0)
            {
                var value = arguments[0];
                var valueObj = value.TryCast<ObjectInstance>();
                if (valueObj != null)
                {
                    return valueObj;
                }
                var type = value.Type;
                if (type == Types.String || type == Types.Number || type == Types.Boolean)
                {
                    return TypeConverter.ToObject(_engine, value);
                }
            }

            var obj = new ObjectInstance(_engine)
                {
                    Extensible = true,
                    Prototype = Engine.Object.PrototypeObject
                };

            return obj;
        }
        private string SerializeObject(ObjectInstance value)
        {
            string final;

            EnsureNonCyclicity(value);
            _stack.Push(value);
            var stepback = _indent;
            _indent += _gap;
            
            var k = _propertyList ?? value.Properties
                .Where(x => x.Value.Enumerable.HasValue && x.Value.Enumerable.Value == true)
                .Select(x => x.Key)
                .ToList();

            var partial = new List<string>();
            foreach (var p in k)
            {
                var strP = Str(p, value);
                if (strP != JsValue.Undefined)
                {
                    var member = Quote(p) + ":";
                    if (_gap != "")
                    {
                        member += " ";
                    }
                    member += strP.AsString(); // TODO:This could be undefined
                    partial.Add(member);
                }
            }
            if (partial.Count == 0)
            {
                final = "{}";
            }
            else
            {
                if (_gap == "")
                {
                    var separator = ",";
                    var properties = System.String.Join(separator, partial.ToArray());
                    final = "{" + properties + "}";
                }
                else
                {
                    var separator = ",\n" + _indent;
                    var properties = System.String.Join(separator, partial.ToArray());
                    final = "{\n" + _indent + properties + "\n" + stepback + "}";
                }                
            }
            _stack.Pop();
            _indent = stepback;
            return final;
        }
        /// <summary>
        /// http://www.ecma-international.org/ecma-262/5.1/#sec-13.2.2
        /// </summary>
        /// <param name="arguments"></param>
        /// <returns></returns>
        public ObjectInstance Construct(JsValue[] arguments)
        {
            var proto = Get("prototype").TryCast<ObjectInstance>();
            var obj = new ObjectInstance(Engine);
            obj.Extensible = true;
            obj.Prototype = proto ?? Engine.Object.PrototypeObject;

            var result = Call(obj, arguments).TryCast<ObjectInstance>();
            if (result != null)
            {
                return result;
            }
            
            return obj;
        }
        private JsValue Str(string key, ObjectInstance holder)
        {
            
            var value = holder.Get(key);
            if (value.IsObject())
            {
                var toJson = value.AsObject().Get("toJSON");
                if (toJson.IsObject())
                {
                    var callableToJson = toJson.AsObject() as ICallable;
                    if (callableToJson != null)
                    {
                        value = callableToJson.Call(value, Arguments.From(key));
                    }
                }
            }
            
            if (_replacerFunction != Undefined.Instance)
            {
                var replacerFunctionCallable = (ICallable)_replacerFunction.AsObject();
                value = replacerFunctionCallable.Call(holder, Arguments.From(key, value));
            }

            
            if (value.IsObject())
            {
                var valueObj = value.AsObject();
                switch (valueObj.Class)
                {
                    case "Number":
                        value = TypeConverter.ToNumber(value);
                        break;
                    case "String":
                        value = TypeConverter.ToString(value);
                        break;
                    case "Boolean":
                        value = TypeConverter.ToPrimitive(value);
                        break;
                    case "Array": 
                        value = SerializeArray(value.As<ArrayInstance>());
                        return value;
                    case "Object":
                        value = SerializeObject(value.AsObject());
                        return value;
                }
            }
           
            if (value == Null.Instance)
            {
                return "null";
            }

            if (value.IsBoolean() && value.AsBoolean())
            {
                return "true";
            }

            if (value.IsBoolean() && !value.AsBoolean())
            {
                return "false";
            }

            if (value.IsString())
            {
                return Quote(value.AsString());
            }

            if (value.IsNumber())
            {
                if (GlobalObject.IsFinite(Undefined.Instance, Arguments.From(value)).AsBoolean())
                {
                    return TypeConverter.ToString(value);
                }
                
                return "null";
            }

            var isCallable = value.IsObject() && value.AsObject() is ICallable;

            if (value.IsObject() && isCallable == false)
            {
                if (value.AsObject().Class == "Array")
                {
                    return SerializeArray(value.As<ArrayInstance>());
                }

                return SerializeObject(value.AsObject());
            }

            return JsValue.Undefined;
        }
 public ObjectEnvironmentRecord(Engine engine, ObjectInstance bindingObject, bool provideThis) : base(engine)
 {
     _engine = engine;
     _bindingObject = bindingObject;
     _provideThis = provideThis;
 }