#!/usr/bin/python

version = '0.17'

import platform
from optparse import OptionParser
parser = OptionParser(version="diskscan configure " + version, usage='Usage: %prog [options]')
parser.add_option('-d', '--dev', dest='dev', help='Add developer options', action="store_true", default=False)
(options, args) = parser.parse_args()

lib_srcs = [
        'lib/data.c', 'lib/diskscan.c', 'lib/sha1.c', 'lib/system_id.c', 'lib/verbose.c', 'lib/disk.c',
        'hdrhistogram/src/hdr_histogram.c', 'hdrhistogram/src/hdr_histogram_log.c',
        'hdrhistogram/src/hdr_encoding.c',
]

arch_freebsd = {'src': 'arch/arch-freebsd.c', 'h': 'arch/arch-posix.h'}

arch_srcs = {
        'FreeBSD': arch_freebsd,
        'GNU/kFreeBSD': arch_freebsd,
        'Linux': {'src': 'arch/arch-linux.c', 'h': 'arch/arch-linux.h'},
        '': {'src': 'arch/arch-generic.c', 'h': 'arch/arch-posix.h'},
}[platform.system()]

lib_srcs.append(arch_srcs['src'])

cli_srcs = [
        'cli/cli.c', 'cli/verbose.c', 'progressbar/lib/progressbar.c',
]

executables = {
        'diskscan': cli_srcs,
}

cflags = ['-I.', '-Iinclude', '-Ilibscsicmd/include', '-Iprogressbar/include', '-g', '-O3', '-Wall', '-Wextra', '-Wshadow',
          '-Wmissing-prototypes', '-Winit-self', '-pipe', '-D_GNU_SOURCE',
          '-D_FORTIFY_SOURCE=2', '-DVERSION="%s"' % version]
ldflags = ['-ltermcap', '-lm', '-lz']

if options.dev:
    cflags.append('-Werror')

import os, os.path
import glob
import sys

sys.path.append('libscsicmd/build')
import ninja_syntax


class Platform:
    def __init__(self, cflags, ldflags):
        self.cflags = cflags
        self.ldflags = ldflags

    def fmt(self, args):
        return ' '.join(args)

    def cflags_fmt(self):
        return self.fmt(self.cflags)
    def ldflags_fmt(self):
        return self.fmt(self.ldflags)

    def build_it(self, src, ldflags='', cflags=''):
        filename = '/tmp/tmp_4sadasd.c'
        outfilename = '/tmp/tmp_4sasdasd'
        f = open(filename, 'w')
        f.write(src)
        f.close()
        rc = os.system('gcc -o %s %s %s %s >/dev/null 2>&1' % (outfilename, filename, self.cflags_fmt() + ' ' + cflags, self.ldflags_fmt() + ' ' + ldflags))
        os.unlink(filename)
        if os.access(outfilename, os.F_OK): os.unlink(outfilename)
        return rc == 0

    def check_clock_gettime(self):
        src = '#include <time.h>\nint main() { struct timespec t; return clock_gettime(CLOCK_MONOTONIC, &t); }\n'
        print('Trying to check for librt')
        if not self.build_it(src):
            print('Failed to build without librt')
            if self.build_it(src, ldflags='-lrt'):
                self.ldflags.append('-lrt')
                print('Adding librt for clock_gettime')
            else:
                print('librt didnt help')

platform = Platform(cflags, ldflags)
platform.check_clock_gettime()
cflags = platform.cflags
ldflags = platform.ldflags

print('cflags: %s' % ' '.join(cflags))
print('ldflags: %s' % ' '.join(ldflags))

n = ninja_syntax.Writer(open('build.ninja', 'w'))
n.comment('Auto generated by ./configure, edit the configure script instead')
n.newline()

env_keys = set(['CC', 'AR', 'CFLAGS', 'LDFLAGS'])
configure_env = dict((k, os.environ[k]) for k in os.environ if k in env_keys)
if configure_env:
    config_str = ' '.join([k+'='+configure_env[k] for k in configure_env])
    n.variable('configure_env', config_str+'$ ')
n.newline()

CC = configure_env.get('CC', 'gcc')
n.variable('cc', CC)
AR = configure_env.get('AR', 'ar')
n.variable('ar', AR)
n.newline()

def shell_escape(str):
        """Escape str such that it's interpreted as a single argument by
           the shell."""

        # This isn't complete, but it's just enough to make NINJA_PYTHON work.
        if '"' in str:
                return "'%s'" % str.replace("'", "\\'")
        return str

if 'CFLAGS' in configure_env:
    cflags.append(configure_env['CFLAGS'])
n.variable('cflags', ' '.join(shell_escape(flag) for flag in cflags))

if 'LDFLAGS' in configure_env:
    ldflags.append(configure_env['LDFLAGS'])
n.variable('ldflags', ' '.join(shell_escape(flag) for flag in ldflags))

n.newline()

n.rule('c',
        command='$cc -MMD -MT $out -MF $out.d $cflags $extracflags -c $in -o $out',
        depfile='$out.d',
        deps='gcc',
        description='CC $out'
)
n.newline()

n.rule('ar',
        command='rm -f $out && $ar crs $out $in',
        description='AR $out',
)
n.newline()

n.rule('link',
        command='$cc -o $out $in $libs $ldflags',
        description='LINK $out'
)
n.newline()

n.rule('symlink',
        command='ln -sf ../$in $out',
        description='SYMLINK $out -> $in')
n.newline()

n.rule('configure',
        command='${configure_env} ./configure $arg',
        description='CONFIGURE build.ninja',
        generator=True
        )
n.newline()

gen_files = []
gen_files += n.build('include/arch-internal.h', 'symlink', arch_srcs['h'])
gen_files.append('libscsicmd/include/ata_parse.h')

def src(filename):
        return os.path.join('src', filename)
def built(filename):
        return os.path.join('built', filename)
def cc(filename, **kwargs):
        return n.build(built(filename)[:-2] + '.o', 'c', filename, implicit=gen_files, **kwargs)

all_targets = []
libs = []

# Build libscsicmd
n.variable('libscsicmd_prefix', 'libscsicmd')
os.system('cd libscsicmd && ./configure')
n.subninja('$libscsicmd_prefix/lib.ninja')

# Build libdiskscan
lib_objs = []
for source in lib_srcs:
        lib_objs += cc(source)
lib = n.build('libdiskscan.a', 'ar', lib_objs)
libs += lib
n.newline()

libs.append('libscsicmd.a')

# Build diskscan executables (cli, tui, gui)
exec_bins = []
for exec_name in executables.keys():
        objs = []
        srcs = executables[exec_name]
        for source in srcs + ['diskscan.c']:
                objs += cc(source)
        all_targets += n.build(exec_name, 'link', objs, implicit=libs, variables=[('libs', libs)])
n.newline()

all_targets += n.build('build.ninja', 'configure', implicit=['./configure'])

n.rule('tags',
        command='ctags $in',
        description='CTAGS $out'
        )
all_targets += n.build('tags', 'tags', lib_srcs + glob.glob('include/*.h'))
n.newline()

# Build manpage
all_targets += n.build('Documentation/diskscan.1', 'script', 'Documentation/diskscan.1.in', variables=[('script', 'sed -e "s/@PACKAGE_VERSION@/%s/"' % version)])

n.build('all', 'phony', all_targets)
n.default('all')

print('Configure done')
