#!/usr/bin/env python
# Disable pylint filename and missing module member complaints.
# pylint: disable=C0103,E1101
"""
Initializes git hooks for the parent git repository.

TODO(mfehr): fix this script such that we can use the new cpplint. It currently
results in warnings that are not correct IMO. Also ideally find a way to use
the cpplint file online directly, however that would require a different way
of parsing the linter output.

Set this variable to download the cpplint file instead of using the
local !modified! copy:

cpplint_url = "https://raw.githubusercontent.com/google/styleguide/gh-pages/cpplint/cpplint.py"

Set this variable to use the local modified copy of the newest cpplint script:

default_cpplint = "cpplint.py"
"""

from __future__ import print_function

import argparse
import os
import shutil
import subprocess
import sys

import requests
import yaml

default_cpplint = "modified_cpplint.py"

cpplint_url = ""

CLANG_FORMAT_DIFF_EXECUTABLE_VERSIONS = [
    "clang-format-diff", "clang-format-diff-6.0", "clang-format-diff-5.0", "clang-format-diff-4.0",
    "clang-format-diff-3.9", "clang-format-diff-3.8"
]


def download_file_from_url(url, file_path):
    """Download a file from a HTTPS URL. Verification is enabled."""
    request = requests.get(url, verify=True, stream=True)
    request.raw.decode_content = True
    with open(file_path, 'w') as downloaded_file:
        shutil.copyfileobj(request.raw, downloaded_file)


def get_git_repo_root(some_folder_in_root_repo='./'):
    """Get the root folder of the git repository."""
    get_repo_call = subprocess.Popen("git rev-parse --show-toplevel",
                                     shell=True,
                                     cwd=some_folder_in_root_repo,
                                     stdin=subprocess.PIPE,
                                     stdout=subprocess.PIPE)

    stdout, _ = get_repo_call.communicate()
    repo_root = stdout.rstrip()
    return repo_root


def command_exists(cmd):
    """Check if a bash command exists."""
    return subprocess.call("type " + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0


def find_clang_format_executable():
    for executable in CLANG_FORMAT_DIFF_EXECUTABLE_VERSIONS:
        if subprocess.call("type " + executable, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0:
            return executable

    print("ERROR: clang-format-diff is not installed!")
    exit(1)


def get_hooks_folder_for_repo():
    # Get git root folder of parent repository.
    repo_root = get_git_repo_root('.')
    hooks_folder = os.path.join(repo_root, '.git/hooks')
    if os.path.isfile(os.path.join(repo_root, '.git')):
        # Git repo is a submodule, git information is in a folder listed in the .git
        # file.
        with open(os.path.join(repo_root, '.git'), 'r') as git_info_file:
            git_folder = yaml.load(git_info_file)['gitdir']
        repo_root = get_git_repo_root(os.path.join(repo_root, git_folder))
        hooks_folder = os.path.join(repo_root, git_folder, 'hooks')
    return hooks_folder


def install_linter():
    """ Download cpplint.py and pylint.py and installs the git hooks"""
    script_directory = os.path.dirname(sys.argv[0])
    script_directory = os.path.dirname(os.path.abspath(script_directory))

    if cpplint_url != "":
        # Download linter files.
        download_file_from_url(cpplint_url, script_directory + "/cpplint.py")
        if not os.path.isfile(script_directory + "/cpplint.py"):
            print("ERROR: Could not download cpplint.py file!")
            exit(1)
    else:
        cp_params = (script_directory + "/default/" + default_cpplint + " " + script_directory + "/cpplint.py")
        if subprocess.call("sudo cp " + cp_params, shell=True) != 0:
            print("Failed to copy default cpplint.")
            exit(1)

    default_pylint_file = os.path.join(script_directory, 'default', 'pylint.rc')
    if not os.path.isfile(default_pylint_file):
        print("Default pylint.rc wasn't found under", default_pylint_file)
        exit(1)

    cp_params = (default_pylint_file + " " + os.path.join(script_directory, 'pylint.rc'))
    if subprocess.call("sudo cp " + cp_params, shell=True) != 0:
        print("Failed to copy default pylint.rc.")
        exit(1)

    if not os.path.isfile(script_directory + "/pylint.rc"):
        print("ERROR: Could not download pylint.rc file!")
        exit(1)

    find_clang_format_executable()

    if not command_exists("yapf"):
        print("ERROR: yapf is not installed! Try: pip install yapf")
        exit(1)

    # Copy git hooks.
    # hooks_folder = get_hooks_folder_for_repo()
    hooks_folder = os.environ["HOME"] + '/.amz/data/githooks'
    HYPHEN_DIR_EXISTS = os.path.exists(hooks_folder + "/pre-commit-/")
    if not HYPHEN_DIR_EXISTS:
        os.mkdir(hooks_folder + "/pre-commit-")
    cp_params = script_directory + "/git_hooks.py " + \
        hooks_folder + "/pre-commit-/pre-commit-linter"
    if subprocess.call("sudo cp " + cp_params, shell=True) != 0:
        print("Failed to copy githooks to " "{}...".format(hooks_folder))
        exit(1)
    
    # Add a python3 linter
    cp_params = script_directory + "/git_hooks_pylint3.py " + \
        hooks_folder + "/pre-commit-/pre-commit-pylint3"
    if subprocess.call("sudo cp " + cp_params, shell=True) != 0:
        print("Failed to copy githooks to " "{}...".format(hooks_folder))
        exit(1)
    

    print("Success, githooks initialized!")


def remove_linter():
    hooks_folder = get_hooks_folder_for_repo()
    pre_commit_file = os.path.join(hooks_folder, 'pre-commit-/pre-commit-linter')
    with open(pre_commit_file, 'w+') as out_file:
        out_file.write('#!/bin/sh\n')
    pre_commit_file = os.path.join(hooks_folder, 'pre-commit-/pre-commit-pylint3')
    with open(pre_commit_file, 'w+') as out_file:
        out_file.write('#!/bin/sh\n')
    print("Linter githooks removed!")


def main():
    arg_parser = argparse.ArgumentParser()
    arg_parser.add_argument('--remove',
                            dest='remove_linter',
                            action="store_true",
                            help='Remove the linter from this repository.')
    args = arg_parser.parse_args()

    if args.remove_linter:
        remove_linter()
    else:
        install_linter()


if __name__ == "__main__":
    main()
