#                                  emacs: -*- python -*-
# Hydrogen build script
#

# vim: set filetype=python
# kate: syntax python

import urllib
import os
import subprocess
import sys
import glob

def printStatus( value ):
    if str(value) == "1":
	return "enabled"
    else:
	return "disabled"

def recursiveDirs(root) :
	return filter( ( lambda a : a.rfind( ".svn") == -1 ),  [ a[0] for a in os.walk( root ) ] )

def unique( list ) :
	return dict.fromkeys( list ).keys()

def scanFiles(dir, accept=[ "*.cpp" ], reject=[] ) :
	sources = []
	paths = recursiveDirs( dir )
	for path in paths:
		for pattern in accept:
			sources += glob.glob( path + "/" + pattern )
	for pattern in reject:
		sources = filter( ( lambda a : a.rfind( pattern ) == -1 ),  sources )
	return unique( sources )

def subdirsContaining( root, patterns ):
	dirs = unique( map( os.path.dirname, scanFiles( root, patterns ) ) )
	dirs.sort()
	return dirs



def get_platform_flags( opts ):
	includes = []
	cppflags = []
	ldflags = []

	env = Environment( options = opts )

	if sys.platform == "linux2" or sys.platform == "darwin":
		if str(env['debug']) == "1":
			cppflags += ['-Wall',  '-g2', '-ggdb', '-O0'] 
			for flag in env["optflags"].split(" "):
				cppflags.append(flag)
			
		else:
			cppflags += ['-O3', '-fomit-frame-pointer', '-funroll-loops']
			#cppflags += " %s" % get_optimized_flags( target_cpu )
			for flag in env["optflags"].split(" "):
				cppflags.append(flag)


		if str(env['oss']) == "1": cppflags.append('-DOSS_SUPPORT')
		if str(env['alsa']) == "1": cppflags.append('-DALSA_SUPPORT')
		if str(env['jack']) == "1": cppflags.append('-DJACK_SUPPORT')
		if str(env['lash']) == "1": cppflags.append('-DLASH_SUPPORT')
                if str(env['lrdf']) == "1": cppflags.append('-DLRDF_SUPPORT')
		if str(env['portaudio']) == "1": cppflags.append('-DPORTAUDIO_SUPPORT')
		if str(env['portmidi']) == "1": cppflags.append('-DPORTMIDI_SUPPORT')
                if str(env['flac']) == "1": cppflags.append('-DFLAC_SUPPORT')
		
		if sys.platform == "darwin" and str(env['coreaudio']) == "1": cppflags.append('-DCOREAUDIO_SUPPORT')

		cppflags.append('-DLADSPA_SUPPORT')
		


	if str(env['libarchive']) == "1": cppflags.append('-DLIBARCHIVE_SUPPORT')

	includes.append( './' )
	includes.append( 'gui/src/' )
	includes.append( '3rdparty/install/include' )

	if sys.platform == "darwin":
		ldflags.append( '-L/opt/local/lib' )

	if sys.platform == 'linux2':
		ldflags.append('-lasound')

	elif sys.platform == "win32":
		includes.append( '3rdparty\libsndfile-1_0_17' )
		includes.append( 'build\pthreads\include' )
		includes.append( '3rdparty\libarchive\include' )
		includes.append( 'windows\timeFix' )
		includes.append( 'C:\Program Files\GnuWin32\include' )
	else:
		raise Exception( "Platform '%s' not supported" % sys.platform )

	return (includes, cppflags, ldflags)



def download_3rdparty_libs():
	print " * Downloading required 3rdparty libraries"

	curdir = os.path.abspath( os.path.curdir )

	if sys.platform != "win32":
		prefix = os.path.abspath( os.path.curdir ) + "/3rdparty/install"
	else:
		prefix = os.path.abspath( os.path.curdir ) + "\3rdparty\install"


	compile_flags = "--enable-static --disable-shared"


	if not os.path.exists( "3rdparty" ):
		os.mkdir( "3rdparty" )
	


	if not os.path.exists( "3rdparty/install" ):
		os.mkdir( "3rdparty/install" )

	if not os.path.exists( "3rdparty/install/lib" ):
		os.mkdir( "3rdparty/install/lib" )




	if not os.path.exists( "3rdparty/libsndfile.tar.gz" ) and not os.path.exists("3rdparty/libsndfile.zip"):
		if sys.platform != "win32":
			print " * Downloading libsndfile.tar.gz"
			urllib.urlretrieve("http://www.mega-nerd.com/libsndfile/libsndfile-1.0.17.tar.gz", "3rdparty/libsndfile.tar.gz")
		else:
			print " * Downloading libsndfile.zip"
			urllib.urlretrieve("http://www.mega-nerd.com/libsndfile/libsndfile-1_0_17.zip", "3rdparty/libsndfile.zip")


	if sys.platform != "win32":
		#unix commands
		if not os.path.exists( "3rdparty/install/lib/libsndfile.a" ):
			Execute( "cd 3rdparty; tar xzf libsndfile.tar.gz" )
			Execute( "cd 3rdparty/libsndfile-1.0.17; ./configure --disable-flac --prefix=%s %s" % (prefix, compile_flags) )
			res = Execute( "cd 3rdparty/libsndfile-1.0.17; make -j2; make install" )
			if res != 0:
				raise Exception( "Error compiling 3rdparty libraries" )
	else:
		#windows
		if not os.path.exists( "3rdparty\install\lib\libsndfile-1.dll" ):
			Execute( "unzip 3rdparty\libsndfile.zip -d 3rdparty" )
			Execute( "copy 3rdparty\libsndfile-1_0_17\libsndfile-1.dll 3rdparty\install\lib")
			Execute( "copy 3rdparty\libsndfile-1_0_17\sndfile.h 3rdparty\install\lib")




def get_svn_revision():
	
	if sys.platform != "win32":
		p = subprocess.Popen("svnversion -n", shell=True, stdout=subprocess.PIPE)
		return p.stdout.read()
	else:
		return "win32 build"


def get_hydrogen_lib( opts ):
	includes, cppflags, ldflags = get_platform_flags( opts )

	includes.append( "libs/hydrogen/include" )
	
	env = Environment( options = opts ) 


	#location of qt4.py
	qt4ToolLocation="."

	env = Environment(options = opts , tools=['default','qt4'], toolpath=[qt4ToolLocation], ENV=os.environ, CPPPATH = includes, CPPFLAGS = cppflags, CCFLAGS = "", LINKFLAGS=ldflags )
	env.EnableQt4Modules( ['QtCore', 'QtGui'], debug=False)
	env.CacheDir( "scons_cache" )
	

        if str(env['jack']) == "1":
            env.ParseConfig('pkg-config --modversion jack', get_jack_api_flags)
        if str(env['lash']) == "1":
            env.ParseConfig('pkg-config --cflags --libs lash-1.0')


	#env.Decider is not known in older scons version
	try:
		env.Decider( "MD5-timestamp" )
	except AttributeError:
		env.SourceSignatures('MD5')


	src = scanFiles( "libs/hydrogen", ['*.cpp', '*.cc', '*.c' ], [ 'moc_'] )
	src.append( "version.cpp" )

	static_lib = env.StaticLibrary(target = 'hydrogen', source = src )
	return static_lib


def install_images( arg , dir , files):
	#install all image files in a subdirectory
	for file in files:
		if file.endswith(".png"):
			
			if env['prefix'].endswith("/"):
				dname = dir[2:]  
			else:
				dname = dir[1:]  

			env.Alias(target="install", source=env.Install(dir= env['DESTDIR'] + env['prefix'] + '/share/hydrogen/' + dname, source= dir + "/" + file))

def get_hydrogen_gui( lib_hydrogen , opts ):
	includes, cppflags, ldflags = get_platform_flags( opts )

	includes.append( "libs/hydrogen/include" )
	includes.append( "gui/src/UI" )

	#location of qt4.py
	qt4ToolLocation="."

	env = Environment(options = opts , tools=['default','qt4'], toolpath=[qt4ToolLocation], ENV=os.environ, CPPPATH = includes, CPPFLAGS = cppflags, CCFLAGS = "", LINKFLAGS=ldflags )
	
	env.EnableQt4Modules( ['QtCore', 'QtGui','QtNetwork','QtXml'], debug=False)
	#
	env.CacheDir( "scons_cache" )
	
	#env.Decider is not known in older scons version
	try:
		env.Decider( "MD5-timestamp" )
	except AttributeError:
		env.SourceSignatures('MD5')

	# rcc needs a -name flag because examples use identified resource files
	def takebasename(file):
		return os.path.splitext(os.path.basename(file))[0]


	directory = "gui"

	resources = [ env.Qrc( qrc, QT4_QRCFLAGS = '-name ' + takebasename( qrc ) ) for qrc in scanFiles(directory, ['*.qrc'] ) ]
	interfaces = [ env.Uic4( uic ) for uic in scanFiles(directory, ['*.ui'] ) ]


	src = scanFiles( directory, ['*.cpp', '*.cc', '*.c' ], [ 'moc_'] )

	env.Append( LIBS = lib_hydrogen )
	
	if sys.platform != "win32":
		env.Append( LIBS = ["sndfile"] )
	else:
		env.Append( LIBS = ["sndfile-1"] )
		env.Append( LIBPATH = '3rdparty\libsndfile-1_0_17' )
		env.Append( LIBPATH = 'C:\Program Files\GnuWin32\lib' )
		env.Append( LIBS = [ "pthread" ] )
	
	if str(env['lrdf']) == "1": env.Append( LIBS = ["lrdf"] )
	if str(env['flac']) == "1": env.Append( LIBS = ["FLAC","FLAC++"] )
	if str(env['jack']) == "1": env.Append( LIBS = ["jack"])
	if str(env['alsa']) == "1": env.Append( LIBS = ["asound"])
	if str(env['libarchive']) == "1": env.Append( LIBS = ["archive"])
	else: env.Append( LIBS = ["tar"])
	if str(env['portaudio']) == "1": env.Append( LIBS = [ "portaudio" ] )
	if str(env['portmidi']) == "1":
		env.Append( LIBS = [ "portmidi" ] )
		env.Append( LIBS = [ "porttime" ] )
	if str(env['lash']) == "1":
	        env.ParseConfig('pkg-config --cflags --libs lash-1.0')

	if sys.platform == "darwin":
		env.Append( LIBS = ["z"] )

	if sys.platform == "darwin" and str(env['coreaudio']) == "1":
		env.Append( LINKFLAGS = ['-framework','ApplicationServices'])
		env.Append( LINKFLAGS = ['-framework','AudioUnit'])
		env.Append( LINKFLAGS = ['-framework','Coreaudio'])



	app = env.Program(target = 'hydrogen', source = src )

	env.Alias('programs', app)
	env.Default('programs')

        for N in glob.glob('./data/i18n/hydrogen.*'):
            env.Alias(target="install", source=env.Install(dir= env['DESTDIR'] + env['prefix'] + '/share/hydrogen/data/i18n', source=N))
	env.Alias(target="install", source=env.Install(dir= env['DESTDIR'] + env['prefix'] + '/share/hydrogen/data', source="./data/img"))

	#add every img in ./data/img to the install list. 
	os.path.walk("./data/img/",install_images,env) 


	env.Alias(target="install", source=env.Install(dir= env['DESTDIR'] + env['prefix'] + '/share/hydrogen/data', source="./data/drumkits"))
	env.Alias(target="install", source=env.Install(dir= env['DESTDIR'] + env['prefix'] + '/share/hydrogen/data', source="./data/demo_songs"))
	env.Alias(target="install", source=env.Install(dir= env['DESTDIR'] + env['prefix'] + '/share/hydrogen/data', source="./data/hydrogen.default.conf"))
	env.Alias(target="install", source=env.Install(dir= env['DESTDIR'] + env['prefix'] + '/share/hydrogen/data', source="./data/emptySample.wav"))
	env.Alias(target="install", source=env.Install(dir= env['DESTDIR'] + env['prefix'] + '/share/hydrogen/data', source="./data/click.wav"))
	env.Alias(target="install", source=env.Install(dir= env['DESTDIR'] + env['prefix'] + '/share/hydrogen/data', source="./data/doc"))
	env.Alias(target="install", source=env.Install(dir= env['DESTDIR'] + env['prefix'] + '/share/hydrogen/data', source="./data/DefaultSong.h2song"))
	env.Alias(target="install", source=env.Install(dir= env['DESTDIR'] + env['prefix'] + '/bin/', source="./hydrogen"))
	env.Alias(target="install", source=env.Install(dir= env['DESTDIR'] + env['prefix'] + '/share/applications', source="./hydrogen.desktop"))
	env.Alias(target="install", source=env.Install(dir= env['DESTDIR'] + env['prefix'] + '/share/pixmaps', source="./data/img/gray/h2-icon.svg"))


	return app

def get_jack_api_flags(xenv, pkg_ver):
    (major, minor, patch) = pkg_ver.rstrip().split('.')
    major = int(major)
    minor = int(minor)
    patch = int(patch)
    rv = ""
    if (major == 0) and (minor < 102):
        rv = "-DJACK_NO_BBT_OFFSET"
    if (major == 0) and (minor == 102) and (patch < 4):
        rv = "-DJACK_NO_BBT_OFFSET"
    xenv.MergeFlags(rv)

opts = Options('scache.conf')

#platform independent settings
opts.Add('debug', 'Set to 1 to build with debug informations', 0)
opts.Add('libarchive', 'Set to 1 to enable libarchive instead of libtar', 0)
opts.Add('prefix','Default: /usr/local',"/usr/local")
opts.Add('DESTDIR','Default: none',"")
opts.Add('optflags','Default: none',"")

#platform dependent settings
if sys.platform == "darwin":
	opts.Add('coreaudio', 'Set to 1 to enable Coreaudio',1)

if sys.platform != "win32":
	opts.Add('oss', 'Set to 1 to enable oss',1)

	opts.Add('portmidi', 'Set to 1 to enable portmidi',0)
	
	opts.Add('portaudio', 'Set to 1 to enable portaudio',0)
	
	opts.Add('lash', 'Set to 1 to enable lash',0)
	
	opts.Add('alsa', 'Set to 1 to enable alsa',1)
	
	opts.Add('jack', 'Set to 1 to enable jack',1)	
	
	opts.Add('lrdf', 'Set to 1 to enable lrdf',1)
	
	opts.Add('flac', 'Set to 1 to enable flac',1)
else:
	#alsa, lash,oss and jack are not available on windows
	opts.Add('portmidi', 'Set to 1 to enable portmidi',1)
	
	opts.Add('portaudio', 'Set to 1 to enable portaudio',1)
	
	opts.Add('oss', 'Set to 1 to enable oss',0)

	opts.Add('lash', 'Set to 1 to enable lash',0)
	
	opts.Add('alsa', 'Set to 1 to enable alsa',0)
	
	opts.Add('jack', 'Set to 1 to enable jack',0)
	
	opts.Add('lrdf', 'Set to 1 to enable lrdf',0)
	
	opts.Add('flac', 'Set to 1 to enable flac',0)



#get includes ( important if you compile on non-standard envorionments)

includes, a , b = get_platform_flags( opts )

env = Environment(options = opts, CPPPATH = includes)


Help(opts.GenerateHelpText(env))


platform = sys.platform

#just download 3rd party libs if we're *not* running linux.
#We trust in our package managment system!
if platform == "win32":
    download_3rdparty_libs()



#Check if all required libraries are installed
def CheckPKG(context, name):
    context.Message( 'Checking for %s... ' % name )
    ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0]
    context.Result( ret )
    return ret

conf = Configure(env, custom_tests = { 'CheckPKG' : CheckPKG })
if not conf.CheckCHeader('sndfile.h'):
    print 'libsndfile must be installed!'
    Exit(1)



# it seems that conf.CheckCHeader  dislikes like the "++" in filenames
#if not conf.CheckCHeader('FLAC++/all.h'):
#   print 'FLAC++ must be installed!'
#   Exit(1)


# these libraries are optional (can be enabled/disabled, see 'scons -h')

if str(env['portaudio']) == "1" and not conf.CheckCHeader('portaudio.h'):
    print "portaudio must be installed!"
    Exit(1)

if str(env['portmidi']) == "1" and not conf.CheckCHeader('portmidi.h'):
    print "portmidi must be installed!"
    Exit(1)


#alsa: (default: enabled)
if str(env['alsa']) == "1" and not conf.CheckCHeader('alsa/asoundlib.h'):
    print 'alsa must be installed!'
    Exit(1)

#jack: (default: enabled)
if str(env['jack']) == "1" and not conf.CheckCHeader('jack/jack.h'):
    print 'jack must be installed!'
    Exit(1)

#lash: (default: disabled)
if str(env['lash']) == "1" and not conf.CheckPKG('lash-1.0 >= 0.5.0'):
    print 'liblash must be installed!'
    Exit(1)

#libarchive: (default: disabled)
if str(env['libarchive']) == "1" and not conf.CheckCHeader("archive.h"):
    print 'libarchive must be installed!'
    Exit(1)
#libtar: needed if not libarchive
elif not str(env['libarchive']) == "1" and not conf.CheckCHeader("zlib.h"):
   print 'zlib devel package must be installed!'
   Exit(1)
elif not str(env['libarchive']) == "1" and not conf.CheckCHeader("libtar.h"):
   print 'libtar must be installed!'
   Exit(1)

#lrdf: categorizing of ladspa effects
if str(env['lrdf']) == "1" and not conf.CheckCHeader('lrdf.h'):
    print 'lrdf must be installed!'
    Exit(1)

#flac: support for flac samples
if str(env['flac']) == "1" and not conf.CheckCHeader('FLAC/all.h'):
    print 'FLAC must be installed!'
    Exit(1)


print ""
print "================================================================="
print " Hydrogen build script"
print ""
print " Revision: %s" % get_svn_revision()
print " Platform: %s" % platform

if str(env['debug']) == "1" :
	print " Debug build"
else:
	print " Release build"

print " Prefix: " + env['prefix']
print " Destdir: " + env['DESTDIR']
print "================================================================="
print "Feature Overview:\n"


print "      lash: " + printStatus( env["lash"] )
print "      oss: " + printStatus( env["oss"] )
print "      alsa: " + printStatus( env["alsa"] )
print "      jack: " + printStatus( env["jack"] )
print "libarchive: " + printStatus( env["libarchive"] ) 
print " portaudio: " + printStatus( env["portaudio"] )
print "  portmidi: " + printStatus( env["portmidi"] ) 
if sys.platform == "darwin":
	print " coreaudio: " + printStatus( env["coreaudio"] )

print "\n================================================================="
print ""

# write the config.h file
conf = open("config.h", "w")

conf.write( "#ifndef HYD_CONFIG_H\n" )
conf.write( "#define HYD_CONFIG_H\n" )
conf.write( "#include <string>\n" )


if str(env['debug']) == "1": conf.write( "#define CONFIG_DEBUG\n" )
if str(env['lash']) == "1": conf.write( "#define LASH\n" )

conf.write( "#ifndef QT_BEGIN_NAMESPACE\n" )
conf.write( "#    define QT_BEGIN_NAMESPACE\n" )
conf.write( "#endif\n" )
conf.write( "#ifndef QT_END_NAMESPACE\n" )
conf.write( "#    define QT_END_NAMESPACE\n" )
conf.write( "#endif\n" )

conf.write( "#define CONFIG_PREFIX \"%s\"\n" % env['prefix'] )
conf.write( "#define DATA_PATH \"%s/share/hydrogen/data\"\n" % env['prefix'] )

conf.write( "#endif\n" )

conf.close()

version = open("version.cpp", "w")
version.write( "// autogenerated by Sconstruct script\n" )
version.write( '#include "version.h"\n' )
version.write( '#include "config.h"\n' )
version.write( "static const std::string extra_version = \"svn%s\";\n" % get_svn_revision() )

#just for non-stable releases
#version.write( "static const std::string VERSION = \"0.9.4-\" + extra_version;\n" )

version.write( "static const std::string VERSION = \"0.9.4\";\n" )
version.write( "std::string get_version() { return VERSION;	}\n" )
version.close()


libhyd = get_hydrogen_lib( opts )
app = get_hydrogen_gui( libhyd , opts )

opts.Save("scache.conf",env)
