#!/usr/bin/env python2

import os
import signal
import subprocess
import sys

HOME = os.path.expanduser("~")

WORKING_DIRECTORY = [HOME, "Project", "Firefox", "source"]
WORKING_DIRECTORY_ALTERNATIVE = [HOME, "Firefox", "gecko"]
DIMI_UTITLTY_DIRECTORY = [HOME, "dimitools", "moztools", "bin"]

USER_EMAIL = "dlee@mozilla.com"

def run_process(cmd):
    proc = subprocess.Popen(cmd)

    # ignore SIGINT, the mozlint subprocess should exit quickly and gracefully
    orig_handler = signal.signal(signal.SIGINT, signal.SIG_IGN)
    proc.wait()
    signal.signal(signal.SIGINT, orig_handler)
    return proc.returncode


def checkFileExists(aFile):
    return os.path.exists("/".join(aFile))

def createBugWorkingDirectory(bug):
    gotoWorkingDirectory()

    if isGitBranchExist(bug) == True:
        return

    # This should be able to generated by git command
    git_remote = "origin/bookmarks/central"
    directory = getBugWorkingDirectory(bug)
    cmd = ["git", "worktree", "add", "-b", bug, directory, "--track", git_remote]
    print('[OK]Create bug directory : %s' %(directory))
    run_process(cmd)

def setBugDescription(bug, fDescription):
    gotoWorkingDirectory()

    description = fDescription(bug)
    if not description:
        return

    cmd = ["git", "config", "branch." + str(bug) + ".description", description]
    print('[OK]Set bug %s with description : %s'%(bug, description))
    run_process(cmd)


def getBugIdFromInput():
    # TODO : test current directory
    if len(sys.argv) >= 2:
        bug = sys.argv[1]
        if bug.isdigit():
            return bug
        print("[Error]Input is not valid, get from user")

    bug = str(raw_input("Enter bug id:"))

    if not bug.isdigit():
        print("[Error]Invalid bug number")

    return bug

########################
#
# File system
########################
def getWorkingDirectory():
    return "/".join(WORKING_DIRECTORY)
    dirs = os.listdir(getWorkingDirectory() + "/../")

def gotoWorkingDirectory():
    gotoDirectory(getWorkingDirectory)

def getBugWorkingDirectory(bug):
    return "/".join(WORKING_DIRECTORY[:-1] + [bug])

def gotoDirectory(getDirectory):
    os.chdir(getDirectory())

def getBugsDirectory():
    dirs = os.listdir(getWorkingDirectory() + "/../")

    gotoWorkingDirectory()

    out = []
    for dir in dirs:
        if isGitBranchExist(dir):
            out.append(dir)
    return out

def updateBugsDescription(bugs):
    query = getQueryFromBranchList(bugs)
    request = "https://bugzilla.mozilla.org/rest/bug?id=" + query + "&include_fields=id,status,summary"
    response = bugzilla_request(request)['bugs']
    for info in response:
        setBugDescription(info['id'], lambda x : info['summary'])

def dumpBranchDescription(branches):
    gotoWorkingDirectory()

    status = getBugStatus(branches)
    for branch in branches:
        if not branch in status or status[branch] in ['RESOLVED']:
            continue

        cmd = ['git', 'config', 'branch.' + branch + '.description']
        ret = os.popen("git config branch." + branch + ".description").read().strip()
        if ret == '':
            ret = getSummaryByBugNumber(branch)

        print('[%8s] %s : %s' %(status[branch] if status[branch] else 'UNKNOWN', branch, ret))

def dumpBranchDescriptionMore(branches):
    gotoWorkingDirectory()

    status = getBugStatus(branches)
    for branch in branches:
        if not branch in status:
            continue
        cmd = ['git', 'config', 'branch.' + branch + '.description']
        ret = os.popen("git config branch." + branch + ".description").read().strip()
        if ret == '':
            ret = getSummaryByBugNumber(branch)

        print('[%8s] %s : %s' %(status[branch] if status[branch] else 'UNKNOWN', branch, ret))

########################
#
# Build
########################
def prepareBuild(bug):
    os.chdir(getBugWorkingDirectory(bug))

    # get mozconfig
    cmd = ["getmozconfig.sh"]
    run_process(cmd)
    return

def build(bug):
    os.chdir(getBugWorkingDirectory(bug))

    # get mozconfig
    cmd = ["./mach", "build"]
    run_process(cmd)

########################
#
# Git utility
# Assume we are already under the repository
########################
def isGitBranchExist(branch):
    cmd = ['git', 'show-ref', '--quiet', 'refs/heads/' + branch]
    if 0 == run_process(cmd):
        return True
    return False

########################
#
# This is for Bugzilla
########################
def bugzilla_request(request):
    import urllib2
    import json
    try:
        contents = urllib2.urlopen(request).read()
    except:
        return {}
    return json.loads(contents)

# TODO: this doesn't show security bugs
def dumpBugIdAndSummary(bugs):
    for i in range(len(bugs)):
        print("[%d]%d : %s" %(i, bugs[i]['id'], bugs[i]['summary']))

def showAssignedBugByUser(user_email = USER_EMAIL):
    dumpBugIdAndSummary(getBugsByAssignedUser(user_email))

def getQueryFromBranchList(branches):
    bugs = filter(lambda x: x.isdigit(), branches)
    return ",".join(bugs)

def getSummaryByBugNumber(bugs):
    if not bugs.isdigit():
        return
    response = bugzilla_request("https://bugzilla.mozilla.org/rest/bug/" +
                                bugs + "?include_fields=summary")
    return response['bugs'][0]['summary'] if response else ""

def getBugsByAssignedUser(user_email):
    request = "https://bugzilla.mozilla.org/rest/bug?assigned_to=" + user_email + "&status=ASSIGNED"
    response = bugzilla_request(request)
    return response['bugs'] if response else ""

def getBugStatus(branches):
    query = getQueryFromBranchList(branches)
    request = "https://bugzilla.mozilla.org/rest/bug?id=" + query + "&include_fields=id,status"
    response = bugzilla_request(request)
    bugs = response['bugs'] if response else ""
    ret = {}
    for r in bugs:
        ret[str(r['id'])] = r['status']
    return ret

def getBugNumberByLocalId(localId, user_email = USER_EMAIL):
    content = getBugsByAssignedUser(user_email)
    if len(content) > localId:
        print('[Error]Index out of range')
        sys.exit(1)
    else:
        return str(content[int(localId)]['id'])

########################
#
# Command
########################
def init():
    global WORKING_DIRECTORY
    if not checkFileExists(WORKING_DIRECTORY):
        if checkFileExists(WORKING_DIRECTORY_ALTERNATIVE):
            WORKING_DIRECTORY = WORKING_DIRECTORY_ALTERNATIVE
        else:
            print("[Error]Init fail, file(%s) doesn't exist" %(WORKING_DIRECTORY))

    if not checkFileExists(DIMI_UTITLTY_DIRECTORY):
        print("[Error]Init fail, file(%s) doesn't exist" %(DIMI_UTITLTY_DIRECTORY))

def workOnBug(bug, user_email = USER_EMAIL):
    if bug == None:
        showAssignedBugByUser(USER_EMAIL)
        bug = getBugNumberByLocalId(getBugIdFromInput())

    print("Working on bug %s"%(bug))
    print("[OK]Use %s as working directory" %(WORKING_DIRECTORY))

    if os.path.exists(getBugWorkingDirectory(bug)):
        con = raw_input("We already have the directory, continue? [y/g/N]")
        if con == "y":
            pass
        elif con == "g":
            cmd = ["ln", "-sf", getBugWorkingDirectory(bug), HOME + "/go"]
            run_process(cmd)
            sys.exit(0)
        else:
            sys.exit(0)

    # 1. Create the bug's working directory
    createBugWorkingDirectory(bug)

    # 2. Set bug description
    setBugDescription(bug, getSummaryByBugNumber)

    # 2. Prepare build
    prepareBuild(bug)

    # 3. Build
    build(bug)

def showHelp():
    list = [('list', 'query bugzilla and show current assigned bugs'),
            ('assigned', 'work on current assigned bug '),
            ('[0-9*]', 'work on bug with specified bug nummber'),
            ('show', 'show the information of local directory'),
            ('showmore', 'show the information of local directory with bug status')]
    for l in list:
        print '   %-20s %s' %(l[0], l[1])

def parse_argument(args):
    cmd = None
    if len(args) >= 2:
        cmd = args[1]

    init()

    if cmd == None:
        workOnBug(None)
    elif cmd == '-h':
        showHelp()
    elif cmd == 'list':
        showAssignedBugByUser(USER_EMAIL)
    elif cmd == 'assigned':
        showAssignedBugByUser(USER_EMAIL)
        id = str(raw_input('Enter the id:'))
        workOnBug(getBugNumberByLocalId(id, USER_EMAIL))
    elif cmd.isdigit():
        workOnBug(cmd)
    elif cmd == 'show':
        dir = getBugsDirectory()
        dumpBranchDescription(dir)
    elif cmd == 'showmore':
        dir = getBugsDirectory()
        dumpBranchDescriptionMore(dir)
    elif cmd == 'update':
        updateBugsDescription(getBugsDirectory())
    else:
        print 'unknown command'

if __name__ == '__main__':
    parse_argument(sys.argv)

