# encoding: UTF-8

# Copyright 2012 Twitter, Inc
# http://www.apache.org/licenses/LICENSE-2.0

require 'ruby_parser'

module TwitterCldr
  module Js
    module Renderers
      module PluralRules

        class PluralRulesCompiler

          class << self
            def rule_to_js(rule_code)
              tree = RubyParser.new.parse(rule_code).to_a
              "function(n) { return #{statement_list(tree)} }"
            end

            protected

            def statement_list(tree)
              if tree.first == :block
                tree[1..-1].map { |sub_tree| send(:"_#{sub_tree.first}", sub_tree) }.join(" ")
              else
                send(:"_#{tree.first}", tree)
              end
            end

            def _if(tree)
              result = "(function() { if (#{statement_list(tree[1])}) { return #{statement_list(tree[2])} }"
              result << " else { return #{statement_list(tree[3])} }" if tree[3]
              "#{result} })();"
            end

            def _lvar(tree)
              tree.first.to_s
            end

            def _call(tree)
              case tree[2]
                when :==, :%, :<, :>  # special operators that actually resolve to method calls
                  "#{statement_list(tree[1])} #{tree[2]} #{statement_list(tree[3])}"
                when :include?
                  "#{statement_list(tree[1])}.indexOf(#{statement_list(tree[3])}) >= 0"
                when :between?
                  smt = "((#{statement_list(tree[1])} >= #{statement_list(tree[3][1])})"
                  smt << " && (#{statement_list(tree[1])} <= #{statement_list(tree[3][2])}))"
                  smt
                else
                  # this should be the only case where tree[1] might be nil (i.e. the method was not called on any object)
                  call = tree[1] ? "#{statement_list(tree[1])}.#{tree[2]}" : tree[2].to_s
                  arglist = statement_list(tree[3])
                  arglist == "" ? call : "#{call}(#{arglist})"
              end
            end

            def _arglist(tree)
              tree[1..-1].map { |arg| statement_list(arg) }.join(", ")
            end

            def _lit(tree)
              if tree[1].is_a?(Symbol) || tree[1].is_a?(String)
                %Q("#{tree[1]}")
              else
                tree[1]
              end
            end

            def _array(tree)
              "[#{tree[1..-1].map { |arg| statement_list(arg) }.join(", ")}]"
            end

            def _not(tree)
              "!(#{statement_list(tree[1])})"
            end

            def _and(tree)
              "#{statement_list(tree[1])} && #{statement_list(tree[2])}"
            end

            def _or(tree)
              "#{statement_list(tree[1])} || #{statement_list(tree[2])}"
            end
          end

        end

      end
    end
  end
end