CSC ?= gmcs ;
NCC ?= ncc.exe ;
LOCATE_TARGETS ?= $(TOP) ;
CSFLAGS ?= -debug ;

rule AntLR {
    local sources = [ SearchSource $(>) ] ;
    local target = $(<:G=antlr) ;
    
    MakeLocate $(target) : $(SUBDIR) ;
    antlr $(target) : $(sources) ;
    Depends $(target) : $(sources) ;
    Clean clean : $(target) ;
    OUTDIR on $(target) = $(<:D) ;

    return $(target) ;
}

actions antlr {
    rm -f $(<) ;
    CLASSPATH=tools/antlr/antlr.jar:$CLASSPATH java antlr.Tool -o $(OUTDIR) $(>)
}

rule SearchSource {
    local sources ;
    for s in $(<) {
        if $(s:G) {
            sources += $(s) ;
        } else {
            local source = $(s:G=$(SOURCE_GRIST:E)) ;
            sources += $(source) ;
            SEARCH on $(source) = $(SEARCH_SOURCE) ;
        }
    }
    return $(sources) ;
}

# CSharp target : sources : resources
rule CSharp {
    local sources = [ SearchSource $(>) ] ;
    local resources = [ SearchSource $(3) ] ;
    local target = $(<) ;
    
    MakeLocate $(target) : $(SUBDIR) ;
    MonoCSharp $(target) : $(sources) ;
    CSFLAGS on $(target) = $(CSFLAGS) ;
    RESOURCES on $(target) = $(resources) ;
    if $(target:S) = .dll {
        TARGET on $(target) = library ;
    } else if $(<:S) = .exe {
        TARGET on $(target) = exe ;
    }
    Depends $(target) : $(sources) $(resources) ;
    Depends all : $(target) ;

    Clean clean : $(target) ;
    Clean clean$(<) : $(target) ;
}

# Nemerle target : sources : resources
rule Nemerle {
    local sources = [ SearchSource $(>) ] ;
    local resources = [ SearchSource $(3) ] ;
    local target = $(<) ;

    MakeLocate $(target) : $(SUBDIR) ;
    Ncc $(target) : $(sources) ;
    if $(target:S) = .dll {
        TARGET on $(target) = library ;
    } else if $(<:S) = .exe {
        TARGET on $(target) = exe ;
    }                                      
    NFLAGS on $(target) = $(NFLAGS) ;
    RESOURCES on $(target) = $(resources) ;
    Depends $(target) : $(sources) ;
    Depends $(target) : $(resources) ;
    Depends all : $(target) ;

    Clean clean : $(target) ;
    Clean clean$(<) : $(target) ;
}

rule LinkWith {
    LIBS on $(<) += $(>) ;
    Depends $(<) : $(>) ;
}

actions MonoCSharp bind RESOURCES {
    $(CSC) $(CSFLAGS) -out:$(<) -target:$(TARGET) -r:$(LIBS) -resource:$(RESOURCES) $(>)
}

actions Ncc bind RESOURCES {
    $(NCC) $(NFLAGS) -out:$(<) -target:$(TARGET) -r:$(LIBS) -resource:$(RESOURCES),$(RESOURCES:BS) $(>)
}

##  ConcatDirs dirs
##    Concatenates a set of directories. This is a substitute for FDirName in
##    Jambase. It works also correctly for several rooted paths, where FDirName
##    fails.
##    The advantage over $(dir1)/$(dir2) is that this also works correctly if
##    $(dir1) or $(dir2) is not set.
rule ConcatDirs
{
  local i ;
  local result = $(<[1]) ;
  if ! $(result) { $result = "" ; }
  local dir1 dir2 ;

  for i in $(<[2-])
  {
    # eleminate multiple slashes because jam is somewhat buggy here
    dir1 = [ MATCH (.*[^/]?) : $(result) ] ;
    dir2 = [ MATCH ([^/].*) : $(i) ] ;
    if ! $(dir1) { dir1 = "" ; }
    if $(dir1) != "" { dir1 = $(dir1)/ ; }
    if ! $(dir2) { dir2 = "" ; }
    result = $(dir1)$(dir2) ;
  }

  return $(result) ;
}

##  Wildcard [ dir : ] patterns
##    Create a list of files in a directory which match the pattern. You can
##    optionally specify a subdirectory. The files will be returned with
##    stripped pathnames. The difference from GLOB is that this rule respects
##    subdirectories which may have been entered with the SubDir rule.
rule Wildcard
{
  local files dir sdir wildcards ;

  # Is a directory given?
  if $(>) {
    dir = $(<)/ ;
    sdir = $(<) ;
    wildcards = $(>) ;
  } else {
    dir = "" ;
    sdir = "" ;
    wildcards = $(<) ;
  }

  files = [ GLOB [ ConcatDirs $(SUBDIR) $(dir) ] : $(wildcards) ] ;

  return $(files:BSR=$(sdir)) ;
}

# fix bug in Jambase where SubInclude in the middle of a jam file made it break
rule SubInclude
{
    if ! $($(<[1]))
    {
        Exit SubInclude $(<[1]) without prior SubDir $(<[1]) ;
    }

    local save_SUBDIR_TOKENS = $(SUBDIR_TOKENS) ;

    SubDir $(<) ;

    include $(JAMFILE:D=$(SUBDIR)) ;

    SubDir $(<[1]) $(save_SUBDIR_TOKENS) ;
}

SUBDIRRULES += FixSubDirPath ;

rule FixSubDirPath
{
    LOCATE_SOURCE = [ ConcatDirs $(LOCATE_OBJECTS) $(SUBDIR_TOKENS) ] ;
    LOCATE_TARGET = [ ConcatDirs $(LOCATE_OBJECTS) $(SUBDIR_TOKENS) ] ;
}

##  IsElem element : list
##    Returns "true" if the elemnt is in the list. Otherwise nothing is
##    returned.
rule IsElem
{
  local i ;

  for i in $(>)
  {
    if $(i) = $(<)
    {
      return "true" ;
    }
  }

  return ;
}

##  Filter list : filter
##    Returns the list without the words contained in filter.
rule Filter
{
  local i result ;

  for i in $(<)
  {
    if ! [ IsElem $(i) : $(>) ]
    {
      result += $(i) ;
    }
  }

  return $(result) ;
}

