#!/usr/bin/env python

# Copyright 2012-2013 Daniel James
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)

import sys, os, subprocess, tempfile, re

def main(args, directory):
    if len(args) != 1:
        print "Usage: output-deps.py quickbook-command"
        exit(1)
    quickbook_command = args[0]

    failures = 0

    # Dependency tests

    failures += run_quickbook(quickbook_command, 'svg_missing.qbk',
            deps_gold = 'svg_missing_deps.txt')
    failures += run_quickbook(quickbook_command, 'svg_missing.qbk',
            locations_gold = 'svg_missing_locs.txt')
    failures += run_quickbook(quickbook_command, 'missing_relative.qbk',
            deps_gold = 'missing_relative_deps.txt',
            locations_gold = 'missing_relative_locs.txt')
    failures += run_quickbook(quickbook_command, 'include_path.qbk',
            deps_gold = 'include_path_deps.txt',
            locations_gold = 'include_path_locs.txt',
            input_path = ['sub1', 'sub2'])
    failures += run_quickbook(quickbook_command, 'include_glob.qbk',
            deps_gold = 'include_glob_deps.txt',
            locations_gold = 'include_glob_locs.txt',
            input_path = ['sub1', 'sub2'])

    # Try building a simple document with various flags.

    failures += run_quickbook(quickbook_command, 'simple.qbk',
        output_gold = 'simple.xml')
    failures += run_quickbook(quickbook_command, 'simple.qbk',
        extra_flags = ['--no-self-linked-headers'],
        output_gold = 'simple_no_self_linked.xml')
    failures += run_quickbook(quickbook_command, 'simple.qbk',
        extra_flags = ['--no-pretty-print'],
        output_gold = 'simple_no_pretty_print.xml')
    failures += run_quickbook(quickbook_command, 'simple.qbk',
        extra_flags = ['--indent','4','--linewidth','60'],
        output_gold = 'simple_custom_pretty_print.xml')

    if failures == 0:
        print "Success"
    else:
        print "Failures:",failures
        exit(failures)

def run_quickbook(quickbook_command, filename, output_gold = None,
        deps_gold = None, locations_gold = None, input_path = [],
        extra_flags = None):
    failures = 0

    command = [quickbook_command, '--debug', filename]

    output_filename = None
    if output_gold:
        output_filename = temp_filename('.qbk')
        command.extend(['--output-file', output_filename])

    deps_filename = None
    if deps_gold:
        deps_filename = temp_filename('.txt')
        command.extend(['--output-deps', deps_filename])

    locations_filename = None
    if locations_gold:
        locations_filename = temp_filename('.txt')
        command.extend(['--output-checked-locations', locations_filename])

    for path in input_path:
        command.extend(['-I', path])

    if extra_flags:
        command.extend(extra_flags)

    try:
        print 'Running: ' + ' '.join(command)
        print
        exit_code = subprocess.call(command)
        print
        success = not exit_code

        if output_filename:
            output = load_file(output_filename)
        else:
            output = None

        if deps_filename:
            deps = load_dependencies(deps_filename)
        else:
            deps = None

        if locations_filename:
            locations = load_locations(locations_filename)
        else:
            locations = None
    finally:
        if output_filename: os.unlink(output_filename)
        if deps_filename: os.unlink(deps_filename)

    if deps_gold:
        gold = load_dependencies(deps_gold)
        if deps != gold:
            failures = failures + 1
            print "Dependencies don't match:"
            print "Gold:", gold
            print "Result:", deps
            print

    if locations_gold:
        gold = load_locations(locations_gold)
        if locations != gold:
            failures = failures + 1
            print "Dependencies don't match:"
            print "Gold:", gold
            print "Result:", locations
            print

    if output_gold:
        gold = load_file(output_gold)
        if gold != output:
            failures = failures + 1
            print "Output doesn't match:"
            print
            print gold
            print
            print output
            print

    return failures

def load_dependencies(filename):
    dependencies = set()
    f = open(filename, 'r')
    for path in f:
        if path[0] == '#': continue
        if path in dependencies:
            raise Exception("Duplicate path (%1s) in %2s" % (path, filename))
        dependencies.add(path)
    return dependencies

def load_locations(filename):
    line_matcher = re.compile("^([+-g]) (.*)$")
    dependencies = {}
    f = open(filename, 'r')
    glob = None
    globs = {}
    for line in f:
        if line[0] == '#': continue
        m = line_matcher.match(line)

        path = m.group(2)

        if not m:
            raise Exception("Invalid dependency file: %1s" % filename)
        if m.group(1) == 'g':
            globs[path] = []
            glob = path
        elif glob:
            if m.group(1) != '+':
                raise Exception("Negative match in glob.")
            globs[glob].append(path)
        else:
            found = m.group(1) == '+'
            if path in dependencies:
                raise Exception("Duplicate path (%1s) in %2s" % (path, filename))
            dependencies[path] = found
    return { 'dependencies': dependencies, 'globs': globs }

def temp_filename(extension):
    file = tempfile.mkstemp(suffix = extension)
    os.close(file[0])
    return file[1]

def load_file(filename):
    f = open(filename, 'r')
    try:
        return f.read()
    finally:
        f.close()

    return None

main(sys.argv[1:], os.path.dirname(sys.argv[0]))