#!/usr/bin/env python

import os
import re
import shutil
import subprocess

from waflib import Options
from waflib.extras import autowaf

BLOP_VERSION = '1.0.2'

# Mandatory waf variables
APPNAME = 'blop-lv2'    # Package name for waf dist
VERSION = BLOP_VERSION  # Package version for waf dist
top     = '.'           # Source directory
out     = 'build'       # Build directory

# Release variables
uri          = 'http://drobilla.net/sw/blop.lv2'
dist_pattern = 'http://download.drobilla.net/blop-lv2-%d.%d.%d.tar.bz2'
post_tags    = ['LV2', 'Blop.lv2']

def options(ctx):
    ctx.load('compiler_c')
    ctx.load('lv2')
    opt = ctx.configuration_options()
    opt.add_option('--rate', type='int', default=48000,
                   dest='rate',
                   help='ideal sample rate for oscillator wave tables [Default: 48000]')

def configure(conf):
    conf.load('compiler_c', cache=True)
    conf.load('lv2', cache=True)
    conf.load('autowaf', cache=True)
    autowaf.set_c_lang(conf, 'c99')

    if Options.options.ultra_strict:
        autowaf.add_compiler_flags(conf.env, 'c', {
            'clang': [
                '-Wno-bad-function-cast',
                '-Wno-covered-switch-default',
                '-Wno-double-promotion',
                '-Wno-extra-semi-stmt',
                '-Wno-float-equal',
                '-Wno-implicit-float-conversion',
                '-Wno-padded',
                '-Wno-shorten-64-to-32',
                '-Wno-sign-conversion',
                '-Wno-unreachable-code-break',
                '-Wno-unused-parameter',
            ],
            'gcc': [
                '-Wno-bad-function-cast',
                '-Wno-conversion',
                '-Wno-double-promotion',
                '-Wno-float-conversion',
                '-Wno-float-equal',
                '-Wno-inline',
                '-Wno-null-dereference',
                '-Wno-padded',
                '-Wno-suggest-attribute=pure',
                '-Wno-unused-parameter',
            ]
        })

    conf.check_pkg('lv2 >= 1.16.0', uselib_store='LV2')

    conf.check_function('c',  'sinf',
                        header_name = 'math.h',
                        lib         = 'm',
                        define_name = 'HAVE_SINF',
                        return_type = 'float',
                        arg_types   = 'float',
                        mandatory   = False)

    conf.check(define_name = 'HAVE_LIBDL',
               lib         = 'dl',
               mandatory   = False)

    conf.check_function('c', 'getopt_long',
                        header_name = 'getopt.h',
                        return_type = 'int',
                        arg_types   = '''int,
                                       char* const*,
                                       const char*,
                                       const struct option*,
                                       int*'''
    )

    conf.write_config_header('blop_config.h', remove=False)

    conf.define('BLOP_SHLIB_EXT', conf.env.LV2_LIB_EXT)

    conf.run_env.append_unique('LV2_PATH', [conf.build_path('lv2')])

    autowaf.display_summary(conf,
                            {'LV2 bundle directory': conf.env.LV2DIR,
                            'Ideal sampling rate': Options.options.rate})

def build_plugin(bld, lang, bundle, name, source, defines=None, lib=[]):
    # Make a pattern for shared objects without the 'lib' prefix
    module_pat = re.sub('^lib', '', bld.env.cshlib_PATTERN)

    # Build plugin library
    obj = bld(features     = '%s %sshlib lv2lib' % (lang,lang),
              source       = source,
              includes     = ['.', 'src/include'],
              name         = name,
              target       = os.path.join('lv2', bundle, name),
              uselib       = ['LV2'],
              lib          = ['m'] + lib,
              install_path = '${LV2DIR}/' + bundle)

    if defines != None:
        obj.defines = defines

    # Install data file
    data_file = '%s.ttl' % name
    bld.install_files('${LV2DIR}/' + bundle, os.path.join(bundle, data_file))

def build(bld):
    for i in bld.path.ant_glob('blop.lv2/*.ttl'):
        bld(features     = 'subst',
            is_copy      = True,
            source       = i,
            target       = 'lv2/blop.lv2/%s' % i.name,
            install_path = '${LV2DIR}/blop.lv2')

    bld(features     = 'subst',
        source       = 'blop.lv2/manifest.ttl.in',
        target       = 'lv2/blop.lv2/manifest.ttl',
        LIB_EXT      = bld.env.LV2_LIB_EXT,
        install_path = '${LV2DIR}/blop.lv2')

    plugins = '''
		adsr
		adsr_gt
		amp
		branch
		dahdsr
		difference
		fmod
		interpolator
		product
		random
		ratio
		sum
		sync_pulse
		sync_square
		tracker
	'''.split()

    # Simple (single source file) plugins
    for i in plugins:
        build_plugin(bld, 'c', 'blop.lv2', i,
                     ['src/%s.c' % i])

    # Low pass filter
    build_plugin(bld, 'c', 'blop.lv2', 'lp4pole',
                 ['src/lp4pole.c', 'src/lp4pole_filter.c'])

    # Oscillators
    for i in ['pulse', 'sawtooth', 'square', 'triangle']:
        lib = []
        if bld.is_defined('HAVE_LIBDL'):
            lib += ['dl']
        build_plugin(bld, 'c', 'blop.lv2', i,
                     ['src/%s.c' % i, 'src/wavedata.c'],
                     lib=lib)

    # Sequencers
    for i in [16, 32, 64]:
        uri = 'http://drobilla.net/plugins/blop/sequencer_%d' % i
        build_plugin(bld, 'c', 'blop.lv2', 'sequencer_%d' % i,
                     ['src/sequencer.c'],
                     defines=['SEQUENCER_MAX_INPUTS=%d' % i,
                              'SEQUENCER_URI="%s"' % uri])

    # Quantisers
    for i in [20, 50, 100]:
        uri = 'http://drobilla.net/plugins/blop/quantiser_%d' % i
        build_plugin(bld, 'c', 'blop.lv2', 'quantiser_%d' % i,
                     ['src/quantiser.c'],
                     defines=['QUANTISER_MAX_INPUTS=%d' % i,
                              'QUANTISER_URI="%s"' % uri])

    # Wavegen
    wavegen = bld(features     = 'c cprogram',
                  source       = ['src/wavegen.c', 'src/wdatutil.c'],
                  target       = 'src/wavegen',
                  name         = 'wavegen',
                  includes     = ['.', 'src/include'],
                  lib          = ['m'],
                  install_path = None)

    wavegen.post()
    bld.add_group()

    # Waveform data source
    for i in ['parabola', 'sawtooth', 'square']:
        cmd = '${SRC} -r %d -f 12 -s 1 -m 128 -g 1.0 -w %s -p %s -o ${TGT}'
        if Options.options.wrapper:
            cmd = Options.options.wrapper + ' ' + cmd

        bld(rule = cmd % (Options.options.rate, i, i),
            source = wavegen.link_task.outputs[0],
            target = 'src/%s_data.c' % i,
            name = i)

        bld(features     = 'c cshlib lv2lib',
            source       = bld.path.get_bld().make_node('src/%s_data.c' % i),
            target       = 'lv2/blop.lv2/%s_data' % i,
            includes     = ['.', 'src/include'],
            install_path = '${LV2DIR}/blop.lv2',
            uselib       = ['LV2'])

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