#!/usr/bin/env ruby

RAILS_ENV = 'test'
REDMINE_ROOT = '/var/www/html/redmine/'
# This does _NOT_ work. I looked back 3 revisions and found the correct line
#require File.dirname(__FILE__) + '/../config/boot'
require REDMINE_ROOT + 'config/environment'

require 'getoptlong'

class BugMail

  attr_accessor :issue, :desc, :subject, :category, :project, :status, 
      :tracker, :priority, :author, :email, :allow_override, 
      :use_email_header, :input, :debug

  def initialize

    @issue = nil
    @desc = nil
    @subject = nil
    @category = nil
    @project = nil
    @status = nil
    @tracker = 'Bug'
    @priority = nil
    @author = nil
    @email = nil
    @allow_override = false
    @use_email_header = false
    @debug = false
  end

  def process(msg)
    @issue = line_match(msg, "Issue", @issue)
    @subject = line_match(msg, "Subject", @subject)
# we can generalize via mail-aliases setup to be <project>@<fqdn>
    @project = match(msg, /^To:.*?(\w+)@.*$/, @project) if(@use_email_header)
    @project = line_match(msg, "Project", @project)
    @status = line_match(msg, "Status", @status)
    @tracker = line_match(msg, "Tracker", @racker)
    @priority = line_match(msg, "Priority", @priority)
    @category = line_match(msg, "Category", @category)
    @email = match(msg, /^From:.*?(\w+@[A-Za-z0-9.-]+).*?$/, @email) if(@use_email_header)
    @author = line_match(msg, "Author", @author)

    @desc = block_match(msg, "Description", @desc)

    puts "Issue: [#{@issue}]" if @debug
    puts "Project: [#{@project}]" if @debug
    puts "Subject: [#{@subject}]" if @debug
    puts "Tracker: [#{@tracker}]" if @debug
    puts "Priority: [#{@priority}]" if @debug
    puts "Category: [#{@category}]" if @debug
    puts "Status: [#{@status}]" if @debug
    puts "Author/email: [#{@author}/#{@email}]" if @debug
    puts "Desc: [#{@desc}]" if @debug

    ic = Iconv.new('UTF-8', 'UTF-8')

    p = Project.find_by_identifier(@project)
    if(! p) 
      puts 'Unable to find project [#{@project}]'
      return false
    end

    priorities = Enumeration.get_values('IPRI')
    @DEFAULT_PRIORITY = priorities[0]
    @DEFAULT_TRACKER = p.trackers.find_by_position(1) || Tracker.find_by_position(1)
    @PRIORITY_MAPPING = {}
    priorities.each { |prio| @PRIORITY_MAPPING[prio.name] = prio }

    puts "Searching for user [#{author}/#{email}]" if debug

    u = User.find_by_login(@author)
    if(! u && @use_email_header)
      puts "Searching for user via email: [#{@email}]" if @debug
      u = User.find_by_mail(@email)
    end

    if(!u)
      puts "Unable to find user"
      return false
    else
      puts "Found user [#{u.login}/#{u.mail}]"
    end

    puts "Searching for issue [#{@issue}]" if @debug
    i = Issue.find_by_id(@issue)

    if(i == nil) 
      prio = @PRIORITY_MAPPING[@priority] || @DEFAULT_PRIORITY
      st = IssueStatus.find_by_name(@status) || IssueStatus.default
      t = p.trackers.find_by_name(@tracker) || @DEFAULT_TRACKER
      c = p.issue_categories.find_by_name(@category)
      i = Issue.create( :priority => prio,
                        :status => st,
                        :tracker => t,
                        :project => p,
                        :category => c,
                        :start_date => Date.today,
                        :author => u,
                        :description => ic.iconv(@desc),
                        :subject => ic.iconv(@subject) )
      puts "Created issue [#{i.id}] [#{i.to_yaml}]" if @debug

      if(!i.save)
        puts "Failed to save new issue"
        exit 1 
      end
    else
      puts "Issue exists, adding comment..."
      n = Journal.new(:notes => ic.iconv(@desc),
                      :journalized => i,
                      :user => u);
      if(!n.save)
        puts "Failed to add comment"
        return false
      end
    end

    return true
  end

private
  def match(msg, regex, default)
    if((@allow_override || default == nil) && (msg =~ regex))
      return $1
    end
    return default
  end


  def line_match(msg, label, default)
    return match(msg, /^#{label}:[ \t]*(.*)$/, default)
  end

  def block_match(msg, label, default)
    return match(msg, /^#{label}:[ \t]*(.*)$/m, default)
  end

end

opts = GetoptLong.new(
      [ '--help', '-h', GetoptLong::NO_ARGUMENT ],
      [ '--debug', GetoptLong::NO_ARGUMENT ],
      [ '--issue', '-i', GetoptLong::REQUIRED_ARGUMENT ],
      [ '--desc', '-d', GetoptLong::REQUIRED_ARGUMENT ],
      [ '--subject', '-s', GetoptLong::REQUIRED_ARGUMENT ],
      [ '--category', '-c', GetoptLong::REQUIRED_ARGUMENT ],
      [ '--project', '-p', GetoptLong::REQUIRED_ARGUMENT ],
      [ '--tracker', '-t', GetoptLong::REQUIRED_ARGUMENT ],
      [ '--status', GetoptLong::REQUIRED_ARGUMENT ],
      [ '--priority', GetoptLong::REQUIRED_ARGUMENT ],
      [ '--author', '-a',  GetoptLong::REQUIRED_ARGUMENT ],
      [ '--file', '-f',  GetoptLong::REQUIRED_ARGUMENT ],
      [ '--allow-override',  GetoptLong::NO_ARGUMENT ],
      [ '--use-email-header',  GetoptLong::NO_ARGUMENT ]
    )

def usage
  puts "Usage: [--help] [--debug] [--allow-override] [--use-email-header] [--file <filename> ] [--<param> <value> ...]"
  puts " --help  show this help"
  puts " --debug show extra debug information"
  puts " --allow-override   allow message contents to override cmd line args"
  puts " --use-email-header search in email header for user, subject and project"
  puts " --file      get input from a file instead of STDIN"
  puts " --<param>   set a parameter's value.  Parameter is one of:"
  puts "             issue, project, subject, desc, status, tracker, priority"
  puts "             category, author"
  exit
end

input = $stdin
mailer = BugMail.new

opts.each do |opt, arg|
  case opt
  when '--help'
    usage
  when '--issue'
    mailer.issue = arg.to_i
  when '--project'
    mailer.project = arg
  when '--subject'
    mailer.subject = arg
  when '--desc'
    mailer.desc = arg
  when '--status'
    mailer.status = arg
  when '--tracker'
    mailer.tracker = arg
  when '--priority'
    mailer.priority = arg
  when '--category'
    mailer.category = arg
  when '--author'
    mailer.author = arg
  when '--file'
    input = FILE.open(arg, "r")
  when '--debug'
    mailer.debug = true
  when '--allow-override'
    mailer.allow_override = true
  when '--use-email-header'
    mailer.use_email_header = true
  end
end

msg = input.read

mailer.process(msg)

