#!/usr/bin/env python
import sys, os.path, subprocess, re, argparse
import yaml

def find_ws_root_dir(current_dir):
    while True:
        if os.path.exists(os.path.join(current_dir,  '.rosinstall')):
            return current_dir
        elif current_dir == '/':
            return None
        current_dir = os.path.abspath(os.path.join(current_dir, os.path.pardir))

def get_remotes(git_dir):
    remote_names = subprocess.check_output(['git', 'remote'], cwd=git_dir).split()
    remotes = {}
    for remote_name in remote_names:
        remotes[remote_name] = {}
        for line in subprocess.check_output(['git', 'remote', 'show', remote_name], cwd=git_dir).split('\n'):
            tokens = [s.lower() for s in line.strip().split()]
            if len(tokens) >= 2 and tokens[0] == 'fetch':
                remotes[remote_name]['fetch_url'] = tokens[2]
            elif len(tokens) >= 2 and tokens[0] == 'push':
                remotes[remote_name]['push_url'] = tokens[2]
    return remotes


def setup_remotes(git_dir):
    remotes = get_remotes(git_dir)

    # rename origin to main
    if 'origin' in remotes:
        print 'Renaming "origin" remote to "main"'
        subprocess.check_output('git remote rename origin main'.split(), cwd=git_dir)

    # make sure a main remote exists
    remotes = get_remotes(git_dir)
    if not 'main' in remotes:
        print 'No main in remotes, cannot setup remotes'
        return

    # parse out the name of the repo
    m = re.match('git@github.com:(.+)\/.+.git', remotes['main']['fetch_url'])
    if m is None:
        print 'Cannot parse main remote: %s' % remotes['main']['fetch_url']
    repo_name = m.groups()[0]
    fork_url = re.sub(repo_name, config['github_username'], remotes['main']['fetch_url'])

    # add a remote for the fork
    fork_name = config['github_username']
    if fork_name in remotes:
        print 'Fork %s already exists' % fork_name
    else:
        print 'Adding remote %s for %s' % (config['github_username'], fork_url)
        subprocess.check_output(['git', 'remote', 'add', config['github_username'], fork_url], cwd=git_dir)

def do_command(command, cwd):
    '''
    Run command with working directory cwd.
    '''
    if command[0] == 'github':
        if command[1] == 'setup_remotes':
            setup_remotes(cwd)
    else:
        try:
            output = subprocess.check_output(command, cwd=cwd)
        except:
            print 'WST ERROR: Nonzero exit status'
            return
        print output

# TODO pull this out into a config file
config = {
    'github_username' : 'jonbinney'
}

if __name__ == '__main__':
    # look in higher level directories to find rosinstall file
    initial_dir = os.getcwd()
    ws_dir = find_ws_root_dir(initial_dir)
    if ws_dir is None:
        print 'No .rosinstall file found in any parent directory'
        sys.exit(-1)
    rosinstall_config = yaml.load(open(os.path.join(ws_dir, '.rosinstall')))
    wst_config = yaml.load(open(os.path.join(ws_dir, '.wst')))

    # we don't use argparse here because we want options at the end of the
    # command to be passed through directly to some shell command, and not
    # parsed as arguments to this script. argparse complains about unknown args.
    args = sys.argv[1:]
    filter_re = None
    if len(args) >= 2 and args[0] == '-f':
        filter_str = args[1]
        filter_re = re.compile(filter_str)
        filter_f = lambda e: filter_re.search(e['local-name'])
        args = args[2:]
    elif len(args) >= 2 and args[0] == '-g':
        group_name = args[1]
        filter_f = lambda e: e['git']['local-name'] in wst_config['groups'][group_name]
        args = args[2:]
    else:
        filter_f = lambda e: True
    command = args

    # apply filters to select rosisntall entries
    selected_entries = []
    for entry in rosinstall_config:
        if 'git' in entry and filter_f(entry):
            selected_entries.append(entry)

    if len(command) > 0:
        print 'Running "%s"\n' % (' '.join(command),)

    for entry in selected_entries:
        print '\033[35m[ %s ]\033[0m' % entry['git']['local-name']
        if len(command) > 0:
            entry_config = entry['git']
            entry_dir = os.path.join(ws_dir, entry_config['local-name'])
            rel_entry_dir = os.path.relpath(entry_dir, ws_dir)

            if filter_re is None or filter_re.search(rel_entry_dir):
                do_command(command, entry_dir)
