#!/usr/bin/ruby
require 'appscript'
require 'rubygems'
require 'net/http'
require 'json'

#JIRA Configuration
JIRA_BASE_URL = 'https://www.yoursite.com/jira'
USERNAME = 'devon'
PASSWORD = 'mypassword'

#OmniFocus Configuration
DEFAULT_CONTEXT="Jira"
DEFAULT_PROJECT="Work"
FLAGGED=true

# This method gets all issues that are assigned to your USERNAME and whos status isn't Closed or Resolved.  It returns a Hash where the key is the Jira Ticket Key and the value is the Jira Ticket Summary.
def get_issues
  jira_issues = Hash.new
  # This is the REST URL that will be hit.  Change the jql query if you want to adjust the query used here
  uri = URI(JIRA_BASE_URL + '/rest/api/2/search?jql=assignee+%3D+currentUser()+AND+status+not+in+(Closed,+Resolved)')

  Net::HTTP.start(uri.hostname, uri.port, :use_ssl => uri.scheme == 'https') do |http|
    request = Net::HTTP::Get.new(uri)
    request.basic_auth USERNAME, PASSWORD
    response = http.request request
    # If the response was good, then grab the data
    if response.code =~ /20[0-9]{1}/
        data = JSON.parse(response.body)
        data["issues"].each do |item|
          jira_id = item["key"]
          jira_issues[jira_id] = item["fields"]["summary"]
        end
    else
     raise StandardError, "Unsuccessful response code " + response.code + " for issue " + issue
    end
  end
  return jira_issues
end

# This method adds a new Task to OmniFocus based on the new_task_properties passed in
def add_task(omnifocus_document, new_task_properties)
  # If there is a passed in OF project name, get the actual project object
  if new_task_properties['project']
    proj_name = new_task_properties["project"]
    proj = omnifocus_document.flattened_tasks[proj_name]
  end

  # Check to see if there's already an OF Task with that name in the referenced Project
  # If there is, just stop.
  name   = new_task_properties["name"]
  exists = proj.tasks.get.find { |t| t.name.get == name }
  return false if exists

  # If there is a passed in OF context name, get the actual context object
  if new_task_properties['context']
    ctx_name = new_task_properties["context"]
    ctx = omnifocus_document.flattened_contexts[ctx_name]
  end

  # Do some task property filtering.  I don't know what this is for, but found it in several other scripts that didn't work...
  tprops = new_task_properties.inject({}) do |h, (k, v)|
    h[:"#{k}"] = v
    h
  end

  # Remove the project property from the new Task properties, as it won't be used like that.
  tprops.delete(:project)
  # Update the context property to be the actual context object not the context name
  tprops[:context] = ctx if new_task_properties['context']

  # You can uncomment this line and comment the one below if you want the tasks to end up in your Inbox instead of a specific Project
#  new_task = omnifocus_document.make(:new => :inbox_task, :with_properties => tprops)

  # Make a new Task in the Project
  proj.make(:new => :task, :with_properties => tprops)

  puts "task created"
  return true
end

# This method is responsible for getting your assigned Jira Tickets and adding them to OmniFocus as Tasks
def add_jira_tickets_to_omnifocus ()
  # Get the open Jira issues assigned to you
  results = get_issues
  if results.nil?
    puts "No results from Jira"
    exit
  end

  # Get the OmniFocus app and main document via AppleScript
  omnifocus_app = Appscript.app.by_name("OmniFocus")
  omnifocus_document = omnifocus_app.default_document

  # Iterate through resulting issues.
  results.each do |jira_id, summary|
    # Create the task name by adding the ticket summary to the jira ticket key
    task_name = "#{jira_id}: #{summary}"
    # Create the task notes with the Jira Ticket URL
    task_notes = "#{JIRA_BASE_URL}/browse/#{jira_id}"

    # Build properties for the Task
    @props = {}
    @props['name'] = task_name
    @props['project'] = DEFAULT_PROJECT
    @props['context'] = DEFAULT_CONTEXT
    @props['note'] = task_notes
    @props['flagged'] = FLAGGED
    add_task(omnifocus_document, @props)
  end
end

def mark_resolved_jira_tickets_as_complete_in_omnifocus ()
  # get tasks from the project
  omnifocus_app = Appscript.app.by_name("OmniFocus")
  omnifocus_document = omnifocus_app.default_document
  ctx = omnifocus_document.flattened_contexts[DEFAULT_CONTEXT]
  ctx.tasks.get.find.each do |task|
    if task.note.get.match(JIRA_BASE_URL)
      # try to parse out jira id
      full_url= task.note.get
      jira_id=full_url.sub(JIRA_BASE_URL+"/browse/","")
      # check status of the jira
      uri = URI(JIRA_BASE_URL + '/rest/api/2/issue/' + jira_id)

      Net::HTTP.start(uri.hostname, uri.port, :use_ssl => uri.scheme == 'https') do |http|
        request = Net::HTTP::Get.new(uri)
        request.basic_auth USERNAME, PASSWORD
        response = http.request request

  if response.code =~ /20[0-9]{1}/
            data = JSON.parse(response.body)
            # Check to see if the Jira ticket has been resolved, if so mark it as complete.
            resolution = data["fields"]["resolution"]
            if resolution != nil
              # if resolved, mark it as complete in OmniFocus
              task.completed.set(true)
            end
            # Check to see if the Jira ticket has been assigned to someone else, if so delete it.  It will be re-created if it is assigned back to you.
            assignee = data["fields"]["assignee"]["name"]
            if assignee != USERNAME
              omnifocus_document.delete task
            end
        else
         raise StandardError, "Unsuccessful response code " + response.code + " for issue " + issue
        end
      end
    end
  end
end

def app_is_running(app_name)
  `ps aux` =~ /#{app_name}/ ? true : false
end

def main ()
   if app_is_running("OmniFocus")
	  add_jira_tickets_to_omnifocus
	  mark_resolved_jira_tickets_as_complete_in_omnifocus
   end
end

main
