#!/usr/bin/env python3
import argparse
import os
import subprocess
import xml.etree.ElementTree as ET

from common import git
from common import Colors


SCRIPTDIR = os.path.dirname(__file__)


def manifest_get_commits(manifest):
    res = {}
    tree = ET.parse(manifest)
    root = tree.getroot()
    for child in root:
        if child.tag == 'project':
            res[child.attrib["name"]] = child.attrib["revision"]
    return res


def update_subprojects(manifest, no_interaction=False):
    if manifest:
        repos_commits = manifest_get_commits(manifest)
    else:
        repos_commits = {}

    subprojects_dir = os.path.join(SCRIPTDIR, "subprojects")
    for repo_name in os.listdir(subprojects_dir):
        repo_dir = os.path.normpath(os.path.join(SCRIPTDIR, subprojects_dir, repo_name))
        if not os.path.exists(os.path.join(repo_dir, '.git')):
            continue
        revision = repos_commits.get(repo_name)
        if not update_repo(repo_name, repo_dir, revision, no_interaction):
            return False

    return True


def update_repo(repo_name, repo_dir, revision, no_interaction, recurse_i=0):
    print("Updating %s..." % repo_name)
    try:
        if revision:
            git("fetch", repository_path=repo_dir)
            git("checkout", revision, repository_path=repo_dir)
        else:
            git("pull", "--rebase", repository_path=repo_dir)
    except Exception as e:
        out = getattr(e, "output", b"").decode()
        if not no_interaction:
            print("====================================="
                  "\n%sEntering a shell in %s to fix that"
                  " just `exit` once done`"
                  "\n=====================================" % (
                        out, os.getcwd()))
            try:
                subprocess.check_call(os.environ.get("SHELL", "/bin/sh"),
                                      cwd=repo_dir)
            except:
                # Result of subshell does not really matter
                pass

            if recurse_i < 3:
                return update_repo(repo_name, repo_dir, revision, no_interaction,
                                    recurse_i + 1)
            return False
        else:
            print("\nCould not rebase %s, please fix and try again."
                    " Error:\n\n%s %s" % (repo_dir, out, e))

            return False


    commit_message = git("show", repository_path=repo_dir).split("\n")
    print(u"  -> %s%s%s — %s" % (Colors.HEADER, commit_message[0][7:14], Colors.ENDC,
                                    commit_message[4].strip()))

    return True


if __name__ == "__main__":
    parser = argparse.ArgumentParser(prog="git-update")

    parser.add_argument("--no-color",
                        default=False,
                        action='store_true',
                        help="Do not output ansi colors.")
    parser.add_argument("--no-interaction",
                        default=False,
                        action='store_true',
                        help="Do not allow interaction with the user.")
    parser.add_argument("--manifest",
                        default=None,
                        help="Use a android repo manifest to sync repositories"
                        " Note that it will let all repositories in detached state")
    options = parser.parse_args()
    if options.no_color:
        Colors.disable()

    exit(not update_subprojects(options.manifest,
                                options.no_interaction))