/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// Disable eslint warnings to preserve original code style.
/* eslint-disable */

/**
 * This module provides the PluralForm object which contains a method to figure
 * out which plural form of a word to use for a given number based on the
 * current localization.
 */

const PluralForm = {
  init()
  {
    delete this.numForms;
    delete this.get;

    let [numForms, pluralFunc] = this.getPluralRule();
    this.numForms = () => numForms;
    this.get = (aNum, aWords) => {
      // Figure out which index to use for the semi-colon separated words
      let index = pluralFunc(aNum ? Number(aNum) : 0);
      let words = aWords ? aWords.split(/;/) : [""];

      // Explicitly check bounds to avoid strict warnings
      let ret = index < words.length ? words[index] : undefined;

      // Check for array out of bounds or empty strings
      if ((ret == undefined) || (ret == "")) {
        console.warn(`plural-form.js: Index #${index} of '${aWords}' for value ${aNum} is invalid;\n`);

        // Default to the first entry (which might be empty, but not undefined)
        ret = words[0];
      }

      return ret;
    };
  },

  /**
   * Get the correct plural form of a word based on the number
   *
   * @param aNum
   *        The number to decide which plural form to use
   * @param aWords
   *        A semi-colon (;) separated string of words to pick the plural form
   * @return The appropriate plural form of the word
   */
  get get()
  {
    this.init();
    return this.get;
  },

  /**
   * Get the number of forms for the current plural rule
   *
   * @return The number of forms
   */
  get numForms()
  {
    this.init();
    return this.numForms;
  },

  /**
   * Selects the number of plural categories and the function for selecting between them.
   *
   * The default is to use the same plural rules as English, which has "one" and "other" categories.
   * This is only used for a small number of devtools messages that have a custom format;
   * Fluent plurals in general rely on Unicode Common Locale Data Repository data.
   *
   * @return The available plural function that gives the appropriate index
   *   based on the plural rule number specified. The first element is the number
   *   of plural forms and the second is the function to figure out the index.
   */
  getPluralRule()
  {
    let appLocale = Services.locale.appLocalesAsLangTags[0];

    // See searchfox.org/firefox-main/rev/f6385e6644d5d4343d33b692810275c434122199/intl/docs/locale.rst#463-471
    // Swap ja-JP-mac (legacy locale in gecko, but invalid) with the valid ja-JP-macos
    if (appLocale === "ja-JP-mac") {
      appLocale = "ja-JP-macos";
    }

    const locale = new Intl.Locale(appLocale);
    switch (locale.language) {
      case "bo":
      case "id":
      case "ja":
      case "km":
      case "ko":
      case "lo":
      case "meh":
      case "ms":
      case "my":
      case "th":
      case "vi":
      case "wo":
      case "zh":
        return [1, (n) => 0];
      case "bn":
      case "fa":
      case "fr":
      case "gu":
      case "hi":
      case "oc":
      case "pa":
        return [2, (n) => n>1?1:0];
      case "ltg":
      case "lv":
        return [3, (n) => n%10==1&&n%100!=11?1:n%10==0?0:2];
      case "gd":
        return [4, (n) => n==1||n==11?0:n==2||n==12?1:n>0&&n<20?2:3];
      case "ro":
        return [3, (n) => n==1?0:n==0||n%100>0&&n%100<20?1:2];
      case "lt":
        return [3, (n) => n%10==1&&n%100!=11?0:n%10>=2&&(n%100<10||n%100>=20)?2:1];
      case "be":
      case "ru":
      case "uk":
        return [3, (n) => n%10==1&&n%100!=11?0:n%10>=2&&n%10<=4&&(n%100<10||n%100>=20)?1:2];
      case "cs":
      case "sk":
        return [3, (n) => n==1?0:n>=2&&n<=4?1:2];
      case "pl":
      case "szl":
        return [3, (n) => n==1?0:n%10>=2&&n%10<=4&&(n%100<10||n%100>=20)?1:2];
      case "dsb":
      case "hsb":
      case "sl":
        return [4, (n) => n%100==1?0:n%100==2?1:n%100==3||n%100==4?2:3];
      case "ga":
        return [5, (n) => n==1?0:n==2?1:n>=3&&n<=6?2:n>=7&&n<=10?3:4];
      case "ar":
        return [6, (n) => n==0?5:n==1?0:n==2?1:n%100>=3&&n%100<=10?2:n%100>=11&&n%100<=99?3:4];
      case "is":
      case "mk":
        return [4, (n) => n==1?0:n==0||n%100>0&&n%100<=10?1:n%100>10&&n%100<20?2:3];
      case "br":
        return [5, (n) => n%10==1&&n%100!=11&&n%100!=71&&n%100!=91?0:n%10==2&&n%100!=12&&n%100!=72&&n%100!=92?1:(n%10==3||n%10==4||n%10==9)&&n%100!=13&&n%100!=14&&n%100!=19&&n%100!=73&&n%100!=74&&n%100!=79&&n%100!=93&&n%100!=94&&n%100!=99?2:n%1000000==0&&n!=0?3:4];
      case "cy":
        return [6, (n) => n==0?0:n==1?1:n==2?2:n==3?3:n==6?4:5];
      case "bs":
      case "hr":
      case "sr":
        return [3, (n) => n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2];
      default:
        return [2, (n) => n!=1?1:0];
    }
  }
};

exports.PluralForm = PluralForm;
exports.get = PluralForm.get;

/* eslint-enable */
