module I18nSpec
  class LocaleFile
    PLURALIZATION_KEYS = %w{zero one two few many other}

    attr_accessor :filepath
    attr_reader :errors

    def initialize(filepath)
      @filepath = filepath
      @errors = {}
    end

    def content
      @content ||= IO.read(@filepath)
    end

    def translations
      @translations ||= yaml_load_content
    end

    def flattened_translations
      @flattened_translations ||= flatten_tree(translations.values.first)
    end

    def locale
      @locale ||= ISO::Tag.new(locale_code)
    end

    def locale_code
      translations.keys.first
    end

    def pluralizations
      result = flatten_tree(translations).select do |key, value|
        value.is_a?(Hash)
      end

      if result.is_a?(Array)
        Hash[result]
      else
        result
      end
    end

    def invalid_pluralization_keys
      invalid = []
      pluralizations.each do |parent, pluralization|
        unless pluralization.keys.all? { |key| PLURALIZATION_KEYS.include?(key) }
          invalid << parent
        end
      end
      @errors[:invalid_pluralization_keys] = invalid unless invalid.empty?
      invalid
    end

    def missing_pluralization_keys
      return_data = {}
      rule_names = locale.language.plural_rule_names
      pluralizations.each do |parent, pluralization|
        missing_keys = rule_names - pluralization.keys
        return_data[parent] = missing_keys if missing_keys.any?
      end
      @errors[:missing_pluralization_keys] = return_data if return_data.any?
      return_data
    end

    def is_parseable?
      if RUBY_VERSION < "1.9.3"
        yaml_parse_exception = YAML::ParseError
      else
        yaml_parse_exception = YAML::SyntaxError
      end

      begin
        yaml_load_content
        true
      rescue yaml_parse_exception => e
        @errors[:unparseable] = e.to_s
        false
      rescue ArgumentError => e
        @errors[:unparseable] = e.to_s
        false
      end
    end

    def has_one_top_level_namespace?
      translations.keys.size == 1
    end

    def is_named_like_top_level_namespace?
      locale_code == File.basename(@filepath, File.extname(@filepath))
    end

  protected

    def flatten_tree(data, prefix = '', result = {})
      data.each do |key, value|
        current_prefix = prefix.empty? ? key.to_s : "#{prefix}.#{key}"
        if !value.is_a?(Hash) || pluralization_data?(value)
          result[current_prefix] = value
        else
          flatten_tree(value, current_prefix, result)
        end
      end
      result
    end

    def pluralization_data?(data)
      keys = data.keys.map(&:to_s)
      keys.any? {|k| PLURALIZATION_KEYS.include?(k) }
    end

    def yaml_load_content
      if defined?(Psych) and defined?(Psych::VERSION)
        Psych.load(content)
      else
        YAML.load(content)
      end
    end

  end
end
