/**
 * Globalize v1.0.0
 *
 * http://github.com/jquery/globalize
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license
 * http://jquery.org/license
 *
 * Date: 2015-04-23T12:02Z
 */
/*!
 * Globalize v1.0.0 2015-04-23T12:02Z Released under the MIT license
 * http://git.io/TrdQbw
 */
(function( root, factory ) {

	// UMD returnExports
	if ( typeof define === "function" && define.amd ) {

		// AMD
		define([
			"cldr",
			"../globalize",
			"cldr/event",
			"cldr/supplemental"
		], factory );
	} else if ( typeof exports === "object" ) {

		// Node, CommonJS
		module.exports = factory( require( "cldrjs" ), require( "globalize" ) );
	} else {

		// Global
		factory( root.Cldr, root.Globalize );
	}
}(this, function( Cldr, Globalize ) {

var validateCldr = Globalize._validateCldr,
	validateDefaultLocale = Globalize._validateDefaultLocale,
	validateParameterPresence = Globalize._validateParameterPresence,
	validateParameterType = Globalize._validateParameterType,
	validateParameterTypePlainObject = Globalize._validateParameterTypePlainObject;
var MakePlural;
/* jshint ignore:start */
MakePlural = (function() {


var _toArray = function (arr) { return Array.isArray(arr) ? arr : Array.from(arr); };

var _toConsumableArray = function (arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } };

var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } };

var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();


/**
 * make-plural.js -- https://github.com/eemeli/make-plural.js/
 * Copyright (c) 2014-2015 by Eemeli Aro <eemeli@gmail.com>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * The software is provided "as is" and the author disclaims all warranties
 * with regard to this software including all implied warranties of
 * merchantability and fitness. In no event shall the author be liable for
 * any special, direct, indirect, or consequential damages or any damages
 * whatsoever resulting from loss of use, data or profits, whether in an
 * action of contract, negligence or other tortious action, arising out of
 * or in connection with the use or performance of this software.
 */

var Parser = (function () {
    function Parser() {
        _classCallCheck(this, Parser);
    }

    _createClass(Parser, [{
        key: 'parse',
        value: function parse(cond) {
            var _this = this;

            if (cond === 'i = 0 or n = 1') {
                return 'n >= 0 && n <= 1';
            }if (cond === 'i = 0,1') {
                return 'n >= 0 && n < 2';
            }if (cond === 'i = 1 and v = 0') {
                this.v0 = 1;
                return 'n == 1 && v0';
            }
            return cond.replace(/([tv]) (!?)= 0/g, function (m, sym, noteq) {
                var sn = sym + '0';
                _this[sn] = 1;
                return noteq ? '!' + sn : sn;
            }).replace(/\b[fintv]\b/g, function (m) {
                _this[m] = 1;
                return m;
            }).replace(/([fin]) % (10+)/g, function (m, sym, num) {
                var sn = sym + num;
                _this[sn] = 1;
                return sn;
            }).replace(/n10+ = 0/g, 't0 && $&').replace(/(\w+ (!?)= )([0-9.]+,[0-9.,]+)/g, function (m, se, noteq, x) {
                if (m === 'n = 0,1') return '(n == 0 || n == 1)';
                if (noteq) return se + x.split(',').join(' && ' + se);
                return '(' + se + x.split(',').join(' || ' + se) + ')';
            }).replace(/(\w+) (!?)= ([0-9]+)\.\.([0-9]+)/g, function (m, sym, noteq, x0, x1) {
                if (Number(x0) + 1 === Number(x1)) {
                    if (noteq) return '' + sym + ' != ' + x0 + ' && ' + sym + ' != ' + x1;
                    return '(' + sym + ' == ' + x0 + ' || ' + sym + ' == ' + x1 + ')';
                }
                if (noteq) return '(' + sym + ' < ' + x0 + ' || ' + sym + ' > ' + x1 + ')';
                if (sym === 'n') {
                    _this.t0 = 1;return '(t0 && n >= ' + x0 + ' && n <= ' + x1 + ')';
                }
                return '(' + sym + ' >= ' + x0 + ' && ' + sym + ' <= ' + x1 + ')';
            }).replace(/ and /g, ' && ').replace(/ or /g, ' || ').replace(/ = /g, ' == ');
        }
    }, {
        key: 'vars',
        value: (function (_vars) {
            function vars() {
                return _vars.apply(this, arguments);
            }

            vars.toString = function () {
                return _vars.toString();
            };

            return vars;
        })(function () {
            var vars = [];
            if (this.i) vars.push('i = s[0]');
            if (this.f || this.v) vars.push('f = s[1] || \'\'');
            if (this.t) vars.push('t = (s[1] || \'\').replace(/0+$/, \'\')');
            if (this.v) vars.push('v = f.length');
            if (this.v0) vars.push('v0 = !s[1]');
            if (this.t0 || this.n10 || this.n100) vars.push('t0 = Number(s[0]) == n');
            for (var k in this) {
                if (/^.10+$/.test(k)) {
                    var k0 = k[0] === 'n' ? 't0 && s[0]' : k[0];
                    vars.push('' + k + ' = ' + k0 + '.slice(-' + k.substr(2).length + ')');
                }
            }if (!vars.length) return '';
            return 'var ' + ['s = String(n).split(\'.\')'].concat(vars).join(', ');
        })
    }]);

    return Parser;
})();



var MakePlural = (function () {
    function MakePlural(lc) {
        var _ref = arguments[1] === undefined ? MakePlural : arguments[1];

        var cardinals = _ref.cardinals;
        var ordinals = _ref.ordinals;

        _classCallCheck(this, MakePlural);

        if (!cardinals && !ordinals) throw new Error('At least one type of plural is required');
        this.lc = lc;
        this.categories = { cardinal: [], ordinal: [] };
        this.parser = new Parser();
        
        this.fn = this.buildFunction(cardinals, ordinals);
        this.fn._obj = this;
        this.fn.categories = this.categories;
        
        this.fn.toString = this.fnToString.bind(this);
        return this.fn;
    }

    _createClass(MakePlural, [{
        key: 'compile',
        value: function compile(type, req) {
            var cases = [];
            var rules = MakePlural.rules[type][this.lc];
            if (!rules) {
                if (req) throw new Error('Locale "' + this.lc + '" ' + type + ' rules not found');
                this.categories[type] = ['other'];
                return '\'other\'';
            }
            for (var r in rules) {
                var _rules$r$trim$split = rules[r].trim().split(/\s*@\w*/);

                var _rules$r$trim$split2 = _toArray(_rules$r$trim$split);

                var cond = _rules$r$trim$split2[0];
                var examples = _rules$r$trim$split2.slice(1);
                var cat = r.replace('pluralRule-count-', '');
                if (cond) cases.push([this.parser.parse(cond), cat]);
                
            }
            this.categories[type] = cases.map(function (c) {
                return c[1];
            }).concat('other');
            if (cases.length === 1) {
                return '(' + cases[0][0] + ') ? \'' + cases[0][1] + '\' : \'other\'';
            } else {
                return [].concat(_toConsumableArray(cases.map(function (c) {
                    return '(' + c[0] + ') ? \'' + c[1] + '\'';
                })), ['\'other\'']).join('\n      : ');
            }
        }
    }, {
        key: 'buildFunction',
        value: function buildFunction(cardinals, ordinals) {
            var _this3 = this;

            var compile = function compile(c) {
                return c ? (c[1] ? 'return ' : 'if (ord) return ') + _this3.compile.apply(_this3, _toConsumableArray(c)) : '';
            },
                fold = { vars: function vars(str) {
                    return ('  ' + str + ';').replace(/(.{1,78})(,|$) ?/g, '$1$2\n      ');
                },
                cond: function cond(str) {
                    return ('  ' + str + ';').replace(/(.{1,78}) (\|\| |$) ?/gm, '$1\n          $2');
                } },
                cond = [ordinals && ['ordinal', !cardinals], cardinals && ['cardinal', true]].map(compile).map(fold.cond),
                body = [fold.vars(this.parser.vars())].concat(_toConsumableArray(cond)).join('\n').replace(/\s+$/gm, '').replace(/^[\s;]*[\r\n]+/gm, ''),
                args = ordinals && cardinals ? 'n, ord' : 'n';
            return new Function(args, body);
        }
    }, {
        key: 'fnToString',
        value: function fnToString(name) {
            return Function.prototype.toString.call(this.fn).replace(/^function( \w+)?/, name ? 'function ' + name : 'function').replace('\n/**/', '');
        }
    }], [{
        key: 'load',
        value: function load() {
            for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
                args[_key] = arguments[_key];
            }

            args.forEach(function (cldr) {
                var data = cldr && cldr.supplemental || null;
                if (!data) throw new Error('Data does not appear to be CLDR data');
                MakePlural.rules = {
                    cardinal: data['plurals-type-cardinal'] || MakePlural.rules.cardinal,
                    ordinal: data['plurals-type-ordinal'] || MakePlural.rules.ordinal
                };
            });
            return MakePlural;
        }
    }]);

    return MakePlural;
})();



MakePlural.cardinals = true;
MakePlural.ordinals = false;
MakePlural.rules = { cardinal: {}, ordinal: {} };


return MakePlural;
}());
/* jshint ignore:end */


var validateParameterTypeNumber = function( value, name ) {
	validateParameterType(
		value,
		name,
		value === undefined || typeof value === "number",
		"Number"
	);
};




var validateParameterTypePluralType = function( value, name ) {
	validateParameterType(
		value,
		name,
		value === undefined || value === "cardinal" || value === "ordinal",
		"String \"cardinal\" or \"ordinal\""
	);
};




/**
 * .plural( value )
 *
 * @value [Number]
 *
 * Return the corresponding form (zero | one | two | few | many | other) of a
 * value given locale.
 */
Globalize.plural =
Globalize.prototype.plural = function( value, options ) {
	validateParameterPresence( value, "value" );
	validateParameterTypeNumber( value, "value" );
	return this.pluralGenerator( options )( value );
};

/**
 * .pluralGenerator( [options] )
 *
 * Return a plural function (of the form below).
 *
 * fn( value )
 *
 * @value [Number]
 *
 * Return the corresponding form (zero | one | two | few | many | other) of a value given the
 * default/instance locale.
 */
Globalize.pluralGenerator =
Globalize.prototype.pluralGenerator = function( options ) {
	var cldr, isOrdinal, plural, type;

	validateParameterTypePlainObject( options, "options" );

	options = options || {};
	type = options.type || "cardinal";
	cldr = this.cldr;

	validateParameterTypePluralType( options.type, "options.type" );

	validateDefaultLocale( cldr );

	isOrdinal = type === "ordinal";

	cldr.on( "get", validateCldr );
	cldr.supplemental([ "plurals-type-" + type, "{language}" ]);
	cldr.off( "get", validateCldr );

	MakePlural.rules = {};
	MakePlural.rules[ type ] = cldr.supplemental( "plurals-type-" + type );

	plural = new MakePlural( cldr.attributes.language, {
		"ordinals": isOrdinal,
		"cardinals": !isOrdinal
	});

	return function( value ) {
		validateParameterPresence( value, "value" );
		validateParameterTypeNumber( value, "value" );

		return plural( value );
	};
};

return Globalize;




}));
