/* eslint-disable */
// Taken from https://github.com/Nanonid/rison at 917679fb6cafa15e2a186cd5a47163792899b321
// Uses CommonJS, AMD or browser globals to create a module.
// Based on: https://github.com/umdjs/umd/blob/master/commonjsStrict.js
(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(['exports'], factory);
    } else if (typeof exports === 'object') {
        // CommonJS
        factory(exports);
    } else {
        // Browser globals
        factory((root.rison = {}));
    }
}(this, function (exports) {
    var rison = exports;

//////////////////////////////////////////////////
//
//  the stringifier is based on
//    http://json.org/json.js as of 2006-04-28 from json.org
//  the parser is based on 
//    http://osteele.com/sources/openlaszlo/json
//

    if (typeof rison == 'undefined')
        window.rison = {};

    /**
     *  rules for an uri encoder that is more tolerant than encodeURIComponent
     *
     *  encodeURIComponent passes  ~!*()-_.'
     *
     *  we also allow              ,:@$/
     *
     */
    rison.uri_ok = {  // ok in url paths and in form query args
        '~': true, '!': true, '*': true, '(': true, ')': true,
        '-': true, '_': true, '.': true, ',': true,
        ':': true, '@': true, '$': true,
        "'": true, '/': true
    };

    /*
     * we divide the uri-safe glyphs into three sets
     *   <rison> - used by rison                         ' ! : ( ) ,
     *   <reserved> - not common in strings, reserved    * @ $ & ; =
     *
     * we define <identifier> as anything that's not forbidden
     */

    /**
     * punctuation characters that are legal inside ids.
     */
// this var isn't actually used
//rison.idchar_punctuation = "_-./~";  

    (function () {
        var l = [];
        for (var hi = 0; hi < 16; hi++) {
            for (var lo = 0; lo < 16; lo++) {
                if (hi + lo == 0) continue;
                var c = String.fromCharCode(hi * 16 + lo);
                if (!/\w|[-_.\/~]/.test(c))
                    l.push('\\u00' + hi.toString(16) + lo.toString(16));
            }
        }
        /**
         * characters that are illegal inside ids.
         * <rison> and <reserved> classes are illegal in ids.
         *
         */
        rison.not_idchar = l.join('')
        //idcrx = new RegExp('[' + rison.not_idchar + ']');
        //console.log('NOT', (idcrx.test(' ')) );
    })();
//rison.not_idchar  = " \t\r\n\"<>[]{}'!=:(),*@$;&";
    rison.not_idchar = " '!:(),*@$";


    /**
     * characters that are illegal as the start of an id
     * this is so ids can't look like numbers.
     */
    rison.not_idstart = "-0123456789";


    (function () {
        var idrx = '[^' + rison.not_idstart + rison.not_idchar +
            '][^' + rison.not_idchar + ']*';

        rison.id_ok = new RegExp('^' + idrx + '$');

        // regexp to find the end of an id when parsing
        // g flag on the regexp is necessary for iterative regexp.exec()
        rison.next_id = new RegExp(idrx, 'g');
    })();

    /**
     * this is like encodeURIComponent() but quotes fewer characters.
     *
     * @see rison.uri_ok
     *
     * encodeURIComponent passes   ~!*()-_.'
     * rison.quote also passes   ,:@$/
     *   and quotes " " as "+" instead of "%20"
     */
    rison.quote = function (x) {
        if (/^[-A-Za-z0-9~!*()_.',:@$\/]*$/.test(x))
            return x;

        return encodeURIComponent(x)
            .replace(/%2C/g, ',')
            .replace(/%3A/g, ':')
            .replace(/%40/g, '@')
            .replace(/%24/g, '$')
            .replace(/%2F/g, '/')
            .replace(/%20/g, '+');
    };


//
//  based on json.js 2006-04-28 from json.org
//  license: http://www.json.org/license.html
//
//  hacked by nix for use in uris.
//

    (function () {
        var sq = { // url-ok but quoted in strings
                "'": true, '!': true
            },
            enc = function (v) {
                if (v && typeof v.toJSON === 'function') v = v.toJSON();
                var fn = s[typeof v];
                if (fn) return fn(v);
            },
            s = {
                array: function (x) {
                    var a = ['!('], b, f, i, l = x.length, v;
                    for (i = 0; i < l; i += 1) {
                        v = enc(x[i]);
                        if (typeof v == 'string') {
                            if (b) {
                                a[a.length] = ',';
                            }
                            a[a.length] = v;
                            b = true;
                        }
                    }
                    a[a.length] = ')';
                    return a.join('');
                },
                'boolean': function (x) {
                    if (x)
                        return '!t';
                    return '!f'
                },
                'null': function (x) {
                    return "!n";
                },
                number: function (x) {
                    if (!isFinite(x))
                        return '!n';
                    // strip '+' out of exponent, '-' is ok though
                    return String(x).replace(/\+/, '');
                },
                object: function (x) {
                    if (x) {
                        if (x instanceof Array) {
                            return s.array(x);
                        }
                        // WILL: will this work on non-Firefox browsers?
                        if (typeof x.__prototype__ === 'object' && typeof x.__prototype__.encode_rison !== 'undefined')
                            return x.encode_rison();

                        var a = ['('], b, f, i, v, ki, ks = [];
                        for (i in x)
                            ks[ks.length] = i;
                        ks.sort();
                        for (ki = 0; ki < ks.length; ki++) {
                            i = ks[ki];
                            v = enc(x[i]);
                            if (typeof v == 'string') {
                                if (b) {
                                    a[a.length] = ',';
                                }
                                a.push(s.string(i), ':', v);
                                b = true;
                            }
                        }
                        a[a.length] = ')';
                        return a.join('');
                    }
                    return '!n';
                },
                string: function (x) {
                    if (x == '')
                        return "''";

                    if (rison.id_ok.test(x))
                        return x;

                    x = x.replace(/(['!])/g, function (a, b) {
                        if (sq[b]) return '!' + b;
                        return b;
                    });
                    return "'" + x + "'";
                },
                undefined: function (x) {
                    // ignore undefined just like JSON
                }
            };


        /**
         * rison-encode a javascript structure
         *
         *  implemementation based on Douglas Crockford's json.js:
         *    http://json.org/json.js as of 2006-04-28 from json.org
         *
         */
        rison.encode = function (v) {
            return enc(v);
        };

        /**
         * rison-encode a javascript object without surrounding parens
         *
         */
        rison.encode_object = function (v) {
            if (typeof v != 'object' || v === null || v instanceof Array)
                throw new Error("rison.encode_object expects an object argument");
            var r = s[typeof v](v);
            return r.substring(1, r.length - 1);
        };

        /**
         * rison-encode a javascript array without surrounding parens
         *
         */
        rison.encode_array = function (v) {
            if (!(v instanceof Array))
                throw new Error("rison.encode_array expects an array argument");
            var r = s[typeof v](v);
            return r.substring(2, r.length - 1);
        };

        /**
         * rison-encode and uri-encode a javascript structure
         *
         */
        rison.encode_uri = function (v) {
            return rison.quote(s[typeof v](v));
        };

    })();


//
// based on openlaszlo-json and hacked by nix for use in uris.
//
// Author: Oliver Steele
// Copyright: Copyright 2006 Oliver Steele.  All rights reserved.
// Homepage: http://osteele.com/sources/openlaszlo/json
// License: MIT License.
// Version: 1.0


    /**
     * parse a rison string into a javascript structure.
     *
     * this is the simplest decoder entry point.
     *
     *  based on Oliver Steele's OpenLaszlo-JSON
     *     http://osteele.com/sources/openlaszlo/json
     */
    rison.decode = function (r) {
        var errcb = function (e) {
            throw Error('rison decoder error: ' + e);
        };
        var p = new rison.parser(errcb);
        return p.parse(r);
    };

    /**
     * parse an o-rison string into a javascript structure.
     *
     * this simply adds parentheses around the string before parsing.
     */
    rison.decode_object = function (r) {
        return rison.decode('(' + r + ')');
    };

    /**
     * parse an a-rison string into a javascript structure.
     *
     * this simply adds array markup around the string before parsing.
     */
    rison.decode_array = function (r) {
        return rison.decode('!(' + r + ')');
    };


    /**
     * construct a new parser object for reuse.
     *
     * @constructor
     * @class A Rison parser class.  You should probably
     *        use rison.decode instead.
     * @see rison.decode
     */
    rison.parser = function (errcb) {
        this.errorHandler = errcb;
    };

    /**
     * a string containing acceptable whitespace characters.
     * by default the rison decoder tolerates no whitespace.
     * to accept whitespace set rison.parser.WHITESPACE = " \t\n\r\f";
     */
    rison.parser.WHITESPACE = "";

// expose this as-is?
    rison.parser.prototype.setOptions = function (options) {
        if (options['errorHandler'])
            this.errorHandler = options.errorHandler;
    };

    /**
     * parse a rison string into a javascript structure.
     */
    rison.parser.prototype.parse = function (str) {
        this.string = str;
        this.index = 0;
        this.message = null;
        var value = this.readValue();
        if (!this.message && this.next())
            value = this.error("unable to parse string as rison: '" + rison.encode(str) + "'");
        if (this.message && this.errorHandler)
            this.errorHandler(this.message, this.index);
        return value;
    };

    rison.parser.prototype.error = function (message) {
        if (typeof(console) != 'undefined')
            console.log('rison parser error: ', message);
        this.message = message;
        return undefined;
    };

    rison.parser.prototype.readValue = function () {
        var c = this.next();
        var fn = c && this.table[c];

        if (fn)
            return fn.apply(this);

        // fell through table, parse as an id

        var s = this.string;
        var i = this.index - 1;

        // Regexp.lastIndex may not work right in IE before 5.5?
        // g flag on the regexp is also necessary
        rison.next_id.lastIndex = i;
        var m = rison.next_id.exec(s);

        // console.log('matched id', i, r.lastIndex);

        if (m.length > 0) {
            var id = m[0];
            this.index = i + id.length;
            return id;  // a string
        }

        if (c) return this.error("invalid character: '" + c + "'");
        return this.error("empty expression");
    };

    rison.parser.parse_array = function (parser) {
        var ar = [];
        var c;
        while ((c = parser.next()) != ')') {
            if (!c) return parser.error("unmatched '!('");
            if (ar.length) {
                if (c != ',')
                    parser.error("missing ','");
            } else if (c == ',') {
                return parser.error("extra ','");
            } else
                --parser.index;
            var n = parser.readValue();
            if (typeof n == "undefined") return undefined;
            ar.push(n);
        }
        return ar;
    };

    rison.parser.bangs = {
        t: true,
        f: false,
        n: null,
        '(': rison.parser.parse_array
    };

    rison.parser.prototype.table = {
        '!': function () {
            var s = this.string;
            var c = s.charAt(this.index++);
            if (!c) return this.error('"!" at end of input');
            var x = rison.parser.bangs[c];
            if (typeof(x) == 'function') {
                return x.call(null, this);
            } else if (typeof(x) == 'undefined') {
                return this.error('unknown literal: "!' + c + '"');
            }
            return x;
        },
        '(': function () {
            var o = {};
            var c;
            var count = 0;
            while ((c = this.next()) != ')') {
                if (count) {
                    if (c != ',')
                        this.error("missing ','");
                } else if (c == ',') {
                    return this.error("extra ','");
                } else
                    --this.index;
                var k = this.readValue();
                if (typeof k == "undefined") return undefined;
                if (this.next() != ':') return this.error("missing ':'");
                var v = this.readValue();
                if (typeof v == "undefined") return undefined;
                o[k] = v;
                count++;
            }
            return o;
        },
        "'": function () {
            var s = this.string;
            var i = this.index;
            var start = i;
            var segments = [];
            var c;
            while ((c = s.charAt(i++)) != "'") {
                //if (i == s.length) return this.error('unmatched "\'"');
                if (!c) return this.error('unmatched "\'"');
                if (c == '!') {
                    if (start < i - 1)
                        segments.push(s.slice(start, i - 1));
                    c = s.charAt(i++);
                    if ("!'".indexOf(c) >= 0) {
                        segments.push(c);
                    } else {
                        return this.error('invalid string escape: "!' + c + '"');
                    }
                    start = i;
                }
            }
            if (start < i - 1)
                segments.push(s.slice(start, i - 1));
            this.index = i;
            return segments.length == 1 ? segments[0] : segments.join('');
        },
        // Also any digit.  The statement that follows this table
        // definition fills in the digits.
        '-': function () {
            var s = this.string;
            var i = this.index;
            var start = i - 1;
            var state = 'int';
            var permittedSigns = '-';
            var transitions = {
                'int+.': 'frac',
                'int+e': 'exp',
                'frac+e': 'exp'
            };
            do {
                var c = s.charAt(i++);
                if (!c) break;
                if ('0' <= c && c <= '9') continue;
                if (permittedSigns.indexOf(c) >= 0) {
                    permittedSigns = '';
                    continue;
                }
                state = transitions[state + '+' + c.toLowerCase()];
                if (state == 'exp') permittedSigns = '-';
            } while (state);
            this.index = --i;
            s = s.slice(start, i);
            if (s == '-') return this.error("invalid number");
            return Number(s);
        }
    };
// copy table['-'] to each of table[i] | i <- '0'..'9':
    (function (table) {
        for (var i = 0; i <= 9; i++)
            table[String(i)] = table['-'];
    })(rison.parser.prototype.table);

// return the next non-whitespace character, or undefined
    rison.parser.prototype.next = function () {
        var c;
        var s = this.string;
        var i = this.index;
        do {
            if (i == s.length) return undefined;
            c = s.charAt(i++);
        } while (rison.parser.WHITESPACE.indexOf(c) >= 0);
        this.index = i;
        return c;
    };

// End of UMD module wrapper
}));
