=begin
  locale_object.rb - Locale::Object

  Copyright (C) 2006  Masao Mutoh

  You may redistribute it and/or modify it under the same
  license terms as Ruby.

  $Id: locale_object.rb,v 1.8 2006/06/11 15:36:20 mutoh Exp $
=end


module Locale
  class Object
    attr_accessor :language, :country, :charset, :script, :variant, :modifier, :orig_str

    # Parse POSIX or RFC 3066 style locale name to Array.
    #
    # * locale_name: locale name as String 
    #   
    #   * Basic POSIX format: <language>_<COUNTRY>.<charset>@<modifier>
    #     * Both of POSIX and C are converted to "en".
    #   * Basic RFC3066 format: <language>-<COUNTRY>
    #   * Win32 format: <language>-<COUNTRY>-<Script>_<sort order>
    #   * CLDR format: <language>_<Script>_<COUNTRY>_<variant>@<modifier>
    #   * Some broken format: <language>_<country>_<script>  # Don't use this.
    #   * The max locale format is below:     
    #     * <language>-<COUNTRY>-<Script>_<sort order>.<charset>@<modifier>
    #     * format: <language>_<Script>_<COUNTRY>_<variant>@<modifier>
    #       * both of '-' and '_' are separators.
    #       * each elements are omittable.
    #   
    #   (e.g.) uz-UZ-Latn, ja_JP.eucJP, wa_BE.iso885915@euro
    # * Returns: [language, country, charset, script, modifier]
    #   * language: a lowercase ISO 639(or 639-2/T) language code.
    #   * country: an uppercase ISO 3166-1 country/region identifier.
    #   * charset: charset(codeset) (no standard)
    #   * script: an initial-uppercase ISO 15924 script code. 
    #   * variant: variant value in CLDR or sort order in Win32.
    #   * modifier: (no standard)
    #
    #  (e.g.)
    #  "ja_JP.eucJP" => ["ja", "JP", "eucJP", nil, nil]
    #  "ja-jp.utf-8" => ["ja", "JP", "utf-8", nil, nil]
    #  "ja-jp" => ["ja", "JP", nil, nil, nil]
    #  "ja" => ["ja", nil, nil, nil, nil]
    #  "uz@Latn" => ["uz", nil, nil, nil, "Latn"]
    #  "uz-UZ-Latn" => ["uz", "UZ", nil, "Latn", nil]
    #  "uz_UZ_Latn" => ["uz", "UZ", nil, "Latn", nil]
    #  "wa_BE.iso885915@euro" => ["wa", "BE", "iso885915", nil, "euro"]
    #  "C" => ["en", nil, nil, nil, nil]
    #  "POSIX" => ["en", nil, nil, nil, nil]
    #  "zh_Hant" => ["zh", nil, nil, "Hant", nil]
    #  "zh_Hant_HK" => ["zh", "HK", nil, "Hant", nil]
    #  "de_DE@collation=phonebook,currency=DDM" => ["de", "DE", nil, nil, "collation=phonebook,currency=DDM"]
    def self.parse(locale_name)
      lang_charset, modifier = locale_name.split(/@/)
      lang, charset = lang_charset.split(/\./)
      language, country, script, variant = lang.gsub(/_/, "-").split('-')
      language = language ? language.downcase : nil
      language = "en" if language == "c" || language == "posix"
      if country
	if country =~ /[A-Z][a-z]+/  #Latn => script
	  tmp = script
	  script = country
	  if tmp =~ /[A-Z]+/ # US => country
	    country = tmp
	  else
	    country = nil
	    variant = tmp
	  end
	else
	  country = country.upcase
	  if script !~ /[A-Z][a-z]+/ #Latn => script
	    variant = script
	    script = nil
	  end
	end
      end
      [language, country, charset, script, variant, modifier]
    end

    # Initialize Locale::Object.
    # * language_or_locale_name: language(ISO 639) or POSIX or RFC3066 style locale name
    # * country: an uppercase ISO 3166-1 country/region identifier, or nil
    # * charset: charset(codeset) (no standard), or nil
    #
    #  Locale::Object.new("ja", "JP", "eucJP")
    #   -> language = "ja", country = "JP", charset = "eucJP".
    #  Locale::Object.new("ja", "JP")
    #   -> language = "ja", country = "JP", charset = nil.
    #  Locale::Object.new("ja_JP.eucJP")
    #   -> language = "ja", country = "JP", charset = "eucJP".
    #  Locale::Object.new("ja_JP.eucJP", nil, "UTF-8")
    #   -> language = "ja", country = "JP", charset = "UTF-8".
    #  Locale::Object.new("en-US", "CA")
    #   -> language = "en", country = "CA", charset = nil.
    #  Locale::Object.new("uz-uz-latn")
    #   -> language = "uz", country = "UZ", charset = nil, script = "Latn"
    #  Locale::Object.new("uz_UZ_Latn")
    #   -> language = "uz", country = "UZ", charset = nil, script = "Latn"
    #  Locale::Object.new("we_BE.iso885915@euro")
    #   -> language = "we", country = "BE", charset = "iso885915", modifier = "euroo".
    #  Locale::Object.new("C")
    #   -> language = "en", country = nil, charset = nil.
    #  Locale::Object.new("POSIX")
    #   -> language = "en", country = nil, charset = nil.
    def initialize(language_or_locale_name, country = nil, charset = nil)
      @orig_str = language_or_locale_name
      @language, @country, @charset, @script, @variant, @modifier = 
	self.class.parse(language_or_locale_name)
      @country = country if country
      @charset = charset if charset
    end
    
    # Returns the locale as POSIX format(but charset is ignored). (e.g.) "ja_JP"
    def to_posix
      ret = @language
      ret += "_#{@country}" if @country
      ret
    end

    # Returns the locale as ISO3066 format. (e.g.) "ja-JP"
    def to_iso3066
      ret = @language
      ret += "-#{@country}" if @country
      ret
    end

    # Returns the locale as Win32 format. (e.g.) "az-AZ-Latn".
    # 
    # This is used to find the charset from locale table.
    def to_win
      ret = @language
      ret += "-#{@country}" if @country
      ret += "-#{@script}" if @script
      ret
    end

    # Returns the locale as 'ruby' general format. (e.g.) "az_AZ_Latn"
    def to_general
      ret = @language
      ret += "_#{@country}" if @country
      ret += "_#{@script}" if @script
      ret      
    end

    # Gets the locale informations as an Array.
    # * Returns [language, country, charset, script, variant, modifier]
    #   * language: a lowercase ISO 639(or 639-2/T) language code.
    #   * country: an uppercase ISO 3166-1 country/region identifier.
    #   * charset: charset(codeset) (no standard)
    #   * script: an initial-uppercase ISO 15924 script code. 
    #   * variant: variant value in CLDR or sort order in Win32.
    #   * modifier: (no standard)
    def to_a
      [@language, @country, @charset, @script, @variant, @modifier]
    end

    def ==(other)  #:nodoc:
      other != nil and 
	@language == other.language and @country == other.country and 
	@charset == other.charset and @script == other.script and 
	@variant == other.variant and @modifier == other.modifier and
	@charset == other.charset
    end

    def eql?(other) #:nodoc:
      self.==(other)
    end

    def hash #:nodoc:
      "#{self.class}:#{to_general}.#{@charset}@#{modifier}".hash
    end
    alias :to_s :to_posix
    alias :to_str :to_posix
  end
end
