"use strict";

/* global pluralRuleParser */
(function ($) {
  'use strict';

  // jscs:disable
  var language = {
    // CLDR plural rules generated using
    // libs/CLDRPluralRuleParser/tools/PluralXML2JSON.html
    pluralRules: {
      ak: {
        one: 'n = 0..1'
      },
      am: {
        one: 'i = 0 or n = 1'
      },
      ar: {
        zero: 'n = 0',
        one: 'n = 1',
        two: 'n = 2',
        few: 'n % 100 = 3..10',
        many: 'n % 100 = 11..99'
      },
      ars: {
        zero: 'n = 0',
        one: 'n = 1',
        two: 'n = 2',
        few: 'n % 100 = 3..10',
        many: 'n % 100 = 11..99'
      },
      as: {
        one: 'i = 0 or n = 1'
      },
      be: {
        one: 'n % 10 = 1 and n % 100 != 11',
        few: 'n % 10 = 2..4 and n % 100 != 12..14',
        many: 'n % 10 = 0 or n % 10 = 5..9 or n % 100 = 11..14'
      },
      bh: {
        one: 'n = 0..1'
      },
      bn: {
        one: 'i = 0 or n = 1'
      },
      br: {
        one: 'n % 10 = 1 and n % 100 != 11,71,91',
        two: 'n % 10 = 2 and n % 100 != 12,72,92',
        few: 'n % 10 = 3..4,9 and n % 100 != 10..19,70..79,90..99',
        many: 'n != 0 and n % 1000000 = 0'
      },
      bs: {
        one: 'v = 0 and i % 10 = 1 and i % 100 != 11 or f % 10 = 1 and f % 100 != 11',
        few: 'v = 0 and i % 10 = 2..4 and i % 100 != 12..14 or f % 10 = 2..4 and f % 100 != 12..14'
      },
      cs: {
        one: 'i = 1 and v = 0',
        few: 'i = 2..4 and v = 0',
        many: 'v != 0'
      },
      cy: {
        zero: 'n = 0',
        one: 'n = 1',
        two: 'n = 2',
        few: 'n = 3',
        many: 'n = 6'
      },
      da: {
        one: 'n = 1 or t != 0 and i = 0,1'
      },
      dsb: {
        one: 'v = 0 and i % 100 = 1 or f % 100 = 1',
        two: 'v = 0 and i % 100 = 2 or f % 100 = 2',
        few: 'v = 0 and i % 100 = 3..4 or f % 100 = 3..4'
      },
      fa: {
        one: 'i = 0 or n = 1'
      },
      ff: {
        one: 'i = 0,1'
      },
      fil: {
        one: 'v = 0 and i = 1,2,3 or v = 0 and i % 10 != 4,6,9 or v != 0 and f % 10 != 4,6,9'
      },
      fr: {
        one: 'i = 0,1'
      },
      ga: {
        one: 'n = 1',
        two: 'n = 2',
        few: 'n = 3..6',
        many: 'n = 7..10'
      },
      gd: {
        one: 'n = 1,11',
        two: 'n = 2,12',
        few: 'n = 3..10,13..19'
      },
      gu: {
        one: 'i = 0 or n = 1'
      },
      guw: {
        one: 'n = 0..1'
      },
      gv: {
        one: 'v = 0 and i % 10 = 1',
        two: 'v = 0 and i % 10 = 2',
        few: 'v = 0 and i % 100 = 0,20,40,60,80',
        many: 'v != 0'
      },
      he: {
        one: 'i = 1 and v = 0',
        two: 'i = 2 and v = 0',
        many: 'v = 0 and n != 0..10 and n % 10 = 0'
      },
      hi: {
        one: 'i = 0 or n = 1'
      },
      hr: {
        one: 'v = 0 and i % 10 = 1 and i % 100 != 11 or f % 10 = 1 and f % 100 != 11',
        few: 'v = 0 and i % 10 = 2..4 and i % 100 != 12..14 or f % 10 = 2..4 and f % 100 != 12..14'
      },
      hsb: {
        one: 'v = 0 and i % 100 = 1 or f % 100 = 1',
        two: 'v = 0 and i % 100 = 2 or f % 100 = 2',
        few: 'v = 0 and i % 100 = 3..4 or f % 100 = 3..4'
      },
      hy: {
        one: 'i = 0,1'
      },
      is: {
        one: 't = 0 and i % 10 = 1 and i % 100 != 11 or t != 0'
      },
      iu: {
        one: 'n = 1',
        two: 'n = 2'
      },
      iw: {
        one: 'i = 1 and v = 0',
        two: 'i = 2 and v = 0',
        many: 'v = 0 and n != 0..10 and n % 10 = 0'
      },
      kab: {
        one: 'i = 0,1'
      },
      kn: {
        one: 'i = 0 or n = 1'
      },
      kw: {
        one: 'n = 1',
        two: 'n = 2'
      },
      lag: {
        zero: 'n = 0',
        one: 'i = 0,1 and n != 0'
      },
      ln: {
        one: 'n = 0..1'
      },
      lt: {
        one: 'n % 10 = 1 and n % 100 != 11..19',
        few: 'n % 10 = 2..9 and n % 100 != 11..19',
        many: 'f != 0'
      },
      lv: {
        zero: 'n % 10 = 0 or n % 100 = 11..19 or v = 2 and f % 100 = 11..19',
        one: 'n % 10 = 1 and n % 100 != 11 or v = 2 and f % 10 = 1 and f % 100 != 11 or v != 2 and f % 10 = 1'
      },
      mg: {
        one: 'n = 0..1'
      },
      mk: {
        one: 'v = 0 and i % 10 = 1 or f % 10 = 1'
      },
      mo: {
        one: 'i = 1 and v = 0',
        few: 'v != 0 or n = 0 or n != 1 and n % 100 = 1..19'
      },
      mr: {
        one: 'i = 0 or n = 1'
      },
      mt: {
        one: 'n = 1',
        few: 'n = 0 or n % 100 = 2..10',
        many: 'n % 100 = 11..19'
      },
      naq: {
        one: 'n = 1',
        two: 'n = 2'
      },
      nso: {
        one: 'n = 0..1'
      },
      pa: {
        one: 'n = 0..1'
      },
      pl: {
        one: 'i = 1 and v = 0',
        few: 'v = 0 and i % 10 = 2..4 and i % 100 != 12..14',
        many: 'v = 0 and i != 1 and i % 10 = 0..1 or v = 0 and i % 10 = 5..9 or v = 0 and i % 100 = 12..14'
      },
      prg: {
        zero: 'n % 10 = 0 or n % 100 = 11..19 or v = 2 and f % 100 = 11..19',
        one: 'n % 10 = 1 and n % 100 != 11 or v = 2 and f % 10 = 1 and f % 100 != 11 or v != 2 and f % 10 = 1'
      },
      pt: {
        one: 'i = 0..1'
      },
      ro: {
        one: 'i = 1 and v = 0',
        few: 'v != 0 or n = 0 or n != 1 and n % 100 = 1..19'
      },
      ru: {
        one: 'v = 0 and i % 10 = 1 and i % 100 != 11',
        few: 'v = 0 and i % 10 = 2..4 and i % 100 != 12..14',
        many: 'v = 0 and i % 10 = 0 or v = 0 and i % 10 = 5..9 or v = 0 and i % 100 = 11..14'
      },
      se: {
        one: 'n = 1',
        two: 'n = 2'
      },
      sh: {
        one: 'v = 0 and i % 10 = 1 and i % 100 != 11 or f % 10 = 1 and f % 100 != 11',
        few: 'v = 0 and i % 10 = 2..4 and i % 100 != 12..14 or f % 10 = 2..4 and f % 100 != 12..14'
      },
      shi: {
        one: 'i = 0 or n = 1',
        few: 'n = 2..10'
      },
      si: {
        one: 'n = 0,1 or i = 0 and f = 1'
      },
      sk: {
        one: 'i = 1 and v = 0',
        few: 'i = 2..4 and v = 0',
        many: 'v != 0'
      },
      sl: {
        one: 'v = 0 and i % 100 = 1',
        two: 'v = 0 and i % 100 = 2',
        few: 'v = 0 and i % 100 = 3..4 or v != 0'
      },
      sma: {
        one: 'n = 1',
        two: 'n = 2'
      },
      smi: {
        one: 'n = 1',
        two: 'n = 2'
      },
      smj: {
        one: 'n = 1',
        two: 'n = 2'
      },
      smn: {
        one: 'n = 1',
        two: 'n = 2'
      },
      sms: {
        one: 'n = 1',
        two: 'n = 2'
      },
      sr: {
        one: 'v = 0 and i % 10 = 1 and i % 100 != 11 or f % 10 = 1 and f % 100 != 11',
        few: 'v = 0 and i % 10 = 2..4 and i % 100 != 12..14 or f % 10 = 2..4 and f % 100 != 12..14'
      },
      ti: {
        one: 'n = 0..1'
      },
      tl: {
        one: 'v = 0 and i = 1,2,3 or v = 0 and i % 10 != 4,6,9 or v != 0 and f % 10 != 4,6,9'
      },
      tzm: {
        one: 'n = 0..1 or n = 11..99'
      },
      uk: {
        one: 'v = 0 and i % 10 = 1 and i % 100 != 11',
        few: 'v = 0 and i % 10 = 2..4 and i % 100 != 12..14',
        many: 'v = 0 and i % 10 = 0 or v = 0 and i % 10 = 5..9 or v = 0 and i % 100 = 11..14'
      },
      wa: {
        one: 'n = 0..1'
      },
      zu: {
        one: 'i = 0 or n = 1'
      }
    },
    // jscs:enable

    /**
     * Plural form transformations, needed for some languages.
     *
     * @param {integer} count
     *            Non-localized quantifier
     * @param {Array} forms
     *            List of plural forms
     * @return {string} Correct form for quantifier in this language
     */
    convertPlural: function convertPlural(count, forms) {
      var pluralRules,
        pluralFormIndex,
        index,
        explicitPluralPattern = new RegExp('\\d+=', 'i'),
        formCount,
        form;
      if (!forms || forms.length === 0) {
        return '';
      }

      // Handle for Explicit 0= & 1= values
      for (index = 0; index < forms.length; index++) {
        form = forms[index];
        if (explicitPluralPattern.test(form)) {
          formCount = parseInt(form.slice(0, form.indexOf('=')), 10);
          if (formCount === count) {
            return form.slice(form.indexOf('=') + 1);
          }
          forms[index] = undefined;
        }
      }
      forms = $.map(forms, function (form) {
        if (form !== undefined) {
          return form;
        }
      });
      pluralRules = this.pluralRules[$.i18n().locale];
      if (!pluralRules) {
        // default fallback.
        return count === 1 ? forms[0] : forms[1];
      }
      pluralFormIndex = this.getPluralForm(count, pluralRules);
      pluralFormIndex = Math.min(pluralFormIndex, forms.length - 1);
      return forms[pluralFormIndex];
    },
    /**
     * For the number, get the plural for index
     *
     * @param {integer} number
     * @param {Object} pluralRules
     * @return {integer} plural form index
     */
    getPluralForm: function getPluralForm(number, pluralRules) {
      var i,
        pluralForms = ['zero', 'one', 'two', 'few', 'many', 'other'],
        pluralFormIndex = 0;
      for (i = 0; i < pluralForms.length; i++) {
        if (pluralRules[pluralForms[i]]) {
          if (pluralRuleParser(pluralRules[pluralForms[i]], number)) {
            return pluralFormIndex;
          }
          pluralFormIndex++;
        }
      }
      return pluralFormIndex;
    },
    /**
     * Converts a number using digitTransformTable.
     *
     * @param {number} num Value to be converted
     * @param {boolean} integer Convert the return value to an integer
     * @return {string} The number converted into a String.
     */
    convertNumber: function convertNumber(num, integer) {
      var tmp, item, i, transformTable, numberString, convertedNumber;

      // Set the target Transform table:
      transformTable = this.digitTransformTable($.i18n().locale);
      numberString = String(num);
      convertedNumber = '';
      if (!transformTable) {
        return num;
      }

      // Check if the restore to Latin number flag is set:
      if (integer) {
        if (parseFloat(num, 10) === num) {
          return num;
        }
        tmp = [];
        for (item in transformTable) {
          tmp[transformTable[item]] = item;
        }
        transformTable = tmp;
      }
      for (i = 0; i < numberString.length; i++) {
        if (transformTable[numberString[i]]) {
          convertedNumber += transformTable[numberString[i]];
        } else {
          convertedNumber += numberString[i];
        }
      }
      return integer ? parseFloat(convertedNumber, 10) : convertedNumber;
    },
    /**
     * Grammatical transformations, needed for inflected languages.
     * Invoked by putting {{grammar:form|word}} in a message.
     * Override this method for languages that need special grammar rules
     * applied dynamically.
     *
     * @param {string} word
     * @param {string} form
     * @return {string}
     */
    // eslint-disable-next-line no-unused-vars
    convertGrammar: function convertGrammar(word, form) {
      return word;
    },
    /**
     * Provides an alternative text depending on specified gender. Usage
     * {{gender:[gender|user object]|masculine|feminine|neutral}}. If second
     * or third parameter are not specified, masculine is used.
     *
     * These details may be overriden per language.
     *
     * @param {string} gender
     *      male, female, or anything else for neutral.
     * @param {Array} forms
     *      List of gender forms
     *
     * @return {string}
     */
    gender: function gender(_gender, forms) {
      if (!forms || forms.length === 0) {
        return '';
      }
      while (forms.length < 2) {
        forms.push(forms[forms.length - 1]);
      }
      if (_gender === 'male') {
        return forms[0];
      }
      if (_gender === 'female') {
        return forms[1];
      }
      return forms.length === 3 ? forms[2] : forms[0];
    },
    /**
     * Get the digit transform table for the given language
     * See http://cldr.unicode.org/translation/numbering-systems
     *
     * @param {string} language
     * @return {Array|boolean} List of digits in the passed language or false
     * representation, or boolean false if there is no information.
     */
    digitTransformTable: function digitTransformTable(language) {
      var tables = {
        ar: '٠١٢٣٤٥٦٧٨٩',
        fa: '۰۱۲۳۴۵۶۷۸۹',
        ml: '൦൧൨൩൪൫൬൭൮൯',
        kn: '೦೧೨೩೪೫೬೭೮೯',
        lo: '໐໑໒໓໔໕໖໗໘໙',
        or: '୦୧୨୩୪୫୬୭୮୯',
        kh: '០១២៣៤៥៦៧៨៩',
        pa: '੦੧੨੩੪੫੬੭੮੯',
        gu: '૦૧૨૩૪૫૬૭૮૯',
        hi: '०१२३४५६७८९',
        my: '၀၁၂၃၄၅၆၇၈၉',
        ta: '௦௧௨௩௪௫௬௭௮௯',
        te: '౦౧౨౩౪౫౬౭౮౯',
        th: '๐๑๒๓๔๕๖๗๘๙',
        // FIXME use iso 639 codes
        bo: '༠༡༢༣༤༥༦༧༨༩' // FIXME use iso 639 codes
      };

      if (!tables[language]) {
        return false;
      }
      return tables[language].split('');
    }
  };
  $.extend($.i18n.languages, {
    'default': language
  });
})(jQuery);