/*
 * Polyfills for things that are missing in Duktape.
 * Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 */
Error.prototype.toString = function () {
    return 'JavaScript ERROR: ' + this.name + ': ' + this.message + ' (at line ' + this.lineNumber + ')';
};

Object.defineProperty(Object.prototype, '__defineGetter__', {
    value: function(name, func) {Object.defineProperty(this, name, {get: func, enumerable: true})},
    configurable: true,
    enumerable: false
});
Object.defineProperty(Object.prototype, '__defineSetter__', {
    value: function(name, func) {Object.defineProperty(this, name, {set: func, enumerable: true})},
    configurable: true,
    enumerable: false
});

// ES6 String.includes (https://github.com/mathiasbynens/String.prototype.includes/blob/master/includes.js)
if (!String.prototype.includes) {
    (function() {
        'use strict'; // needed to support `apply`/`call` with `undefined`/`null`
        var toString = {}.toString;
        var defineProperty = (function() {
            // IE 8 only supports `Object.defineProperty` on DOM elements
            try {
                var object = {};
                var $defineProperty = Object.defineProperty;
                var result = $defineProperty(object, object, object) && $defineProperty;
            } catch(error) {}
            return result;
        }());
        var indexOf = ''.indexOf;
        var includes = function(search) {
            if (this == null) {
                throw TypeError();
            }
            var string = String(this);
            if (search && toString.call(search) == '[object RegExp]') {
                throw TypeError();
            }
            var stringLength = string.length;
            var searchString = String(search);
            var searchLength = searchString.length;
            var position = arguments.length > 1 ? arguments[1] : undefined;
            // `ToInteger`
            var pos = position ? Number(position) : 0;
            if (pos != pos) { // better `isNaN`
                pos = 0;
            }
            var start = Math.min(Math.max(pos, 0), stringLength);
            // Avoid the `indexOf` call if no match is possible
            if (searchLength + start > stringLength) {
                return false;
            }
            return indexOf.call(string, searchString, pos) != -1;
        };
        if (defineProperty) {
            defineProperty(String.prototype, 'includes', {
                'value': includes,
                'configurable': true,
                'writable': true
            });
        } else {
            String.prototype.includes = includes;
        }
    }());
}

// ES6 Array.includes (https://github.com/kevlatus/polyfill-array-includes/blob/master/array-includes.js)
if (!Array.prototype.includes) {
    Object.defineProperty(Array.prototype, 'includes', {
        value: function (searchElement, fromIndex) {

            // 1. Let O be ? ToObject(this value).
            if (this == null) {
                throw new TypeError('"this" is null or not defined');
            }

            var o = Object(this);

            // 2. Let len be ? ToLength(? Get(O, "length")).
            var len = o.length >>> 0;

            // 3. If len is 0, return false.
            if (len === 0) {
                return false;
            }

            // 4. Let n be ? ToInteger(fromIndex).
            //    (If fromIndex is undefined, this step produces the value 0.)
            var n = fromIndex | 0;

            // 5. If n ≥ 0, then
            //  a. Let k be n.
            // 6. Else n < 0,
            //  a. Let k be len + n.
            //  b. If k < 0, let k be 0.
            var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);

            function sameValueZero(x, y) {
                return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y));
            }

            // 7. Repeat, while k < len
            while (k < len) {
                // a. Let elementK be the result of ? Get(O, ! ToString(k)).
                // b. If SameValueZero(searchElement, elementK) is true, return true.
                // c. Increase k by 1.
                if (sameValueZero(o[k], searchElement)) {
                    return true;
                }
                k++;
            }

            // 8. Return false
            return false;
        }
    });
}

// ES6 String.startWith (https://github.com/mathiasbynens/String.prototype.startsWith/blob/master/startswith.js)
if (!String.prototype.startsWith) {
    (function() {
        'use strict'; // needed to support `apply`/`call` with `undefined`/`null`
        var defineProperty = (function() {
            // IE 8 only supports `Object.defineProperty` on DOM elements
            try {
                var object = {};
                var $defineProperty = Object.defineProperty;
                var result = $defineProperty(object, object, object) && $defineProperty;
            } catch(error) {}
            return result;
        }());
        var toString = {}.toString;
        var startsWith = function(search) {
            if (this == null) {
                throw TypeError();
            }
            var string = String(this);
            if (search && toString.call(search) == '[object RegExp]') {
                throw TypeError();
            }
            var stringLength = string.length;
            var searchString = String(search);
            var searchLength = searchString.length;
            var position = arguments.length > 1 ? arguments[1] : undefined;
            // `ToInteger`
            var pos = position ? Number(position) : 0;
            if (pos != pos) { // better `isNaN`
                pos = 0;
            }
            var start = Math.min(Math.max(pos, 0), stringLength);
            // Avoid the `indexOf` call if no match is possible
            if (searchLength + start > stringLength) {
                return false;
            }
            var index = -1;
            while (++index < searchLength) {
                if (string.charCodeAt(start + index) != searchString.charCodeAt(index)) {
                    return false;
                }
            }
            return true;
        };
        if (defineProperty) {
            defineProperty(String.prototype, 'startsWith', {
                'value': startsWith,
                'configurable': true,
                'writable': true
            });
        } else {
            String.prototype.startsWith = startsWith;
        }
    }());
}

// ES6 WeakMap (https://github.com/polygonplanet/weakmap-polyfill/blob/master/weakmap-polyfill.js)
(function(self) {
    'use strict';

    if (self.WeakMap) {
        return;
    }

    var hasOwnProperty = Object.prototype.hasOwnProperty;
    var defineProperty = function(object, name, value) {
        if (Object.defineProperty) {
            Object.defineProperty(object, name, {
                configurable: true,
                writable: true,
                value: value
            });
        } else {
            object[name] = value;
        }
    };

    self.WeakMap = (function() {

        // ECMA-262 23.3 WeakMap Objects
        function WeakMap() {
            if (this === void 0) {
                throw new TypeError("Constructor WeakMap requires 'new'");
            }

            defineProperty(this, '_id', genId('_WeakMap'));

            // ECMA-262 23.3.1.1 WeakMap([iterable])
            if (arguments.length > 0) {
                // Currently, WeakMap `iterable` argument is not supported
                throw new TypeError('WeakMap iterable is not supported');
            }
        }

        // ECMA-262 23.3.3.2 WeakMap.prototype.delete(key)
        defineProperty(WeakMap.prototype, 'delete', function(key) {
            checkInstance(this, 'delete');

            if (!isObject(key)) {
                return false;
            }

            var entry = key[this._id];
            if (entry && entry[0] === key) {
                delete key[this._id];
                return true;
            }

            return false;
        });

        // ECMA-262 23.3.3.3 WeakMap.prototype.get(key)
        defineProperty(WeakMap.prototype, 'get', function(key) {
            checkInstance(this, 'get');

            if (!isObject(key)) {
                return void 0;
            }

            var entry = key[this._id];
            if (entry && entry[0] === key) {
                return entry[1];
            }

            return void 0;
        });

        // ECMA-262 23.3.3.4 WeakMap.prototype.has(key)
        defineProperty(WeakMap.prototype, 'has', function(key) {
            checkInstance(this, 'has');

            if (!isObject(key)) {
                return false;
            }

            var entry = key[this._id];
            if (entry && entry[0] === key) {
                return true;
            }

            return false;
        });

        // ECMA-262 23.3.3.5 WeakMap.prototype.set(key, value)
        defineProperty(WeakMap.prototype, 'set', function(key, value) {
            checkInstance(this, 'set');

            if (!isObject(key)) {
                throw new TypeError('Invalid value used as weak map key');
            }

            var entry = key[this._id];
            if (entry && entry[0] === key) {
                entry[1] = value;
                return this;
            }

            defineProperty(key, this._id, [key, value]);
            return this;
        });


        function checkInstance(x, methodName) {
            if (!isObject(x) || !hasOwnProperty.call(x, '_id')) {
                throw new TypeError(
                    methodName + ' method called on incompatible receiver ' +
                    typeof x
                );
            }
        }

        function genId(prefix) {
            return prefix + '_' + rand() + '.' + rand();
        }

        function rand() {
            return Math.random().toString().substring(2);
        }


        defineProperty(WeakMap, '_polyfill', true);
        return WeakMap;
    })();


    function isObject(x) {
        return Object(x) === x;
    }

})(
    typeof self !== 'undefined' ? self :
        typeof window !== 'undefined' ? window :
            typeof global !== 'undefined' ? global : this
);

