module XCPretty
  class JUnit

    include XCPretty::FormatMethods
    FILEPATH = 'build/reports/junit.xml'

    def load_dependencies
      unless @@loaded ||= false
        require 'fileutils'
        require 'pathname'
        require 'rexml/document'
        require 'rexml/formatters/pretty'
        @@loaded = true
      end
    end

    def initialize(options)
      load_dependencies
      @filepath  = options[:path] || FILEPATH
      @directory = `pwd`.strip
      @document  = REXML::Document.new
      @document << REXML::XMLDecl.new('1.0','UTF-8')
      @document.add_element('testsuites')
      @parser    = Parser.new(self)
      @total_tests = 0
      @total_fails = 0
    end

    def handle(line)
      @parser.parse(line)
    end

    def format_passing_test(classname, test_case, time)
      test_node = suite(classname).add_element('testcase')
      test_node.attributes['classname'] = classname
      test_node.attributes['name']      = test_case
      test_node.attributes['time']      = time
      @test_count += 1
    end

    def format_pending_test(classname, test_case)
      test_node = suite(classname).add_element('testcase')
      test_node.attributes['classname'] = classname
      test_node.attributes['name']      = test_case
      test_node.add_element('skipped')
      @test_count += 1
    end

    def format_failing_test(classname, test_case, reason, file)
      test_node = suite(classname).add_element('testcase')
      test_node.attributes['classname'] = classname
      test_node.attributes['name']      = test_case
      fail_node = test_node.add_element('failure')
      fail_node.attributes['message'] = reason
      fail_node.text = file.sub(@directory + '/', '')
      @test_count += 1
      @fail_count += 1
    end

    def finish
      set_test_counters
      @document.root.attributes['tests'] = @total_tests
      @document.root.attributes['failures'] = @total_fails
      write_report_file
    end

    private

    def write_report_file
      FileUtils.mkdir_p(File.dirname(@filepath))
      formatter = REXML::Formatters::Pretty.new(2)
      formatter.compact = true
      output_file = File.open(@filepath, 'w+')
      result = formatter.write(@document, output_file)
      output_file.close
      result
    end

    def suite(classname)
      return @last_suite if @last_suite && @last_suite.attributes['name'] == classname

      set_test_counters
      @last_suite = @document.root.add_element('testsuite')
      @last_suite.attributes['name'] = classname
      @last_suite
    end

    def set_test_counters
      if @last_suite
        @last_suite.attributes['tests'] = @test_count
        @last_suite.attributes['failures'] = @fail_count
      end
      @total_fails += @fail_count || 0
      @total_tests += @test_count || 0
      @test_count = 0
      @fail_count = 0
    end
  end
end