#!/usr/bin/env python
import filecmp
import glob
import os
import shutil
import subprocess

from waflib.extras import autowaf as autowaf
import waflib.Logs as Logs, waflib.Options as Options

# Version of this package (even if built as a child)
ZIX_VERSION       = '0.0.2'
ZIX_MAJOR_VERSION = '0'

# Library version (UNIX style major, minor, micro)
# major increment <=> incompatible changes
# minor increment <=> compatible changes (additions)
# micro increment <=> no interface changes
# Zix uses the same version number for both library and package
ZIX_LIB_VERSION = ZIX_VERSION

# Variables for 'waf dist'
APPNAME = 'zix'
VERSION = ZIX_VERSION

# Mandatory variables
top = '.'
out = 'build'

def options(opt):
    autowaf.set_options(opt)
    opt.load('compiler_c')
    opt.add_option('--test', action='store_true', default=False, dest='build_tests',
                   help="Build unit tests")
    opt.add_option('--bench', action='store_true', default=False, dest='build_bench',
                   help="Build benchmarks")

def configure(conf):
    conf.load('compiler_c')
    autowaf.configure(conf)
    autowaf.display_header('Zix Configuration')

    if conf.env['MSVC_COMPILER']:
        conf.env.append_unique('CFLAGS', ['-TP', '-MD'])
    else:
        conf.env.append_unique('CFLAGS', '-std=c99')

    conf.env['BUILD_BENCH'] = Options.options.build_bench
    conf.env['BUILD_TESTS'] = Options.options.build_tests

    # Check for mlock
    conf.check(function_name='mlock',
               header_name='sys/mman.h',
               define_name='HAVE_MLOCK',
               mandatory=False)

    # Check for gcov library (for test coverage)
    if conf.env['BUILD_TESTS']:
        conf.check_cc(lib='gcov',
                      define_name='HAVE_GCOV',
                      mandatory=False)

    if Options.options.build_bench:
        autowaf.check_pkg(conf, 'glib-2.0', uselib_store='GLIB',
                          atleast_version='2.0.0', mandatory=False)
        if not conf.is_defined('HAVE_GLIB'):
            conf.fatal("Glib is required to build benchmarks")

    autowaf.define(conf, 'ZIX_VERSION', ZIX_VERSION)
    conf.write_config_header('zix-config.h', remove=False)

    autowaf.display_msg(conf, "Unit tests", str(conf.env['BUILD_TESTS']))
    autowaf.display_msg(conf, "Benchmarks", str(conf.env['BUILD_BENCH']))
    print('')

tests = [
    'hash_test',
    'patree_test',
    'ring_test',
    'sem_test',
    'sorted_array_test',
    'strindex_test',
    'tree_test'
]

def build(bld):
    # C Headers
    bld.install_files('${INCLUDEDIR}/zix', bld.path.ant_glob('zix/*.h'))

    # Pkgconfig file
    autowaf.build_pc(bld, 'ZIX', ZIX_VERSION, ZIX_MAJOR_VERSION, [],
                     {'ZIX_MAJOR_VERSION' : ZIX_MAJOR_VERSION})

    framework = ''
    if Options.platform == 'darwin':
        framework = ['CoreServices']

    libflags = [ '-fvisibility=hidden' ]
    if bld.env['MSVC_COMPILER']:
        libflags = []

    lib_source = '''
        src/fat_patree.c
        src/hash.c
        src/patree.c
        src/ring.c
        src/sorted_array.c
        src/strindex.c
        src/tree.c
    '''

    # Library
    obj = bld(features        = 'c cshlib',
              export_includes = ['.'],
              source          = lib_source,
              includes        = ['.', './src'],
              name            = 'libzix',
              target          = 'zix',
              vnum            = ZIX_LIB_VERSION,
              install_path    = '${LIBDIR}',
              framework       = framework,
              cflags          = libflags + ['-DZIX_SHARED',
                                            '-DZIX_INTERNAL'])

    if bld.env['BUILD_TESTS']:
        test_libs   = ['pthread']
        test_cflags = []
        if bld.is_defined('HAVE_GCOV'):
            test_libs   += ['gcov']
            test_cflags += ['-fprofile-arcs', '-ftest-coverage']

        # Static library (for unit test code coverage)
        obj = bld(features     = 'c cstlib',
                  source       = lib_source,
                  includes     = ['.', './src'],
                  lib          = test_libs,
                  name         = 'libzix_profiled',
                  target       = 'zix_profiled',
                  install_path = '',
                  framework    = framework,
                  cflags       = test_cflags + ['-DZIX_INTERNAL'])

        # Unit test programs
        for i in tests:
            obj = bld(features     = 'c cprogram',
                      source       = 'test/%s.c' % i,
                      includes     = ['.'],
                      use          = 'libzix_profiled',
                      lib          = test_libs,
                      target       = 'test/%s' % i,
                      install_path = '',
                      framework    = framework,
                      cflags       = test_cflags)

    if bld.env['BUILD_BENCH']:
        # Benchmark programs
        for i in ['tree_bench', 'patree_bench']:
            obj = bld(features     = 'c cprogram',
                      source       = 'test/%s.c' % i,
                      includes     = ['.'],
                      use          = 'libzix',
                      uselib       = 'GLIB',
                      lib          = ['rt'],
                      target       = 'test/%s' % i,
                      framework    = framework,
                      install_path = '')

    # Documentation
    autowaf.build_dox(bld, 'ZIX', ZIX_VERSION, top, out)

    bld.add_post_fun(autowaf.run_ldconfig)
    if bld.env['DOCS']:
        bld.add_post_fun(fix_docs)

def lint(ctx):
    subprocess.call('cpplint.py --filter=-whitespace/tab,-whitespace/braces,-build/header_guard,-readability/casting,-readability/todo src/* zix/*', shell=True)

def build_dir(ctx, subdir):
    if autowaf.is_child():
        return os.path.join('build', APPNAME, subdir)
    else:
        return os.path.join('build', subdir)

def fix_docs(ctx):
    try:
        os.chdir('build/doc/html')
        os.system("sed -i 's/ZIX_API //' group__zix.html")
        os.system("sed -i 's/ZIX_DEPRECATED //' group__zix.html")
        os.remove('index.html')
        os.symlink('group__zix.html',
                   'index.html')
    except:
        Logs.error("Failed to fix up %s documentation" % APPNAME)

def fix_docs(ctx):
    try:
        top = os.getcwd()
        os.chdir(build_dir(ctx, 'doc/html'))
        os.system("sed -i 's/ZIX_API //' group__zix.html")
        os.remove('index.html')
        os.symlink('group__zix.html',
                   'index.html')
        os.chdir(top)
    except Exception as e:
        Logs.error("Failed to fix up %s documentation (%s)" % (APPNAME, e))

def upload_docs(ctx):
    os.system("rsync -avz --delete -e ssh build/doc/html/* drobilla@drobilla.net:~/drobilla.net/docs/zix")

def test(ctx):
    autowaf.pre_test(ctx, APPNAME)
    for i in tests:
        autowaf.run_tests(ctx, APPNAME, ['test/%s' % i], dirs=['./src','./test'])
    autowaf.post_test(ctx, APPNAME)