#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys, os, platform
import SCons
import SCons.Script
import logging
import fnmatch

from build import util, mixxx, depends

Import('build')

# Grab the created environment from the MixxxBuild
env = build.env

# Check for old build.h file and delete it if it exists
defs = str(SCons.Script.File('#src/build.h'))
if os.path.exists(defs):
    print "Deleting deprecated build file: %s" % defs
    os.remove(defs)

#env.Append(CPPDEFINES=[('BUILD_REV', '"%s"' % getBZRRevision())]) #doing this forces a rebuild of everything whenever a commit happens -- not much fun
## instead, embed BZR version into build
## Put version info into a file, so it doesn't force a rebuild of everything :)
f = open("build.h","w")
try:
    branch_name = util.get_bzr_branch_name()
    modified = util.get_bzr_modified() > 0
    # Do not emit BUILD_BRANCH on release branches.
    if not branch_name.startswith('release'):
        f.write('#define BUILD_BRANCH "%s"\n' % branch_name)
    f.write('#define BUILD_REV "%s%s"\n' % (util.get_bzr_revision(),
                                            '+' if modified else ''))
finally:
    f.close()

#Check for dependencies if we're not doing a clean...
#if not env.GetOption('clean') and not SCons.Util.containsAny(os.sys.argv, ['-h', '--help']):
conf = Configure(env, custom_tests = { 'CheckForPKGConfig' : util.CheckForPKGConfig,
                                       'CheckForPKG' : util.CheckForPKG })

available_features = [depends.MixxxCore]
extra_features = build.get_features()
available_features.extend(extra_features)

# Instantiate the features
available_features = [feature_class() for feature_class in available_features]

visited_dependencies = set()
active_dependencies = []
unmet_dependencies = False

def visit_dependency(dependency_class, build, conf):
        """Recursively configure all dependencies. Skip over dependencies we
        have already setup."""
        global unmet_dependencies

        if dependency_class in visited_dependencies:
                return
        visited_dependencies.add(dependency_class)
        dependency = dependency_class()

        try:
                print "Configuring %s" % dependency.name
                dependency.configure(build, conf)
        except Exception, e:
                logging.error("Unmet dependency: %s" % e)
                unmet_dependencies = True
        active_dependencies.append(dependency)

        for sub_dependency in dependency.depends(build):
                visit_dependency(sub_dependency, build, conf)

for feature in available_features:
        try:
                print "Configuring %s" % feature.name
                feature.configure(build, conf)

                # Only process the feature's dependencies if it's enabled
                if feature.enabled(build):
                        active_dependencies.append(feature)
                        for dependency in feature.depends(build):
                                visit_dependency(dependency, build, conf)
        except Exception, e:
                logging.error("Unmet dependency: %s" % e)
                unmet_dependencies = True

if unmet_dependencies:
        logging.error("Build had unmet dependencies. Exiting.")
        Exit(1)

sources = []

# Query each active dependency for sources they require
for dependency in active_dependencies:
        dep_sources = dependency.sources(build)
        if dep_sources is not None:
                sources.extend(dep_sources)
        #If there's additional env variables that need to be set after the
        #Configure checks have run, then we'll take care of that now.
        dependency.post_dependency_check_configure(build, conf)

env = conf.Finish()

#Tell SCons to build libraries that are bundled with Mixxx
#===================================================

#Parse command-line build flags
build_flags = ""

# Print feature summary
print "\nFeatures Summary:\n================"

for feature in available_features:
        message = "Enabled" if feature.enabled(build) else "Disabled"

        # If the plugin has a status message, show it instead
        if len(feature.status) > 0:
                message = "%s" % feature.status

        print "%035s... %s" % (feature.description(), message)

build_flags = ' '.join(sorted([('%s=%s' % (k,v) if int(v) > 1 else k) for k,v in build.flags.iteritems() if int(v) > 0]))

### Put flags info into a file
f = open("build.h","a")
try:
    f.write('#define BUILD_FLAGS "' + build_flags + '"\n')
finally:
    f.close()

#Set up the MSVC target to build a Visual Studio project/solution file
if 'msvc' in COMMAND_LINE_TARGETS:
    #includes = map(str, Glob('#src/*.h'))
    #Make the project file aware of any command-line arguments that were passed...
    cmdargs = ""
    for k in SCons.Script.ARGUMENTS:
        cmdargs += " " + k + "=" + SCons.Script.ARGUMENTS[k]
    env.Append(MSVSSCONSFLAGS = cmdargs)
    #env.Append(MSVSSCONSFLAGS = ' qtdir=' + build.flags['qtdir'])

    # This is the right way to do it but scons is stupid and doesn't copy flags in... Adam
    # Set up environment for debug target
    # TODO Handle lib versions ie /MDd /Md etc...
    #debugenv = env.Clone()
    #debugenv.Prepend(LINKFLAGS = ['/DEBUG','/PDB:dist' + str(build.bitwidth) + '/mixxx.pdb']) # Generate MS VC Program Debug Database
    #debugenv.Append(CXXFLAGS = '/ZI')

    cppfiles = []
    hfiles = []
    # XXX: Assumes we're in the "src" directory!
    for root, dirs, filenames in os.walk('.'):
        #for exclusion in ['.bzr', '.svn']:
        #    if exclusion in dirs:
        #        dirs.remove(exclusion)
        #print filenames
        for file in filenames:
            #print file
            filepath = os.path.join(root, file)
            if filepath.startswith(".\\"):
                filepath = filepath[2:]

            #print filepath
            if fnmatch.fnmatch(filepath, '*.cpp'):
                cppfiles.append(filepath)
            elif fnmatch.fnmatch(filepath, '*.h'):
                hfiles.append(filepath)

    msvc = env.MSVSProject(target = 'mixxx' + env['MSVSPROJECTSUFFIX'], srcs = cppfiles, incs = hfiles, variant = 'Debug', runfile = '../dist' + str(build.bitwidth) + '/mixxx.exe')
    # Reenable this once bug in scons is fixed...
    #msvc = env.MSVSProject(target = 'mixxx' + env['MSVSPROJECTSUFFIX'], srcs = cppfiles, incs = hfiles, variant = 'Release', runfile = '../dist' + str(build.bitwidth) + '/mixxx.exe')

    env.Alias('msvc', msvc)

# Print the build flags (useful if the flags have been cached, ie. if you just run "scons"
# and want to see the flags that you used last time)
print "================"
print "Building with flags: %s" % build_flags
print "Building with CC: %s" % env['CC']
print "Building with CXX: %s" % env['CXX']
print "Building with CCFLAGS: %s" % env['CCFLAGS']
print "Building with CPPDEFINES: %s" % ' '.join(['-D'+'='.join(pair) if not isinstance(pair, basestring) else '-D'+pair for pair in env['CPPDEFINES']])
print "Building with CXXFLAGS: %s" % env['CXXFLAGS']
print "Building with LINKFLAGS: %s" % env['LINKFLAGS']
print "Building with LIBS: %s" % ' '.join(env['LIBS'])
print "================\n"

Export('sources')
