# -*- coding: utf-8 -*- #
# frozen_string_literal: true

require_relative '../task_helper'

# backcompat for ancient net/dav lib
def File.exists?(p)
  File.exist?(p)
end

# And it still warns a lot.
silence_warnings { require 'net/dav' }

require 'nokogiri'
require 'svn/downloader'

APACHE_DOCS_URI = "https://downloads.apache.org/httpd/docs/"
APACHE_KEYWORDS_FILE = "./lib/rouge/lexers/apache/keywords.rb"

namespace :builtins do
  task :apache do
    ApacheBuiltins.process(APACHE_KEYWORDS_FILE)
  end
end

class ApacheBuiltins < BuiltinsGenerator
  APACHE_MOD_DOCS = 'https://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/manual/mod/'

  BASE_PATH = File.expand_path("#{__dir__}/../../tmp/apache-mods")

  def fetch
    SVN::Downloader.download(APACHE_MOD_DOCS, BASE_PATH)

    files = {}

    Dir.chdir BASE_PATH do
      Dir.glob("{directives,core,prefork,mod_*,mpm*}.xml*").each do |f|
        files[File.basename(f)] = File.read(f)
      end
    end

    files
  end

  WORD_VALUE = /\A\w[\w*-]+\z/o

  def parse
    out = Hash.new { |h, k| h[k] = Set.new }

    @input.each do |name, content|
      xml = Nokogiri::XML(content)

      xml.css('directivesynopsis').each do |synopsis|
        name = synopsis.css('name').inner_text.strip
        syntax = synopsis.css('syntax')

        # anything in a <var> or <em> tag is a variable description, and not a constant
        syntax.css('var').remove
        syntax.css('em').remove

        # detect constants in command arguments

        values = syntax.inner_text.strip
          .gsub(/\A\w+\s*/, '')
          .split(/[|\s]+/)
          .grep(WORD_VALUE)

        values.each do |value|
          out[:values] << value.strip.downcase
        end

        name = name.downcase

        if synopsis.attr('type') == "section"
          out[:sections] << name
        else
          out[:directives] << name
        end
      end

      xml.css('usage dt code, section dt code').each do |el|
        el.children.reject(&:text?).each(&:remove)
        value = el.inner_text.strip.downcase

        value.split(/[=\[\]]+/).grep(WORD_VALUE).each { |v| out[:values] << v }
      end
    end

    out
  end

  def generate
    yield "# -*- coding: utf-8 -*- #"
    yield "# frozen_string_literal: true"
    yield ""
    yield "# DO NOT EDIT"
    yield "# This file is automatically generated by `rake builtins:apache`."
    yield "# See tasks/builtins/apache.rake for more info."
    yield ""
    yield "module Rouge"
    yield "  module Lexers"
    yield "    class Apache"
    yield "      DIRECTIVES = Set#{@keywords[:directives].sort.inspect}"
    yield "      VALUES = Set#{@keywords[:values].sort.inspect}"
    yield "      SECTIONS = Set#{@keywords[:sections].sort.inspect}"
    yield "    end"
    yield "  end"
    yield "end"
  end
end
