#
# $Id: makl_deps,v 1.23 2006/11/10 12:17:40 stewy Exp $
#

##\brief Add a required dependency.
##
##  Add a required dependency of type \e $1 and id \e $2.
##  The remaining arguments are to be defined based on the type:
##   \li 'lib' $1 $2 $3 $4, where \e $3 are CFLAGS, and \e $4 LDFLAGS for the
##                        library (both optional). By default the flags are
##                        determined by the library name.
##   \li 'featx' $1 $2 $3, where \e $3 (optional) is the name of the variable 
##                       to be defined containing the path to the feature. 
##                       If undefined, no variables will be set.
##
##   \param $1 dependency type
##   \param $2 dependency id
##   \param $@ args
##   
makl_require ()
{
    if [ -z `makl_get "__noconfig__"` ]; then
        makl_info "adding required $1 dependency $2"

        file=${makl_run_dir}/deps_$1.require

        makl_tab_find ${file} $2
        [ $? = 0 ] && return

        case $1 in
            lib)
                ${ECHO} "$2|$3|$4" >> ${file}
            ;;
            featx)
                ${ECHO} "$2|$3" >> ${file}
            ;;
            *)
                makl_err 2 "Invalid dependency type: $2"
            ;;
        esac
    fi

    makl_args_add $1 $2 "" "<*>" ""
}

##\brief Add an optional dependency.
##
##  Add an optional dependency of type \e $2 and id \e $3.
##  The remaining arguments are to be defined based on the type:
##   \li 'lib' $1 $2 $3 $4 $5, where \e $4 are CFLAGS, and \e $5 LDFLAGS for the
##                             library (both optional). By default the flags are
##                             determined by the library name.
##   \li 'featx' $1 $2 $3 $4, where \e $4 (optional) is the name of the variable
##                            to be defined containing the path to the feature. 
##                            If undefined, no variables will be set.
##
##   \param $1 enabled by default (1) or disabled by default (0)
##   \param $2 dependency type
##   \param $3 dependency id
##   \param $@ args
##   
makl_optional ()
{
    if [ -z `makl_get "__noconfig__"` ]; then
        makl_info "adding optional $2 dependency $3"

        file=${makl_run_dir}/deps_$2.optional
        
        makl_tab_find ${file} $3
        [ $? = 0 ] && return
        
        case $2 in
            lib)
                ${ECHO} "$3|$1|$4|$5" >> ${file}
            ;;
            featx)
                ${ECHO} "$3|$1|$4" >> ${file}
            ;;
            *)
                makl_err 2 "Invalid dependency type: $2"
            ;;
        esac
    fi
    
    makl_args_add $2 $3 "" "<?>" ""
}

##\brief Mark a dependency as found.
##
##  Mark a dependency of type \e $1 and id \e $2 as found.
##
##   \param $1 dependency type
##   \param $2 dependency id
##
makl_req_found ()
{
    file=${makl_run_dir}/deps_$1.found

    makl_tab_find ${file} $2
    [ $? = 0 ] && return
    
    ${ECHO} $2 >> ${file}
}

##\brief Search for library in default directories.
##
##  Search for library \e $1 in default directories (as defined in etc/args.cf).
##  Compilation is tested with CFLAGS \e $2 and LDFLAGS \e $3.
##
##   \param $1 required lib  
##   \param $2 cflags
##   \param $3 ldflags
##   \param 0 on success, 1 on lib not found.
##
_makl_search_lib ()
{
    f_args=${makl_run_dir}/args
    f_args_lib=${makl_run_dir}/args_lib
    
    # get feature argument defaults
    dft=`makl_tab_get ${f_args} "lib" 3`

    # get specific options
    path=`makl_tab_get ${f_args_lib} $1 2`

    if [ -z ${path} ]; then
        # look for base dir in __libs__ 
        libs=`makl_get "__libs__"`
        if [ "${libs}" ]; then
          makl_libdep $1 ${libs} "$2" "$3"
          [ $? = 0 ] && return 0
        fi
        val=`makl_tab_var "${dft}" "BASE"` 
        dirs=`${ECHO} ${val} | sed 's/:/ /g'`
    else
        dirs=${path} 
    fi

    for dir in ${dirs}; do
        makl_libdep $1 ${dir} "$2" "$3"
        [ $? = 0 ] && return 0
    done 

    return 1
}

## \brief Search for an executable feature.
##  
##  Search for executable feature \e $1 in default directories (as defined
##  in etc/args.cf). It is assumed that the id corresponds to the filename 
##  of the executable file.
##
##  \param $1 feature id
##
_makl_search_featx ()
{
    f_args=${makl_run_dir}/args
    f_args_x=${makl_run_dir}/args_featx
    f_deps_x=${makl_run_dir}/deps_featx.optional

    # get feature argument defaults
    dft=`makl_tab_get ${f_args} "featx" 3`

    # get specific options
    path=`makl_tab_get ${f_args_x} $1 2`

    # get dependency values
    var=`makl_tab_get ${f_deps_x} $1 3`
    
    # get paths defined by BASE
    if [ -z ${path} ]; then
        val=`makl_tab_var "${dft}" "BASE"` 
        dirs=`${ECHO} ${val} | sed 's/:/ /g'`
    else
        dirs=`dirname ${path}`
    fi

    # search for executable file
    for dir in ${dirs}; do
        if [ -x ${dir}/$1 ]; then
            makl_set_var "HAVE_"`makl_upper $1`
            [ -z ${var} ] || makl_set_var "PATH_"`makl_upper $1` ${dir}/$1 1
            return 0
        fi
    done 

    makl_unset_var "HAVE_"`makl_upper $1`
    return 1
}

##\brief Check that "type" dependencies have been fulfilled.
##
##   \param $1 dependency type
##   
_makl_require_check ()
{
    f_req=${makl_run_dir}/deps_$1.require
    f_opt=${makl_run_dir}/deps_$1.optional
    f_have=${makl_run_dir}/deps_$1.found

    [ ! -r ${f_req} ] && [ ! -r ${f_opt} ] && return 0
    [ -r ${f_have} ] || touch ${f_have}

    rm -f ${makl_run_dir}/err

    [ -r ${f_req} ] && \
    cat ${f_req} | {
        while read line; do
            req=`makl_tab_elem "${line}" 1`
            case $1 in
                lib)
                    cflags=`makl_tab_elem "${line}" 2`
                    ldflags=`makl_tab_elem "${line}" 3`
                    ;;
            esac
            cat ${f_have} | {
                found=0
                while read have; do
                    if [ ${have} = ${req} ]; then
                        found=1
                    fi
                done
                if [ ${found} = 0 ]; then
                    # look in default directories before panic
                    makl_info "searching for required $1 feature ${req}" 
                    case $1 in
                        lib)
                            _makl_search_lib "${req}" "${cflags}" "${ldflags}"
                            ;;
                        featx) 
                            _makl_search_featx "${req}"
                            ;;
                    esac
                    if [ ! $? = 0 ]; then
                        ${ECHO} -n ${req} > ${makl_run_dir}/err
                        break
                    fi
                fi
            }
        done
    }

    # try to find optional dependencies which are enabled by default   
    [ -r ${f_opt} ] && \
    cat ${f_opt} | {
        while read line; do
            opt=`makl_tab_elem "${line}" 1`
            dft=`makl_tab_elem "${line}" 2`
            [ "${dft}" = 1 ] && makl_info "searching for optional $1 feature ${opt}" 
            case $1 in
                lib)
                    cflags=`makl_tab_elem "${line}" 3`
                    ldflags=`makl_tab_elem "${line}" 4`
                    if [ "${dft}" = "1" ]; then
                        _makl_search_lib "${opt}" "${cflags}" "${ldflags}"
                        [ $? = 0 ] || \
                            makl_warn "could not find optional $1 dependency ${opt}"
                    fi
                    ;;
                featx) 
                    if [ "${dft}" = "1" ]; then 
                        _makl_search_featx "${opt}"
                        [ $? = 0 ] || \
                            makl_warn "could not find optional $1 dependency ${opt}"
                    fi
                    ;;
            esac
        done
    }
   
    if [ -r ${makl_run_dir}/err ]; then
        makl_err 3 "unfulfilled dependency: '`cat ${makl_run_dir}/err`'!"
    fi  
}

##\brief Set the test code for a library.
##
##  Set the test code for library \e $1. 
##  Data is read from standard input.
##
##   \param $1 library id
##
makl_lib_testcode ()
{
    file=${makl_run_dir}/lib_testcode_$1.c

    # create a clean file
    [ -r ${file} ] && rm -f ${file}

    while read line; do
        ${ECHO} ${line} >> ${file}
    done
}

## \brief Check dependencies
##
## This function is called on termination to check dependencies and generate 
## appropriate variables.
## 
_makl_deps_check ()
{
    [ -z `makl_get "__noconfig__"` ] || return
    makl_info "checking dependencies"
    _makl_require_check "lib"
    _makl_require_check "featx"
}
