# -*- coding: utf-8 ; ispell-local-dictionary: "american" -*-
"""
git-flow init
"""
#
# This file is part of `gitflow`.
# Copyright (c) 2010-2011 Vincent Driessen
# Copyright (c) 2012 Hartmut Goebel
# Distributed under a BSD-like license. For full terms see the file LICENSE.txt
#

import sys
import re

try:
    # this will trigger readline functionality for raw_input
    import readline
except:
    # readline is optional and may not be available on all installations
    pass

from gitflow.core import GitFlow as CoreGitFlow, warn, info

from gitflow.exceptions import (AlreadyInitialized, NotInitialized,
                                NoSuchLocalBranchError, NoSuchBranchError,
                                IllegalCommunicationProtocol, RemoteNotFound)

import gitflow.review as rb
import gitflow.pivotal as pt

__copyright__ = "2010-2011 Vincent Driessen; 2012 Hartmut Goebel"
__license__ = "BSD"


def _ensure_SSH():
    gitflow_origin = gitflow.get('gitflow.origin')
    try:
        origin_url = gitflow.get('remote.' + gitflow_origin + '.url')
    except Exception:
        raise RemoteNotFound(
                "Please configure git remote '{0}' before proceesing further." \
                        .format(gitflow_origin))
    if re.match('(https?://|git://)', origin_url):
        raise IllegalCommunicationProtocol("Only SSH remotes are supported.")

class GitFlow(CoreGitFlow):

    @staticmethod
    def _has_configured(branch_func):
        try:
            branch_func()
        except (NotInitialized, IndexError):
            return False
        return True

    def has_master_configured(self):
        return self._has_configured(self.master)

    def has_develop_configured(self):
        return self._has_configured(self.develop)

    def get_default(self, setting):
        return self.get(setting, self.defaults[setting])
        

def _ask_branch(args, name, desc1, desc2, suggestions, filter=[]):
    # Two cases are distinguished:
    # 1. A fresh git repo (without any branches)
    #    We will create a new master/develop branch for the user
    # 2. Some branches do already exist
    #    We will disallow creation of new master/develop branches and
    #    rather allow to use existing branches for git-flow.
    name = 'gitflow.branch.' + name
    default_name = gitflow.get_default(name)
    local_branches = [b
                      for b in gitflow.branch_names()
                      if b not in filter]
    if not local_branches:
        if not filter:
            print "No branches exist yet. Base branches must be created now."
        should_check_existence = False
        default_suggestion = default_name
    else:
        should_check_existence = True
        print
        print "Which branch should be used for %s?" % desc1
        for b in local_branches:
            print '  -', b
        for default_suggestion in [default_name] + suggestions:
            if default_suggestion in local_branches:
                break
        else:
            default_suggestion = ''

    if args.use_defaults and default_suggestion:
        print "Branch name for %s:" % desc2, default_suggestion
        branch_name = default_suggestion
    else:
        answer = raw_input("Branch name for %s: [%s] "
                           % (desc2, default_suggestion))
        branch_name = answer.strip() or default_suggestion
    if not branch_name:
        raise SystemExit('You need to give a branch name.')
    # check existence in case of an already existing repo
    if branch_name in filter:
        raise SystemExit("Production and integration branches should differ.")
    if should_check_existence:
        # if no local branch exists and a remote branch of the same
        # name exists, checkout that branch and use it for the local branch
        if not branch_name in local_branches:
            remote_name = gitflow.origin_name(branch_name)
            if remote_name in gitflow.branch_names(remote=True):
                branch = gitflow.repo.create_head(branch_name, remote_name)
                info("Created local branch %s based on %s."
                     % (branch_name, remote_name))
            else:
                raise NoSuchLocalBranchError(branch_name)

    # store the name of the develop branch
    gitflow.set(name, branch_name)
    return branch_name


def _ask_config(args, name, question):
    default_suggestion = gitflow.get_default(name)
    if args.use_defaults:
        print question +':', default_suggestion
        answer = default_suggestion
    else:
        answer = raw_input(question + '? [' + default_suggestion + '] ')
        answer = answer.strip() or default_suggestion
        if answer == '-':
            answer = ''
    gitflow.set(name, answer)

def _ask_prefix(args, name, question):
    name = 'gitflow.prefix.' + name
    if not gitflow.get(name, None) or args.force:
        _ask_config(args, name, question)

def _ask_name(args, name, question):
    name = 'gitflow.' + name
    if not gitflow.get(name, None) or args.force:
        _ask_config(args, name, question)

def _pick(title, source):
    print
    print 'Please choose one of the following %s:' % title
    msg = '    Loading...'
    sys.stdout.write(msg)
    sys.stdout.flush()
    suggestions = source()
    sys.stdout.write('\r' * len(msg))
    while True:
        i = 0
        for sid, sname in suggestions:
            i += 1
            print '    [%d] %s' % (i, sname)
        a = raw_input("Insert the sequence number (or 'q' to quit): ")
        if a == 'q':
            raise SystemExit('Operation canceled.')
        try:
            answer = int(a)
        except ValueError:
            print 'Please specify a number betweet 1 and %i:' % i
            continue
        if answer >= 1 and answer <= i:
            return suggestions[answer-1]

def _ask_pt_projid():
    gitflow.set('gitflow.pt.projectid',
                _pick('Pivotal Tracker projects', pt.list_projects)[0])

def _ask_rb_repoid():
    gitflow.set('gitflow.rb.repoid',
                _pick('Review Board repositories', rb.list_repos)[0])

def run_default(args):
    global gitflow
    gitflow = GitFlow()
    gitflow._enforce_git_repo()
    gitflow._enforce_services()

    if gitflow.is_initialized():
        if not args.force:
            raise AlreadyInitialized()

    if args.use_defaults:
        warn("Using default branch names.")

    _ask_name(args, "origin", "Remote name to use as origin in git flow")
 
    # Make sure that origin uses SSH protocol for communication,
    # otherwise Review Board is going to fail.
    _ensure_SSH()

    #-- add a master branch if no such branch exists yet
    if gitflow.has_master_configured() and not args.force:
        master_branch = gitflow.master_name()
    else:
        master_branch = _ask_branch(args,
            'master',
            'bringing forth production releases',
            'production releases',
            ['production', 'main', 'master'])

    #-- add a develop branch if no such branch exists yet
    if gitflow.has_develop_configured() and not args.force:
        develop_branch = gitflow.develop_name()
    else:
        develop_branch = _ask_branch(args,
            'develop',
            'integration of the "next release"',
            '"next release" development',
            ['develop', 'int', 'integration', 'master'],
            filter=[master_branch])

    if not gitflow.is_initialized() or args.force:
        print
        print "How to name your supporting branch prefixes?"

    _ask_prefix(args, "feature", "Feature branches")
    _ask_prefix(args, "release", "Release branches")
    _ask_prefix(args, "hotfix", "Hotfix branches")
    _ask_prefix(args, "support", "Support branches")
    _ask_prefix(args, "versiontag", "Version tag prefix")

    _ask_name(args, 'release.versionmatcher',
            'Regular expression for matching release numbers')

    _ask_pt_projid()
    _ask_rb_repoid()

    # assert the gitflow repo has been correctly initialized
    assert gitflow.is_initialized()

    gitflow.init(master_branch, develop_branch)
