require 'i18n/backend/fast/interpolation_compiler'

module I18n
  module Backend
    class Fast < Base
      SEPARATOR_ESCAPE_CHAR = "\001"

      def reset_flattened_translations!
        @flattened_translations = nil
      end

      def flattened_translations
        @flattened_translations ||= flatten_translations(translations)
      end

      def merge_translations(locale, data)
        super
        reset_flattened_translations!
      end

      def init_translations
        super
        reset_flattened_translations!
      end
      
      def translate(locale, key, opts = nil)
        raise InvalidLocale.new(locale) unless locale
        return key.map { |k| translate(locale, k, opts) } if key.is_a?(Array)
        
        if opts
          count = opts[:count]
          scope = opts[:scope]
          
          if entry = lookup(locale, key, scope, opts[:separator]) || ((default = opts.delete(:default)) && default(locale, key, default, opts))
            entry = resolve(locale, key, entry, opts)
            entry = pluralize(locale, entry, count) if count
            entry = interpolate(locale, entry, opts)
            entry
          end
        else
          resolve(locale, key, lookup(locale, key), opts)
        end || raise(I18n::MissingTranslationData.new(locale, key, opts))
      end
      
      protected
        # flatten_hash({:a=>'a', :b=>{:c=>'c', :d=>'d', :f=>{:x=>'x'}}}) 
        # # => {:a=>'a', :b=>{:c=>'c', :d=>'d', :f=>{:x=>'x'}}, :"b.f" => {:x=>"x"}, :"b.c"=>"c", :"b.f.x"=>"x", :"b.d"=>"d"}
        def flatten_hash(h, nested_stack = [], flattened_h = {})
          h.each_pair do |k, v|
            new_nested_stack = nested_stack + [escape_default_separator(k)]
            flattened_h[nested_stack_to_flat_key(new_nested_stack)] = InterpolationCompiler.compile_if_an_interpolation(v)
            flatten_hash(v, new_nested_stack, flattened_h) if v.kind_of?(Hash)
          end

          flattened_h
        end
        
        def escape_default_separator(key)
          key.to_s.tr(I18n.default_separator, SEPARATOR_ESCAPE_CHAR)
        end

        def nested_stack_to_flat_key(nested_stack)
          nested_stack.join(I18n.default_separator).to_sym
        end

        def flatten_translations(translations)
          # don't flatten locale roots
          translations.inject({}) do |flattened_h, (locale_name, locale_translations)|
            flattened_h[locale_name] = flatten_hash(locale_translations)
            flattened_h
          end
        end
        
        def interpolate(locale, string, values)
          if string.respond_to?(:i18n_interpolate)
            string.i18n_interpolate(values)
          elsif values
            super
          else
            string
          end
        end

        def lookup(locale, key, scope = nil, separator = nil)
          init_translations unless @initialized
          if separator
            key   = cleanup_non_standard_separator(key, separator)
            scope = Array(scope).map{|k| cleanup_non_standard_separator(k, separator)} if scope
          end
          flattened_translations[locale.to_sym][(scope ? (Array(scope) + [key]).join(I18n.default_separator) : key).to_sym] rescue nil
        end
        
        def cleanup_non_standard_separator(key, user_separator)
          escape_default_separator(key).tr(user_separator, I18n.default_separator)
        end
    end
  end
end