#! /usr/bin/env python

import argparse
import shutil
import subprocess
import sys
import os

from oclintscripts import cmake
from oclintscripts import environment
from oclintscripts import path
from oclintscripts import process
from oclintscripts import version

arg_parser = argparse.ArgumentParser()
arg_parser.add_argument('task_name', choices=['checkout', 'co', 'update', 'up', 'build', 'prebuilt'])
arg_parser.add_argument('-branch', '--branch', nargs='?', choices=version.llvm_branches(), default=version.llvm_default_branch())
arg_parser.add_argument('-rev', '--rev')
arg_parser.add_argument('-clean', '--clean', action="store_true")
arg_parser.add_argument('-release', '--release', action="store_true")
arg_parser.add_argument('-j', type=int, default=0)
args = arg_parser.parse_args()

def clean_module():
    build_path = path.build.clang_build_dir
    path.rm_f(build_path)
    install_dir = path.build.clang_install_dir
    path.rm_f(install_dir)

def build_command(is_release):
    cmd_build = cmake.builder(path.source.clang_dir)
    if is_release:
        cmd_build.append('CMAKE_BUILD_TYPE', 'Release')
    else:
        cmd_build.append('CMAKE_BUILD_TYPE', 'Debug')
    if environment.is_mingw32():
        cmd_build.append('LLVM_BUILD_RUNTIME', 'OFF')
    else:
        cmd_build.append('LLVM_BUILD_RUNTIME', 'ON')
    if environment.is_darwin():
        cmd_build.append('CMAKE_CXX_FLAGS', '-std=c++11 -stdlib=libc++ ${CMAKE_CXX_FLAGS}', True)
    cmd_build.append('CMAKE_INSTALL_PREFIX', path.build.clang_install_dir, environment.is_mingw32())
    return cmd_build.str()

def build_module(is_release, j):
    build_path = path.build.clang_build_dir

    command = build_command(is_release)

    current_dir = os.getcwd()
    path.mkdir_p(build_path)
    path.cd(build_path)
    process.call(command)
    process.make(j)
    process.call('make install')
    path.cd(current_dir)

def copy_cpp_headers():
    install_dir = path.build.clang_install_dir
    cpp_dir = os.path.join(install_dir, 'include', 'c++')
    if environment.is_darwin() and not path.is_dir(cpp_dir):
        xcode_root = subprocess.check_output(['xcode-select', '--print-path']).strip()
        xcode_cpp_headers = os.path.join(xcode_root, 'Toolchains', 'XcodeDefault.xctoolchain', 'usr', 'include', 'c++')
        path.cp_r(xcode_cpp_headers, cpp_dir)

def svn_checkout(url, prefix, root_dir, rev=None):
    current_dir = os.getcwd()
    path.cd(root_dir)
    svn_command = 'svn checkout ' + url
    if rev:
        svn_command += ' -r ' + rev
    process.call(svn_command + ' ' + prefix)
    path.cd(current_dir)

def svn_update(root_dir, rev):
    current_dir = os.getcwd()
    path.cd(root_dir)
    svn_command = 'svn up'
    if rev:
        svn_command += ' -r ' + rev
    process.call(svn_command)
    path.cd(current_dir)

def checkout_clang(branch_name, rev=None):
    if path.is_dir(path.source.clang_dir):
        sys.exit('Clang folder exists!')
    svn_checkout(path.url.llvm + branch_name, 'llvm', path.root_dir, rev)
    svn_checkout(path.url.clang + branch_name, 'clang', os.path.join(path.root_dir, 'llvm', 'tools'), rev)
    svn_checkout(path.url.clang_rt + branch_name, 'compiler-rt', os.path.join(path.root_dir, 'llvm', 'projects'), rev)

def update_clang(rev):
    if not path.is_dir(path.source.clang_dir):
        sys.exit('Clang folder does not exist!')
    svn_update(os.path.join(path.root_dir, 'llvm'), rev)
    svn_update(os.path.join(path.root_dir, 'llvm', 'tools', 'clang'), rev)
    svn_update(os.path.join(path.root_dir, 'llvm', 'projects', 'compiler-rt'), rev)

def setup_prebuilt_binary():
    build_path = path.build.clang_build_dir
    install_path = path.build.clang_install_dir

    if environment.is_darwin():
        binary_url = path.url.clang_prebuilt_binary_for_macos
    elif environment.is_linux():
        binary_url = path.url.clang_prebuilt_binary_for_ubuntu_lts_16
    else:
        binary_url = path.url.clang_prebuilt_binary_for_ubuntu_lts_16

    current_dir = os.getcwd()
    path.mkdir_p(build_path)
    path.cd(build_path)
    process.call('curl -o prebuilt.tar.xz ' + binary_url)
    path.mkdir_p(install_path)
    process.call('tar xf prebuilt.tar.xz -C ' + install_path + ' --strip-components=1')
    path.cd(current_dir)

if args.task_name == 'checkout' or args.task_name == 'co':
    checkout_clang(args.branch, args.rev)

if args.task_name == 'update' or args.task_name == 'up':
    update_clang(args.rev)

if args.task_name == 'prebuilt':
    setup_prebuilt_binary()

if args.task_name == 'build':
    if args.clean:
        clean_module()
    build_module(args.release, args.j)
    if environment.is_darwin():
        copy_cpp_headers()
