#!/usr/bin/env python
#
# Copyright (C) 2005-2009 ABINIT Group (Yann Pouillon)
# All rights reserved.
#
# This file is part of the ABINIT software package. For license information,
# please see the COPYING file in the top-level directory of the ABINIT source
# distribution.
#

from time import gmtime,strftime

import commands
import os
import re
import sys

# ---------------------------------------------------------------------------- #

#
# Subroutines
#

# Macro header
def macro_header(name,stamp):

 return """# Generated by %s on %s

#
# ABINIT plug-in support for the "configure" script
#

#
# IMPORTANT NOTE
#
# This file has been automatically generated by the %s
# script. If you try to edit it, your changes will systematically be
# overwritten.
#
""" % (name,stamp,name)



# Init macro header
def macro_plugin(nick,name,desc,libs,bins,urls,include=None,tricks="${abi_fc_vendor},${abi_fc_version}"):

 # Create template
 ret = """


# ABI_PLUGIN_@PKG_NICK@()
# -------------------
#
# Sets all variables needed to handle the @PKG_NICK@ plug-in.
#
AC_DEFUN([ABI_PLUGIN_@PKG_NICK@],
[dnl Initial setup
 lib_@pkg_nick@_includes=""
 lib_@pkg_nick@_libs=""
 build_@pkg_nick@="no"
 abi_plug_ready="no"
 abi_plug_tarball="no"
 abi_plug_bins=""
 abi_plug_incs=""
 abi_plug_libs=""

 dnl Define variables needed to build the library
 @pkg_nick@_pkg_name="@PKG_NAME@"
 AC_SUBST(@pkg_nick@_pkg_name)
 @pkg_nick@_pkg_string="@PKG_DESC@"
 AC_SUBST(@pkg_nick@_pkg_string)

 if test -z "${CPPFLAGS_@PKG_NICK@}"; then
  CPPFLAGS_@PKG_NICK@="${CPPFLAGS}"
 fi
 AC_SUBST(CPPFLAGS_@PKG_NICK@)
 if test -z "${CFLAGS_@PKG_NICK@}"; then
  CFLAGS_@PKG_NICK@="${CFLAGS}"
 fi
 AC_SUBST(CFLAGS_@PKG_NICK@)
 if test -z "${CXXFLAGS_@PKG_NICK@}"; then
  CXXFLAGS_@PKG_NICK@="${CXXFLAGS}"
 fi
 AC_SUBST(CXXFLAGS_@PKG_NICK@)
 if test -z "${FCFLAGS_@PKG_NICK@}"; then
  FCFLAGS_@PKG_NICK@="${FCFLAGS}"
 fi
 AC_SUBST(FCFLAGS_@PKG_NICK@)

 dnl Add optimizations for Fortran flags
 FCFLAGS_@PKG_NICK@="${FCFLAGS_@PKG_NICK@} ${fcflags_opt_@pkg_nick@}"

 dnl Check whether to activate plug-in
 if test "${enable_@pkg_nick@}" = "yes"; then

  dnl Check for already installed plug-ins
  if test "${with_plugins_prefix}" != ""; then
   AC_MSG_CHECKING([whether @PKG_NICK@ is ready for use])
   abi_plug_ready="yes"
   abi_plug_bins="${with_plugins_prefix}/bin"
   abi_plug_incs="-I${with_plugins_prefix}/include"
   abi_plug_libs="-L${with_plugins_prefix}/lib"
   @PLUG_INST_TEST@
   AC_MSG_RESULT([${abi_plug_ready}])
  fi

  if test "${abi_plug_ready}" = "yes"; then
   with_@pkg_nick@_bins="${abi_plug_bins}"
   with_@pkg_nick@_includes="${abi_plug_incs}"
   with_@pkg_nick@_libs="${abi_plug_libs}"
  fi

  dnl Check whether command-line plug-in options have been specified
  if test @INCS_TEST@"${with_@pkg_nick@_libs}" = ""; then

   dnl Check for a tarball repository
   AC_MSG_CHECKING([for a source tarball of @PKG_NICK@])
   if test -s "${abinit_tardir}/@PKG_NAME@.tar.gz"; then
    abi_plug_tarball="yes"
   fi
   AC_MSG_RESULT([${abi_plug_tarball}])

   dnl Get the package
   if test "${abi_plug_ready}" = "no"; then
    if test "${abi_plug_tarball}" = "no"; then
     AC_MSG_NOTICE([downloading @PKG_NICK@ - this may take a while])

     @DOWNLOAD@
    fi

    dnl Enable plug-in support only if the download was successful
    if test "${abi_plug_tarball}" = "yes"; then
     lib_@pkg_nick@_includes="@INCS_PATH@"
     lib_@pkg_nick@_libs="@LIBS_SPECS@"
     build_@pkg_nick@="yes"
    else
     lib_@pkg_nick@_includes=""
     lib_@pkg_nick@_libs=""
     enable_@pkg_nick@="no"
     build_@pkg_nick@="no"
     AC_MSG_WARN([could not download @PKG_NICK@ plug-in tarball])
     AC_MSG_WARN([support for @PKG_NICK@ plug-in has been disabled])
    fi
   fi
  else
   lib_@pkg_nick@_includes="${with_@pkg_nick@_includes}"
   lib_@pkg_nick@_libs="${with_@pkg_nick@_libs}"
   build_@pkg_nick@="no"
  fi

 else
  enable_@pkg_nick@="no"
  build_@pkg_nick@="no"
 fi

 dnl Set variables required to build binaries
@BINS_SPECS@

 dnl Apply tricks if wanted
 if test "${build_@pkg_nick@}" = "yes" -a "${enable_tricks}" = "yes"; then
  ABI_TRICKS_@PKG_NICK@(@TRICKS@)
  if test "${@pkg_nick@_tricks_bypass}" = "yes"; then
   build_@pkg_nick@="no"
  fi
 fi

 dnl Output results
 AC_MSG_CHECKING([whether to enable the @PKG_NICK@ plug-in])
 AC_MSG_RESULT([${enable_@pkg_nick@}])
 AC_MSG_CHECKING([whether to build the @PKG_NICK@ plug-in])
 AC_MSG_RESULT([${build_@pkg_nick@}])

 dnl Define preprocessing macro
 if test "${enable_@pkg_nick@}" = "yes"; then
  AC_DEFINE([HAVE_@PKG_NICK@],1,[Define to 1 if you want support for @PKG_NICK@])
 fi

 dnl Substitute variables needed for the use of the plug-in
 AC_SUBST(lib_@pkg_nick@_includes)
 AC_SUBST(lib_@pkg_nick@_libs)
 AC_SUBST(build_@pkg_nick@)

 dnl Inform Automake
 AM_CONDITIONAL(DO_ENABLE_@PKG_NICK@,test "${enable_@pkg_nick@}" = "yes")
 AM_CONDITIONAL(DO_BUILD_@PKG_NICK@,test "${build_@pkg_nick@}" = "yes")
]) # ABI_PLUGIN_@PKG_NICK@
"""

 # Set include specs
 if ( include == None ):
  incs_test = ""
  incs_path = ""
 else:
  incs_test = "\"${with_@pkg_nick@_includes}\" = \"\" -o "
  incs_path = "-I\$(abinit_builddir)/plugins/@pkg_nick@"

 # Set lib specs
 libs_specs = "-L\$(abinit_builddir)/plugins/@pkg_nick@"
 for lib in libs:
  libs_specs += " -l"+lib

 # Set bin specs
 if ( bins == None ):
  bins_specs = " dnl No binary for @PKG_NICK@"
 else:
  bins_specs = " if test \"${enable_@pkg_nick@}\" = \"yes\"; then\n" \
             + "  FCLIBS_@PKG_NICK@='$(FCLIBS)'\n" \
             + " else\n" \
             + "  FCLIBS_@PKG_NICK@=''\n" \
             + " fi\n" \
             + " AC_SUBST(FCLIBS_@PKG_NICK@)"

 # Generate install-test procedure
 inst_proc = ""
 if ( bins != None ):
  for bin in bins:
   inst_proc += "\n" \
             +  "   if test ! -x \"${with_plugins_prefix}/bin/%s\"; then\n"  % (bin) \
             +  "    abi_plug_ready=\"no\"\n" \
             +  "   fi\n"

 if ( libs != None ):
  for lib in libs:
   inst_proc += "\n" \
             +  "   if test -s \"${with_plugins_prefix}/lib/lib%s.a\"; then\n" % (lib) \
             +  "    abi_plug_libs=\"${abi_plug_libs} -l%s\"\n" % (lib) \
             +  "   else\n" \
             +  "    abi_plug_ready=\"no\"\n" \
             +  "   fi\n"

 # Generate download procedure
 urls_proc = ""
 urls_idx  = 1
 for url in urls:
  urls_proc += "     if test ! -s \"${abinit_tardir}/@PKG_NAME@.tar.gz\"; then\n"
  urls_proc += "      AC_MSG_CHECKING([availability of @PKG_NICK@ from URL %d])\n" % (urls_idx)
  urls_proc += "      ${WGET} --timeout=15 --tries=1 -q -O \\\n"
  urls_proc += "       \"${abinit_tardir}/@PKG_NAME@.tar.gz\" \\\n"
  urls_proc += "       '%s'\n" % (url)
  urls_proc += "      test -s \"${abinit_tardir}/@PKG_NAME@.tar.gz\" && abi_plug_tarball=\"yes\"\n"
  urls_proc += "      AC_MSG_RESULT([${abi_plug_tarball}])\n"
  urls_proc += "     fi\n"
  urls_idx  += 1
 urls_proc = urls_proc.lstrip()

 # Transform template (the order is important)
 ret = re.sub("@INCS_TEST@",incs_test,ret)
 ret = re.sub("@INCS_PATH@",incs_path,ret)
 ret = re.sub("@LIBS_SPECS@",libs_specs,ret)
 ret = re.sub("@BINS_SPECS@",bins_specs,ret)
 ret = re.sub("@PLUG_INST_TEST@",inst_proc,ret)
 ret = re.sub("@DOWNLOAD@",urls_proc,ret)
 ret = re.sub("@TRICKS@",tricks,ret)
 ret = re.sub("@PKG_NAME@",name,ret)
 ret = re.sub("@PKG_DESC@",desc,ret)
 ret = re.sub("@PKG_NICK@",nick.upper(),ret)
 ret = re.sub("@pkg_nick@",nick,ret)

 return ret



# ---------------------------------------------------------------------------- #

#
# Main program
#

# Initial setup
my_name    = "make-macros-plugins"
my_configs = ["config/specs/plugins.cf"]
my_output  = "config/m4/do-not-edit-plugins.m4"

# Check if we are in the top of the ABINIT source tree
if ( not os.path.exists("configure.ac") or
     not os.path.exists("src/main/abinit.F90") ):
 print "%s: You must be in the top of an ABINIT source tree." % my_name
 print "%s: Aborting now." % my_name
 sys.exit(1)

# Read config file(s)
for cnf in my_configs:
 if ( os.path.exists(cnf) ):
  execfile(cnf)
 else:
  print "%s: Could not find config file (%s)." % (my_name,cnf)
  print "%s: Aborting now." % my_name
  sys.exit(2)

# What time is it?
now = strftime("%Y/%m/%d %H:%M:%S +0000",gmtime())

# Start writing macro
m4 = file(my_output,"w")
m4.write(macro_header(my_name,now))

# Process plug-ins
for pkg in abinit_plugins:

 # Extract mandatory package information
 pkg_name = eval("%s_name" % (pkg))
 pkg_nick = eval("%s_nick" % (pkg))
 pkg_desc = eval("%s_desc" % (pkg))
 pkg_urls = eval("%s_urls" % (pkg))

 # Extract optional package information
 try:
  pkg_bins = eval("%s_bins" % (pkg))
 except NameError:
  pkg_bins = None
 try:
  pkg_hdrs = eval("%s_hdrs" % (pkg))
 except NameError:
  pkg_hdrs = None
 try:
  pkg_libs = eval("%s_libs" % (pkg))
 except NameError:
  pkg_libs = None
 try:
  pkg_mods = eval("%s_mods" % (pkg))
 except NameError:
  pkg_mods = None

 # Check whether the plug-in exports C headers or modules
 if ( (pkg_hdrs == None) and (pkg_mods == None) ):
  pkg_incs = None
 else:
  pkg_incs = "yes"

 # Prepare libraries
 for i in range(len(pkg_libs)):
  pkg_libs[i] = re.sub(r"^lib(.*)\.a",r"\1",pkg_libs[i])

 # Write macro
 m4.write(macro_plugin(pkg,pkg_name,pkg_desc,pkg_libs,pkg_bins,pkg_urls,pkg_incs))

# Finish
m4.close()

tmp = commands.getoutput("./config/scripts/add-header-typed Autoconf %s" % (my_output))
if ( tmp != "" ):
 print tmp
