text: import isArray from '../utils/is-array';
  import hasOwnProp from '../utils/has-own-prop';
  import isUndefined from '../utils/is-undefined';
  import compareArrays from '../utils/compare-arrays';
  import { deprecateSimple } from '../utils/deprecate';
  import { mergeConfigs } from './set';
  import { Locale } from './constructor';
  import keys from '../utils/keys';
  
  import { baseConfig } from './base-config';
  
  // internal storage for locale config files
  var locales = {};
  var localeFamilies = {};
  var globalLocale;
  
  function normalizeLocale(key) {
      return key ? key.toLowerCase().replace('_', '-') : key;
  }
  
  // pick the locale from the array
  // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
  // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
  function chooseLocale(names) {
      var i = 0, j, next, locale, split;
  
      while (i < names.length) {
          split = normalizeLocale(names[i]).split('-');
          j = split.length;
          next = normalizeLocale(names[i + 1]);
          next = next ? next.split('-') : null;
          while (j > 0) {
              locale = loadLocale(split.slice(0, j).join('-'));
              if (locale) {
                  return locale;
              }
              if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {
                  //the next array item is better than a shallower substring of this one
                  break;
              }
              j--;
          }
          i++;
      }
      return globalLocale;
  }
  
  function loadLocale(name) {
      var oldLocale = null;
      // TODO: Find a better way to register and load all the locales in Node
      if (!locales[name] && (typeof module !== 'undefined') &&
              module && module.exports) {
          try {
              oldLocale = globalLocale._abbr;
              var aliasedRequire = require;
              aliasedRequire('./locale/' + name);
              getSetGlobalLocale(oldLocale);
          } catch (e) {}
      }
      return locales[name];
  }
  
  // This function will load locale and then set the global locale.  If
  // no arguments are passed in, it will simply return the current global
  // locale key.
  export function getSetGlobalLocale (key, values) {
      var data;
      if (key) {
          if (isUndefined(values)) {
              data = getLocale(key);
          }
          else {
              data = defineLocale(key, values);
          }
  
          if (data) {
              // moment.duration._locale = moment._locale = data;
              globalLocale = data;
          }
          else {
              if ((typeof console !==  'undefined') && console.warn) {
                  //warn user if arguments are passed but the locale could not be set
                  console.warn('Locale ' + key +  ' not found. Did you forget to load it?');
              }
          }
      }
  
      return globalLocale._abbr;
  }
  
  export function defineLocale (name, config) {
      if (config !== null) {
          var locale, parentConfig = baseConfig;
          config.abbr = name;
          if (locales[name] != null) {
              deprecateSimple('defineLocaleOverride',
                      'use moment.updateLocale(localeName, config) to change ' +
                      'an existing locale. moment.defineLocale(localeName, ' +
                      'config) should only be used for creating a new locale ' +
                      'See http://momentjs.com/guides/#/warnings/define-locale/ for more info.');
              parentConfig = locales[name]._config;
          } else if (config.parentLocale != null) {
              if (locales[config.parentLocale] != null) {
                  parentConfig = locales[config.parentLocale]._config;
              } else {
                  locale = loadLocale(config.parentLocale);
                  if (locale != null) {
                      parentConfig = locale._config;
                  } else {
                      if (!localeFamilies[config.parentLocale]) {
                          localeFamilies[config.parentLocale] = [];
                      }
                      localeFamilies[config.parentLocale].push({
                          name: name,
                          config: config
                      });
                      return null;
                  }
              }
          }
          locales[name] = new Locale(mergeConfigs(parentConfig, config));
  
          if (localeFamilies[name]) {
              localeFamilies[name].forEach(function (x) {
                  defineLocale(x.name, x.config);
              });
          }
  
          // backwards compat for now: also set the locale
          // make sure we set the locale AFTER all child locales have been
          // created, so we won't end up with the child locale set.
          getSetGlobalLocale(name);
  
  
          return locales[name];
      } else {
          // useful for testing
          delete locales[name];
          return null;
      }
  }
  
  export function updateLocale(name, config) {
      if (config != null) {
          var locale, tmpLocale, parentConfig = baseConfig;
          // MERGE
          tmpLocale = loadLocale(name);
          if (tmpLocale != null) {
              parentConfig = tmpLocale._config;
          }
          config = mergeConfigs(parentConfig, config);
          locale = new Locale(config);
          locale.parentLocale = locales[name];
          locales[name] = locale;
  
          // backwards compat for now: also set the locale
          getSetGlobalLocale(name);
      } else {
          // pass null for config to unupdate, useful for tests
          if (locales[name] != null) {
              if (locales[name].parentLocale != null) {
                  locales[name] = locales[name].parentLocale;
              } else if (locales[name] != null) {
                  delete locales[name];
              }
          }
      }
      return locales[name];
  }
  
  // returns locale data
  export function getLocale (key) {
      var locale;
  
      if (key && key._locale && key._locale._abbr) {
          key = key._locale._abbr;
      }
  
      if (!key) {
          return globalLocale;
      }
  
      if (!isArray(key)) {
          //short-circuit everything else
          locale = loadLocale(key);
          if (locale) {
              return locale;
          }
          key = [key];
      }
  
      return chooseLocale(key);
  }
  
  export function listLocales() {
      return keys(locales);
  }
  