# Copyright (c) 2010 Vladimir Prus.
#
# Use, modification and distribution is subject to the Boost Software
# License Version 1.0. (See accompanying file LICENSE_1_0.txt or
# http://www.boost.org/LICENSE_1_0.txt)

import property-set ;
import path ;
import modules ;
import "class" ; 
import errors ;
import configure ;

rule find-include-path ( variable : properties : header 
    : provided-path ? )
{
    # FIXME: document which properties affect this function by
    # default.
    local target-os = [ $(properties).get <target-os> ] ;
    properties = [ property-set.create <target-os>$(toolset) ] ;    
    if $($(variable)-$(properties))
    {
        return $($(variable)-$(properties)) ;
    }
    else
    {
        provided-path ?= [ modules.peek : $(variable) ] ;
        includes = $(provided-path) ;
        includes += [ $(properties).get <include> ] ;
        if [ $(properties).get <target-os> ] != windows
        {
            # FIXME: use sysroot
            includes += /usr/include ;
        }
        
        local result ;
        while ! $(result) && $(includes)
        {            
            local f = [ path.root $(header) $(includes[1]) ] ;
            ECHO "Checking " $(f) ;
            if [ path.exists $(f) ]
            {
                result = $(includes[1]) ;
            }
            else if $(provided-path)
            {
                errors.user-error "Could not find header" $(header)
                  : "in the user-specified directory" $(provided-path) ;
            }            
            includes = $(includes[2-]) ;                
        }        
        $(variable)-$(properties) = $(result) ;
        return $(result) ;
    }        
}

rule find-library ( variable : properties : names + : provided-path ? )
{
    local target-os = [ $(properties).get <target-os> ] ;
    properties = [ property-set.create <target-os>$(toolset) ] ;
    if $($(variable)-$(properties))
    {
        return $($(variable)-$(properties)) ;
    }
    else
    {
        provided-path ?= [ modules.peek : $(variable) ] ;
        paths = $(provided-path) ;
        paths += [ $(properties).get <library-path> ] ;
        if [ $(properties).get <target-os> ] != windows
        {
            paths += /usr/lib /usr/lib32 /usr/lib64 ;
        }
        
        local result ;               
        while ! $(result) && $(paths)
        {   
            while ! $(result) && $(names)
            {
                local f ;
                if $(target-os) = windows
                {         
                    f = $(paths[1])/$(names[1]).lib ;                
                    if [ path.exists $(f) ] 
                    {
                        result = $(f) ;
                    }
                }
                else
                {
                    # FIXME: check for .a as well, depending on
                    # the 'link' feature.
                    f = $(paths[1])/lib$(names[1]).so ;                
                    ECHO "CHECKING $(f) " ;
                    if [ path.exists $(f) ] 
                    {
                        result = $(f) ;
                    }
                }
                if ! $(result) && $(provided-path)
                {
                    errors.user-error "Could not find either of: " $(names)
                      : "in the user-specified directory" $(provided-path) ;
                    
                }                
                names = $(names[2-]) ;
            }
            paths = $(paths[2-]) ;
        }        
        $(variable)-$(properties) = $(result) ;
        return $(result) ;
    }
}

class ac-library : basic-target
{
    import errors ;
    import indirect ;
    import virtual-target ;
    import ac ;
    import configure ;

    rule __init__ ( name : project : * : * )
    {
        basic-target.__init__ $(name) : $(project) : $(sources)
          : $(requirements) ;
        
        reconfigure $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ; 
    }
    
    rule set-header ( header )
    {
        self.header = $(header) ; 
    }
        
    rule set-default-names ( names + )
    {
        self.default-names = $(names) ;
    }
        
    rule reconfigure ( * : * )
    {
        ECHO "XXX" $(1) ;
        if ! $(1)
        {
            # This is 'using xxx ;'. Nothing to configure, really.
        }
        else
        {
            for i in 1 2 3 4 5 6 7 8 9             
            {
                # FIXME: this naming is inconsistent with XXX_INCLUDE/XXX_LIBRARY
                if ! ( $($(i)[1]) in root include-path library-path library-name condition )
                {
                    errors.user-error "Invalid named parameter" $($(i)[1]) ;
                }   
                local name = $($(i)[1]) ;
                local value = $($(i)[2-]) ;
                if $($(name)) && $($(name)) != $(value)
                {
                    errors.user-error "Attempt to change value of '$(name)'" ;
                }
                $(name) = $(value) ;
            }
            
            include-path ?= $(root)/include ;
            library-path ?= $(root)/lib ;            
        }        
    }
    
    rule construct ( name : sources * : property-set )
    {
        # FIXME: log results.
        local libnames = $(library-name) ;
        if ! $(libnames) && ! $(include-path) && ! $(library-path)
        {
            libnames = [ modules.peek : $(name:U)_NAME ] ;
            # Backward compatibility only.
            libnames ?= [ modules.peek : $(name:U)_BINARY ] ;
        }
        libnames ?= $(self.default-names) ;
                        
        local includes = [ 
          ac.find-include-path $(name:U)_INCLUDE : $(property-set) : $(self.header) : $(include-path) ] ;
        local library = [ ac.find-library $(name:U)_LIBRARY : $(property-set) : $(libnames) : $(library-path) ] ;
        if $(includes) && $(library)
        {
            library = [ virtual-target.from-file $(library) : . : $(self.project) ] ;
            configure.log-library-search-result $(name) : "found" ;
            return [ property-set.create <include>$(includes) <source>$(library) ] ;
        }
        else
        {
            configure.log-library-search-result $(name) : "no found" ;
        }        
    }
}