require 'rubygems'
require 'erb'
require 'tmpdir'
require 'uri'
require 'open-uri'
require 'fileutils'

# Set up gems listed in the Gemfile.
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('./Gemfile', File.dirname(__FILE__))
require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
Bundler.require(:default, :test) if defined?(Bundler)

project_dir = File.expand_path('..', File.dirname(__FILE__))
base_path = File.expand_path('pushstream/docs/preview', Dir.tmpdir)
javascript_dir = File.expand_path(Dir["#{project_dir}/**/js"].first)

begin
  require "rspec/core/rake_task"

  desc "Run all examples"
  RSpec::Core::RakeTask.new(:spec) do |t|
    t.rspec_opts = %w[--color]
    t.pattern = '**/*_spec.rb'
  end
rescue LoadError
  task :spec do
    abort "RSpec is not available. In order to run rspec, you must: (sudo) gem install rspec"
  end
end

begin
  desc 'Start server to host jasmine specs'
  task 'jasmine' => ['dependencies', 'jshint', 'test_server'] do
    system("npx jasmine-browser-runner serve --config=#{File.expand_path('misc/spec/javascripts/support/jasmine-browser.json', project_dir)}") rescue Interrupt
  end

  desc 'Run jasmine tests in a browser, random and seed override config'
  task 'jasmine:ci', [:random, :seed] => ['dependencies', 'jshint', 'test_server'] do |t, args|
    params = []
    params << "--seed=#{args[:seed]}" if args[:seed]
    params << '--random' if args[:random]
    system("npx jasmine-browser-runner runSpecs #{params.join(' ')} --config=#{File.expand_path('misc/spec/javascripts/support/jasmine-browser.json', project_dir)}") rescue Interrupt
  end

  desc 'Run jshint'
  task :jshint => ['dependencies'] do
    system("npx jshint #{javascript_dir}/pushstream.js")
  end

  task :dependencies do
    system('yarn install -s')
  end

  task :test_server do
    require File.expand_path('misc/spec/spec_helper', project_dir)
    include NginxTestHelper
    template = File.read(File.expand_path('misc/nginx.conf', project_dir))
    template.gsub!(/push_stream_subscriber_connection_ttl.*;/, 'push_stream_subscriber_connection_ttl 3s;')
    template.gsub!(/push_stream_longpolling_connection_ttl.*;/, 'push_stream_longpolling_connection_ttl 3s;')
    config = NginxTestHelper::Config.new "jasmine", {:configuration_template => (RUBY_PLATFORM =~ /darwin/) ? template.gsub('epoll', 'kqueue') : template }
    abort "Could not start test server" if start_server(config).include?("[emerg]")
  end
end

namespace :docs do

begin
  Bundler.require(:default, :docs) if defined?(Bundler)

  task :get_static_files do
    FileUtils.mkdir_p("#{base_path}/css")

    download_file("https://github.githubassets.com/assets/global-efcb6353627d.css", "#{base_path}/css/github.css") unless File.exists?("#{base_path}/css/github.css")
    download_file("https://github.githubassets.com/assets/github-07f750db5d7c.css", "#{base_path}/css/github2.css") unless File.exists?("#{base_path}/css/github2.css")
  end

  def generate_preview_for(file, project_dir, base_path)
    template = ERB.new File.read("#{project_dir}/misc/github_template.html.erb")
    filename = File.basename(file)
    content = GitHub::Markup.render(file, File.read(file))
    rendered = template.result(binding)
    output = File.expand_path(file.gsub(project_dir, "./"), base_path)
    output_dir = File.dirname(output)
    FileUtils.mkdir_p(output_dir)
    File.open(output, 'w') {|f| f.write(rendered) }
    puts "Preview rendered to #{output}"
  end

  desc "Generates docs files to preview."
  task :generate => :get_static_files do
    Dir.glob("#{project_dir}/**/*.textile").each do |file|
      generate_preview_for(file, project_dir, base_path)
    end
  end

  desc "Watch for changes on doc to generate the preview."
  task :watch do
    puts "watching for changes on textile files"
    Dir.chdir(project_dir) do
      FileWatcher.new(["**/*.textile"]).watch do |file, event|
        if(event != :delete)
          generate_preview_for(file, project_dir, base_path)
        end
      end
    end
  end

  desc "Convert docs to Nginx wiki format."
  task :convert_to_wiki do
    Dir.glob("#{project_dir}/**/*.textile").each do |file|
      filename = File.basename(file)
      content = File.read(file)

      output      = file.gsub(project_dir, File.expand_path('pushstream/docs/html', Dir.tmpdir)).gsub(".textile", ".html")
      output_wiki = file.gsub(project_dir, File.expand_path('pushstream/docs/wiki', Dir.tmpdir)).gsub(".textile", ".wiki")
      FileUtils.mkdir_p(File.dirname(output))
      FileUtils.mkdir_p(File.dirname(output_wiki))

      File.open(output, 'w') {|f| f.write(RedCloth.new(content).to_html) }
      File.open(output_wiki, 'w') {|f| f.write(convert_to_wiki_syntax(content)) }
      puts "Wiki converted to #{output_wiki}"
    end
  end
rescue LoadError
  desc "Generates docs files to preview."
  task :generate do
    abort "github-markup is not available. In order to run docs:generate, you must: (sudo) gem install github-markup"
  end

  desc "Convert docs to Nginx wiki format."
  task :convert_to_wiki do
    abort "RedCloth or nokogiri is not available. In order to run docs:convert_to_wiki, you must: (sudo) gem install RedCloth nokogiri"
  end
end

  def download_file(url, output_file)
    case io = URI.open(url)
    when StringIO then File.open(output_file, 'w') { |f| f.write(io) }
    when Tempfile then io.close; FileUtils.mv(io.path, output_file)
    end
  end

  def convert_to_wiki_syntax(text)
    doc = Nokogiri::HTML(RedCloth.new(text).to_html)
    convert_elements(doc.children.to_a)
  end

  def convert_elements(nodes)
    result = ""
    nodes.each do |node|
      if node.element? && !node.text?
        childrens = node.children.to_a
        unless childrens.empty?
          result += convert_element(convert_elements(childrens), node)
        end
      elsif node.text?
        result += node.text
      end
    end
    result
  end

  def convert_element(text, node)
    tag = node.name
    text ||= ""
    case tag
    when "strong"
      "'''#{text}'''"
    when "b"
      "'''#{text}'''"
    when "em"
      "''#{text}''"
    when "h1"
      "\n= #{text} ="
    when "h2"
      "\n== #{text} =="
    when "h3"
      "\n=== #{text} ==="
    when "h4"
      "\n==== #{text} ===="
    when "h5"
      "\n===== #{text} ====="
    when "h6"
      "\n====== #{text} ======"
    when "p"
      "\n#{text}"
    when "a"
      if node.attributes['href'].value.start_with?("#")
        "[[#{node.attributes['href'].value}|#{text}]]"
      else
        "[#{node.attributes['href'].value} #{text}]"
      end
    when "html"
      text
    when "body"
      text
    when "span"
      text
    else
      "<#{tag}>#{text}</#{tag}>"
    end
  end
end
