#!/usr/bin/env python

import os
import json
import argparse
import re
import subprocess
import sys

OCLINT_BIN_FOLDER = os.path.dirname(os.path.abspath(__file__))
OCLINT_BIN = OCLINT_BIN_FOLDER + "/oclint-0.7"
CURRENT_WORKING_DIRECTORY = os.getcwd()
JSON_COMPILATION_DATABASE = CURRENT_WORKING_DIRECTORY + "/compile_commands.json"

arg_parser = argparse.ArgumentParser(description='OCLint for JSON Compilation Database (compile_commands.json)')
arg_parser.add_argument("-v", action="store_true", dest="invocation", help="show invocation command with arguments")
arg_parser.add_argument('-debug', '--debug', action="store_true", dest="debug", help="invoke OCLint in debug mode")
arg_parser.add_argument('-i', '-include', '--include', action='append', dest='includes', help="extract files matching pattern")
arg_parser.add_argument('-e', '-exclude', '--exclude', action='append', dest='excludes', help="remove files matching pattern")
arg_parser.add_argument('oclint_args', nargs='*', help="arguments that are passed to OCLint invocation")
args = arg_parser.parse_args()

def get_source_path(file_attr, dir_attr):
    if file_attr.startswith("/"):
        return file_attr
    elif dir_attr[-1] == "/":
        return dir_attr + file_attr
    else:
        return dir_attr + "/" + file_attr

def source_exist_at(path):
    return os.path.isfile(path)

def source_list_inclusion_filter(source_list, inclusion_filter):
    filtered_list = []
    for path in source_list:
        if re.search(inclusion_filter, path):
            filtered_list.append(path)
    return filtered_list

def source_list_exclusion_filter(source_list, exclusion_filter):
    filtered_list = []
    for path in source_list:
        if not re.search(exclusion_filter, path):
            filtered_list.append(path)
    return filtered_list

if os.path.isfile(OCLINT_BIN):
    if os.path.isfile(JSON_COMPILATION_DATABASE):
        compilation_database = json.load(open(JSON_COMPILATION_DATABASE))
        source_list = []
        for file_item in compilation_database:
            file_path = get_source_path(file_item["file"], file_item["directory"])
            if (source_exist_at(file_path)):
                source_list.append(file_path)
        if args.includes:
            for inclusion_filter in args.includes:
                source_list = source_list_inclusion_filter(source_list, inclusion_filter)
        if args.excludes:
            for exclusion_filter in args.excludes:
                source_list = source_list_exclusion_filter(source_list, exclusion_filter)
        source_paths = '"' + '" "'.join(source_list) + '"'
        oclint_arguments = ''
        if args.oclint_args:
            oclint_arguments = ' ' + ' '.join(args.oclint_args)
        debug_argument = ''
        if args.debug:
            debug_argument = ' -debug'
        oclint_invocation = OCLINT_BIN + debug_argument + oclint_arguments + ' ' + source_paths
        if args.invocation:
            print '------------------------------ OCLint ------------------------------'
            print oclint_invocation
            print '--------------------------------------------------------------------'
        exit_code = subprocess.call(oclint_invocation, shell=True)
        sys.exit(exit_code)
    else:
        print "Error: compile_commands.json not found at current location."
else:
    print "Error: OCLint executable file not found."
