#!/usr/bin/env ruby

Dir.chdir(File.split(File.split(__FILE__)[0])[0])

require 'mkmf'
require 'build/mkmf_support.rb'
require 'build/shell.rb'
require 'pp'
require 'rake/clean.rb'


# run configure if config.rb is not yet present
sh(checkMkmf("$(bindir)/$(ruby_install_name) configure",CONFIG)) unless File.exists?("antconfig.rb")

load 'antconfig.rb'

PKG_VERSION=$CONFIG["version"]
MULTISWIG=false
SWIG_ENABLED=($CONFIG['SWIG'] and $CONFIG['SWIG'].length>0)

$SOURCEDIRS=[
	"ext/external",
	"ext/basic",
	"ext/sound",
	"ext/math",
	"ext/video",
	"ext/gui",
	"ext/3dengine",
	"ext/game",
]

$LIBDEPS={"ext/basic"=>["SDL","RUBY"]}

$BOASOURCES=$SOURCEDIRS.select{|dir|not dir=~/external/}

MYINCLUDES=$SOURCEDIRS.map{|dir|"-I#{dir}"}.join(" ")

def dependencies(c)
end

def build(file)
	type=nil
	compiler=nil
	case file
		when /\.c$/
			type=:c
			compiler=$CONFIG["CC"]
		when /\.c(c|pp)$/
			type=:c
			compiler=$CONFIG["CXX"]
	end
	if type==:c
		if $CONFIG["CCACHE"]
			compiler=$CONFIG["CCACHE"]+" "+compiler
		end

		output=file.sub(/\.c$/,".o").sub(/\.(cc|cpp)$/,".oo")
		Dir.mkdir(".deps") unless File.exists?(".deps")
		dep=".deps/"+output.gsub("/","_")
		cmd=compiler+" "+$CONFIG["CFLAGS"]+" "+$CONFIG["INCLUDEPATH"]+" "+MYINCLUDES+" -Wp,-MD,#{dep} -o "+output+" -c "+File.expand_path(file)
	else
		raise "Unknown source file"
	end	
	sh cmd
	$?
end

def generateSwigDeps(dir)
	output=File.join(".deps",dir.gsub("/","_")+"_swig.cc")
	input=dir+"/interface.i"
	cflags=$CONFIG["INCLUDEPATH"]+" "+$CONFIG["DEFINES"]+" -DAGEXPORT"
	puts ""
	cmd=$CONFIG["SWIG"]+" #{cflags} -ruby -c++ -M #{input} >#{output}"
	sh cmd
	$?
end

def generateSwig(dir)
	output=dir+"/swig.cc"
	input=dir+"/interface.i"
	cflags=$CONFIG["INCLUDEPATH"]+" "+$CONFIG["DEFINES"]+" -DAGEXPORT"
	cmd=$CONFIG["SWIG"]+" #{cflags} -v -Wall -ruby -c++ -o #{output} #{input}"
	puts ""
	pp cmd
	sh cmd
	$?
end

def linkLib(name,objects)
	name=name.to_s
	winadd=""
	if $CONFIG["target_os"]=="windows"
		winadd="-Wl,--enable-auto-image-base -Xlinker --out-implib -Xlinker #{name.gsub(/\.so$/,".dll")}.a"
	end

	cmd=$CONFIG["CXX"]+" -dH -shared -o #{name} -Lext #{winadd} -Wl,-\\( #{$CONFIG["LDFLAGS"]} #{$CONFIG["LIBPATH"]} #{objects.join(" ")}"
	if $CONFIG["CCACHE"]
		cmd=$CONFIG["CCACHE"]+" "+cmd
	end
	puts ""
	#pp cmd
	sh cmd
	$?
end

def makeDepFilename(file)
	File.join(".deps",file.gsub("\\","_").gsub("/","_"))
end

def getDepsFromCache(filename,source)
	depfile=makeDepFilename(filename)
	if File.exists?(depfile)
		file=File.open(depfile)
		content=file.read
		file.close
		content=content.gsub("\\\n"," ").gsub(/^[^:]*:/,"").split(" ").map{|fn|fn.chomp}
		return [source]+(content-[source])
	end
	[source]
end



desc "Managing dependencies for c/++ files"
getDeps=lambda{|args|
	cfile=args.sub(/\.oo$/,".cc").sub(/\.o$/,".c")
	getDepsFromCache(args,cfile)
}

rule '.o' => getDeps do |t|
	source=t.sources[0]
	build(source)
end
rule '.oo' => getDeps do |t|
	source=t.sources[0]
	build(source)
end


def isWindows
	#return true
	$CONFIG["target_os"]=="windows"
end


if MULTISWIG

	libdeps=[]
	$SOURCEDIRS.each{|dir|
		base=dir.split("/")[1]
		lib="ext/libantargis#{base}.so"
	
		# FIXME: check for windows
		if isWindows
			libadd=libdeps.map{|l|"-l#{l.sub(/^.*\/lib(.*)\.so$/,'\1')}"}
		else	
			libadd=libdeps.dup #.map{|l|"-l#{l.sub(/^.*\/(.*)\.so$/,'\1')}"}
		end
	
		libadd+=$CONFIG["LIBS"].split(" ") if libdeps.length==0
		libadd+=["-Lext"]
	
		objs=(Dir[dir+"/*.cc"]+Dir[dir+"/*.c"]).select{|file|not file=~/swig/}.map{|file|file.sub(/\.cc$/,".oo").sub(/\.c$/,".o")}
	
		desc "Build dynamic library #{lib}"
		task lib=>libdeps+objs do |t|
			linkLib(lib,libadd+objs)
		end
		libdeps << lib
	}
	
	
	
	$SOURCEDIRS.each{|dir|
		base=dir.split("/")[1]
		lib="ext/antargis#{base}.so"
	
		objs=[dir+"/swig.oo"]
	
		libdeps=[]
		$SOURCEDIRS.each{|cdir|
			cbase=cdir.split("/")[1]
			libdeps << "ext/libantargis#{cbase}.so"
			break if cdir==dir
		}
	
		libadd=$CONFIG["LIBS"].split(" ")+["-Lext"]
	
		
		desc "Build ruby-extension library #{lib}"
		task lib=>libdeps+objs do |t|
			lib=t
			mlibdeps=t.prerequisites
			mlibdeps=t.prerequisites.map{|l|l.sub(/^.*\/lib(.*)\.so$/,'-l\1')} if isWindows
			linkLib(lib,mlibdeps+libadd)
		end
		libdeps=libdeps+[lib]
	}



	swigDeps=lambda{|t|
		dir=File.join(File.split(t)[0..-2])
	
		
		deps=getDepsFromCache(t,dir+"/interface.i")
		return deps if deps.length>0
	
		# FIXME: del this ???
	
		# FIXME: include correct dependencies
		deps=Dir[dir+"/templates.i"]+Dir[dir+"/*.h"]+[dir+"/interface.i"]
	
		$SOURCEDIRS.each{|ct|
			if ct=~/#{dir}/
				break
			else
				deps << ct+"/interface.i"  unless ct=~/external/
			end
		}
	
		pp "DEPS2:",deps
		deps
	}
	
	$BOASOURCES.each{|dir|
		swig=dir+"/swig.cc"
		myDeps=swigDeps.call(swig)
		#rule 'swig.cc'=>swigDeps do |t|
		task swig=>myDeps do |t|
			dir=File.join(File.split(t.name)[0..-2])
			generateSwigDeps(dir)
			generateSwig(dir)
		end
	}

end
















$BOA_LIBRARIES=$SOURCEDIRS.map{|dir|"ext/libantargis"+dir.split("/")[1]+".so"}+$BOASOURCES.map{|dir|"ext/antargis"+dir.split("/")[1]+".so"}
task :libraries=>$BOA_LIBRARIES do
end

task "ext/antargis.so" => ((Dir["ext/*/*.cc"]+Dir["ext/*/*.c"]).select{|file|not file=~/[a-z]swig/}.map{|file|file.sub(".cc",".oo").sub(".c",".o")}+["ext/swig.oo"]) do |t|
	linkLib(t.name,t.prerequisites+$CONFIG["LIBS"].split(" "))
end


task :library=>"ext/antargis.so" do
end

if SWIG_ENABLED

	
	def importsForInterface(name)
		mdeps=[]
		$SOURCEDIRS.each{|t|
			if name=~/#{t}/
				break
			else
				mdeps << t+"/interface.i" unless t=~/external/
			end
		}
		return mdeps.join(":")
	end
	
	interfaceSrc = lambda { |t|
		dir=File.join(File.split(t)[0..-2])
		Dir[dir+"/*.h"].select{|file|not file=~/swig/}
	}
	
	rule 'interface.i' => interfaceSrc do |t|
		output=t.name.sub(/\/interface.[a-z]*/,"")
		input=importsForInterface(t.name)
		cmd=$CONFIG["RUBY"]+" build/create_interface.rb -d=#{output} -i=#{input}"
		puts ""	
		sh cmd
	end
		
	
	
	mSwigDeps=$SOURCEDIRS[1..-1].map{|dir|dir+"/interface.i"}.sort
	
	# this can be used with a later version of rake - 0.7.1 makes problems with rules and more than one dependency
	mSwigDepLambda=lambda{|t|
		mSwigDeps
	}
	
	task "ext/swig.cc"=>mSwigDeps do
	#rule /^ext\/swig\.cc$/=>mSwigDepLambda do |t|
		#pp t
		output="ext/swig.cc"
		input=$BOASOURCES.map{|dir|File.join(dir,"interface.i")}
		#File.delete(output) if File.exists?(output)
		file=File.open("ext/interface.i","w")
		file.puts '%module(directors="1") antargis'
		input.each{|filename|file.puts "%include \"#{filename}\""}
		file.close
		cflags=$CONFIG["INCLUDEPATH"]+" "+$CONFIG["DEFINES"]+" -DAGEXPORT"
		cmd=$CONFIG["SWIG"]+" #{cflags} -v -Wall -ruby -c++ -o #{output} ext/interface.i"
		puts ""
		sh cmd
		$?
	end
else
	puts
	puts "BEWARE: If you make changes to header-files, the swig-interfacing won't be updated as long as swig is not installed!"
	puts
end

desc "Build all"
task :default=>[:library] do
end


task :allclean=>[:clobber_package,:clean] do
	File.delete("antconfig.rb")
end


CLEAN << Dir["**/*.o"]+Dir["**/*.oo"]+Dir["**/*.so"]+Dir[".deps/*"]+Dir["ext/*.so*"]+Dir["ext/*.dll*"]

if SWIG_ENABLED
	CLEAN << Dir["ext/*/interface.i"]+Dir["ext/*/swig.*"]
end






