# Copyright AllSeen Alliance. All rights reserved.
#
#    Permission to use, copy, modify, and/or distribute this software for any
#    purpose with or without fee is hereby granted, provided that the above
#    copyright notice and this permission notice appear in all copies.
#
#    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
#    WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
#    MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
#    ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
#    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
#    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
#    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
# 

import os
Import('env')
from os.path import basename

# Bullseye code coverage for 'debug' builds.
if env['VARIANT'] == 'debug':
    if not env.has_key('BULLSEYE_BIN'):
        print 'BULLSEYE_BIN not specified'
    else:
        env.PrependENVPath('PATH', env.get('BULLSEYE_BIN'))
        if not os.environ.has_key('COVFILE'):
            print 'Error: COVFILE environment variable must be set'
            if not GetOption('help'):
                Exit(1)
        else:
            env.PrependENVPath('COVFILE', os.environ['COVFILE'])

# Make alljoyn C++ dist a sub-directory of the alljoyn dist.
env['OBJDIR_COMMON'] = env['OBJDIR'] + '/common'

# All AllJoyn subprojects have access to common so add the include path to the global environment
env.Append(CPPPATH = [env.Dir('inc')])

# Platform specifics for common
if env['OS_GROUP'] == 'windows':
    vars = Variables()
    vars.Add(PathVariable('OPENSSL_BASE', 'Base OpenSSL directory (windows only)', os.environ.get('OPENSSL_BASE')))
    vars.Update(env)
    Help(vars.GenerateHelpText(env))
    env.AppendUnique(LIBS = ['setupapi', 'user32', 'winmm', 'ws2_32', 'iphlpapi', 'secur32', 'Advapi32'])

    if env['CRYPTO'] == 'cng':
        if env['OS'] == 'winxp':
            print 'Must specify CRYPTO=openssl and OPENSSL_BASE when building for WindowsXP'
            if not GetOption('help'):
                Exit(1)
        else:
            env.AppendUnique(LIBS = ['bcrypt', 'ncrypt', 'crypt32'])
            env.Append(CPPDEFINES=['CRYPTO_CNG'])
            print 'Using CNG crypto libraries'
    else:
        env.Append(CPPPATH = ['$OPENSSL_BASE/include'])
        env.Append(LIBPATH = ['$OPENSSL_BASE/lib'])
        env.AppendUnique(LIBS = ['libeay32'])
        print 'Using OpenSSL crypto libraries'

elif env['OS'] in ['linux', 'openwrt']:
    env.AppendUnique(LIBS =['rt', 'stdc++', 'pthread', 'm'])
    if env['CRYPTO'] == 'openssl':
        env.AppendUnique(LIBS =['crypto', 'ssl'])
        print 'Using OpenSSL crypto'
    else:
        print 'Using builtin crypto'

elif env['OS'] == 'darwin':
    env.Append(CPPDEFINES=['MECHANISM_PIPE'])
    env.AppendUnique(LIBS =['stdc++', 'pthread'])
    if env['CRYPTO'] == 'openssl':
        env.AppendUnique(LIBS =['crypto', 'ssl'])
        if env['CPU'] in ['arm', 'armv7', 'armv7s', 'arm64']:
            vars = Variables()
            vars.Add(PathVariable('OPENSSL_ROOT', 'Base OpenSSL directory (darwin only)', os.environ.get('OPENSSL_ROOT')))
            vars.Update(env)
            Help(vars.GenerateHelpText(env))
            if '' == env.subst('$OPENSSL_ROOT'):
                # Must specify OPENSSL_ROOT for darwin, arm
                print 'Must specify OPENSSL_ROOT when building for OS=darwin, CPU=arm'
                if not GetOption('help'):
                    Exit(1)
            env.Append(CPPPATH = ['$OPENSSL_ROOT/include'])
            env.Append(LIBPATH = ['$OPENSSL_ROOT/build/' + os.environ.get('CONFIGURATION') + '-' + os.environ.get('PLATFORM_NAME')])
        print 'Using OpenSSL crypto'
    else:
        print 'Using builtin crypto'

elif env['OS'] == 'android':
    env.AppendUnique(LIBS = ['m', 'c', 'stdc++', 'log', 'gcc', '$ANDROID_STL'])
    if env['CRYPTO'] == 'openssl':
        env.AppendUnique(LIBS =['crypto'])
        print 'Using OpenSSL crypto'
    else:
        print 'Using builtin crypto'

commonenv = env.Clone()

# Variant settings
commonenv.VariantDir('$OBJDIR_COMMON', 'src', duplicate = 0)
commonenv.VariantDir('$OBJDIR_COMMON/os', 'os/${OS_GROUP}', duplicate = 0)
commonenv.VariantDir('$OBJDIR_COMMON/crypto', 'crypto/${CRYPTO}', duplicate = 0)
# If we're using CNG, use the CNG ECC provider code. Anything else, use the generic provider.
if env['CRYPTO'] == 'cng':
    commonenv.VariantDir('$OBJDIR_COMMON/crypto/ECC', 'crypto/ECC/cng', duplicate = 0)
else:
    commonenv.VariantDir('$OBJDIR_COMMON/crypto/ECC', 'crypto/ECC/generic', duplicate = 0)

commonenv.Append(CPPPATH = ['crypto'])

# Setup dependent include directories
hdrs = { 'qcc': commonenv.File(['inc/qcc/Log.h',
                                'inc/qcc/Debug.h',
                                'inc/qcc/ManagedObj.h',
                                'inc/qcc/Mutex.h',
                                'inc/qcc/String.h',
                                'inc/qcc/StringUtil.h',
                                'inc/qcc/atomic.h',
                                'inc/qcc/CryptoECC.h',
                                'inc/qcc/CertificateECC.h',
                                'inc/qcc/platform.h']),
         'qcc/${OS_GROUP}': commonenv.File(['inc/qcc/${OS_GROUP}/atomic.h',
                                            'inc/qcc/${OS_GROUP}/platform_types.h',
                                            'inc/qcc/${OS_GROUP}/Mutex.h']) }

if commonenv['OS_GROUP'] == 'windows':
    hdrs['qcc/${OS_GROUP}'] += commonenv.File(['inc/qcc/${OS_GROUP}/mapping.h'])


# under normal build conditions the Status.xml found in alljoyn_core is used to
# build Status.h and Status.cc.  If we are building the code in common independent
# of the alljoyn_core we will have to create Status.h and Status.cc for common.
status_obj = [];
if commonenv.has_key('BUILD_COMMON_STATUS'):
    status_src, status_hdr = commonenv.Status('$OBJDIR_COMMON/Status')
    status_obj = commonenv.Object(status_src)
    commonenv.Append(CPPPATH = ['#' + os.path.dirname(str(status_hdr))])
else:
    # allow common to "#include <alljoyn/Status.h>" when building all of AllJoyn
    commonenv.Append(CPPPATH = ['$DISTDIR/cpp/inc'])

if commonenv['CRYPTO'] == 'builtin':
    commonenv.Append(CPPPATH = [env.Dir('../external/sha2'), env.Dir('../external/sha1')])

# Build the sources
status_src = ['Status.cc']


srcs = commonenv.Glob('$OBJDIR_COMMON/*.cc') + commonenv.Glob('$OBJDIR_COMMON/os/*.cc') + commonenv.Glob('$OBJDIR_COMMON/crypto/*.cc') + commonenv.Glob('$OBJDIR_COMMON/crypto/ECC/*.cc')

# Make sure Status never gets included from common for contained projects
srcs = [ f for f in srcs if basename(str(f)) not in status_src ]

static_objs = commonenv.Object(srcs)

if commonenv['LIBTYPE'] != 'static':
    shared_objs = commonenv.SharedObject(srcs)
else:
    shared_objs = []


libcommon = commonenv.StaticLibrary('$OBJDIR_COMMON/common_static', [static_objs, status_obj])

# Build unit Tests
commonenv.SConscript('unit_test/SConscript', variant_dir='$OBJDIR_COMMON/unittest', duplicate=0, exports=['commonenv', 'libcommon'])

ret = (hdrs, static_objs, shared_objs)

Return('ret')
