require 'net/http'
require 'uri'
require 'timeout'
require 'xiki/keys'

class Redmine

  @@url ||= 'http://foo.com:80/wiki/1'
  def self.url= to;  @@url = to;  end
  def self.url;  @@url;  end

  def self.menu
    puts "
      + .pages/
      - .start
      - local: http://localhost:3401/wiki/gateway
      - remote: http://rlitio.chase.com:3401/wiki/1
      "
  end

  def self.pages page=nil
    if page  # If page was passed, open it
      self.open page
      return
    end

    # Otherwise, print list
    t = self.http_get "#{@@url}/Page_index/special" rescue return
    t.scan(/<a href="\/wiki\/1\/([\w-]+)"/) { |m| puts "- #{m[0]}" }
    ""
  end

  def self.redmine_to_xiki txt

    # Angle brackets
    txt.gsub!('&lt;', '<');  txt.gsub!('&gt;', '>')
    txt.gsub!('&amp;', '&');  txt.gsub!('&quot;', '"')

    (1..7).to_a.reverse.each do |i|  # Headers
      txt.gsub!(/^#{'#' * i}/, "#{'|' * i} ")
    end
    (1..9).to_a.reverse.each do |i|  # Bullets
      txt.gsub!(/^#{'\\*' * i}/, "#{'  ' * (i-1)}-")
    end

    txt
  end

  def self.xiki_to_redmine txt
    # Headers (h1. etc)
    (1..7).to_a.reverse.each { |i| txt.gsub!(/^#{'\\|' * i} /, "#{'#' * i}") }
    (1..9).to_a.reverse.each { |i| txt.gsub!(/^#{'  ' * (i-1)}-/, "#{'*' * i}") }
    txt
  end

  def self.open name

    # TODO grab token into a buffer name
    version = "no_version"
    wiki, version = self.page_from_server name
    self.redmine_to_xiki wiki
    View.to_after_bar
    View.to_buffer("redmine/#{name}/#{version}")

    # Set mode and use relevant key shortcuts
    Notes.mode;  $el.use_local_map $el.elvar.redmine_mode_map
    self.apply_styles

    if View.empty?  # If nothing there yet, insert
      $el.insert wiki
    end
    Move.top
    ""
  end

  def self.page_from_server name

    t = self.http_get "#{@@url}/#{name}/edit" rescue
      return
    version = t[/<input id="content_version".+value="(\d+)"/, 1]
    wiki = t[/<textarea.*?>(.+)<\/textarea>/m, 1]
    wiki.gsub!("\C-m", '')
    [wiki, version]
  end

  def self.save
    name, version = View.buffer_name.split('/')[1..2]
    txt = View.txt  # Get text from buffer
    return puts("- Not a redmine page!") unless txt
    self.xiki_to_redmine txt

    # Get text from server
    server_txt, server_version = self.page_from_server name

    # If version is same, save
    if version == server_version
      res = Net::HTTP.post_form(URI.parse("#{@@url}/#{name}/edit"), {  # Save
        'content[version]' => version, 'content[text]' => txt
      })
      message "- page saved"
      $el.rename_buffer "redmine/#{name}/#{version.to_i + 1}"  # Rename
    else  # Otherwise show diff
      message "- wrong version, show diffs!"
      View.to_buffer "*redmine_collision: #{name}/#{server_version}"
      notes_mode;  $el.use_local_map $el.elvar.redmine_mode_map

      View.clear
      $el.insert "- collision with #{name}/#{server_version}!\n\n"
      $el.insert self.diff(server_txt, txt)
    end
  end

  def self.http_get url
    t = nil
    begin
      timeout(2) do
        t = Net::HTTP.get URI.parse(url)
      end
    rescue Exception => e
      puts "- Couldn't connect to url (#{url}): #{e.message}!"
      raise e
    end
    t
  end

  def self.init
    unless $el.boundp :redmine_mode_map
      # Create new map
      $el.elvar.redmine_mode_map = $el.make_sparse_keymap
      # Inherit notes_mode_map!
      $el.set_keymap_parent $el.elvar.redmine_mode_map, $el.elvar.notes_mode_map
    end
    Keys.XS(:redmine_mode_map) { Redmine.save }

    # Make C-. follow link
    Launcher.add(/\[\[.+\]\]/) do |line|  # Redmine wiki links
      name = line[/\[\[(.+?)\]\]/, 1]
      name.gsub!(/ /, "_")
      Redmine.open(name)
    end
  end

  def self.diff a, b
    temp_path_a = "/tmp/diff_tmp_a.txt"
    temp_path_b = "/tmp/diff_tmp_b.txt"
    File.open(temp_path_a, "w") { |f| f << a }
    File.open(temp_path_b, "w") { |f| f << b }
    diff = $el.shell_command_to_string "diff -w -U 0 \"#{temp_path_a}\" \"#{temp_path_b}\""
    DiffLog.format("server/", "diff/", diff)
  end

  def self.apply_styles
    # Strikethrough
    Styles.define(:strike, :strike => true)
    Styles.apply("^ *- \\(-.+-\\)$", nil, :strike)
    # _italic_
    Styles.define(:redmine_green, :bold => true, :fg => "33dd33")
    Styles.apply(" _[a-zA-Z0-9 ]+_ ", :redmine_green)
    Styles.apply(" _[a-zA-Z0-9 ]+_$", :redmine_green)

  end

  def self.start
    Rails.start '$o/redmine/trunk', @@url[/\d+/]
  end

end
# Redmine.init
