#!/bin/bash

# This file is part of MEGAlib.
# Copyright (C) by Andreas Zoglauer.
#
# Please see the MEGAlib software license and documentation for more informations.


# Part 1:
# Helper functions

confhelp() {
  echo ""
  echo "Configuration script for MEGAlib"
  echo ""
  echo "Usage: ./configure [options]";
  echo ""
  echo ""
  echo "Options:"
  echo "--architecture=[linux, macosx]"
  echo "    Default is autodetected via uname -a, thus there should be no need to give this option!"
  echo " "
  echo "--optimization=[off/no, normal/on/yes, strong/hard (requires gcc 4.2 or higher)]"
  echo "    Default is normal."
  echo " "
  echo "--debug=[off/no, on/yes, strong/hard]"
  echo "    Default is on."
  echo " "
  echo "--compiler=[gcc, clang, icc]"
  echo "    This currently only works on Linux. Default is gcc. On a Mac always the default compiler is used."
  echo " "
  echo "--updates=[off/no, on/yes]"
  echo "    Check periodically for updates. Default is off."
  echo "    Even if set to on, update checks will only be performed, if the user has write access to the MEGAlib installation."
  echo " "
  echo "--help or -h"
  echo "    Show this help."
  echo " "
  echo ""
  echo "Examples:"
  echo "  ./configure --optimization=normal --debug=off"
  echo "  It is possible to reduce the command line to the bare minimum which is still unique, e.g. "
  echo "  ./configure -o=y -d=n"
  echo " "
}


# Part 2:
# A first sanity check

if [ "$SHELL" != "/bin/bash" ]; then
  echo " " 
  echo "Info: This is a bash script. Thus you need to use bash for it and not: ${SHELL}"
  echo " "
fi



# Part 3:
# Upgrade the input options:

# Store command line
CMD=""
while [[ $# -gt 0 ]] ; do
    CMD="${CMD} $1"
    shift
done

# Check for help
for C in ${CMD}; do
  if [[ ${C} == *-h* ]]; then
    echo ""
    confhelp
    exit 0
  fi
done


echo ""
echo ""
echo ""
echo "Configuring MEGAlib for compilation on your system"
echo "=================================================="
echo ""
echo " "
echo "(1) Verifying chosen configuration options:"
echo " "

# Remove the old configuration store
rm -f config/configure_lastgoodoptions

# Default options:
OS=`uname -s`
OPT="normal"
DEBUG="on"
COMP="gcc"
UPDATES="off"

# Overwrite default options with user options:
for C in ${CMD}; do
  if [[ ${C} == *-a*=* ]]; then
    OS=`echo ${C} | awk -F"=" '{ print $2 }'`
  elif [[ ${C} == *-o*=* ]]; then
    OPT=`echo ${C} | awk -F"=" '{ print $2 }'`
  elif [[ ${C} == *-d*=* ]]; then
    DEBUG=`echo ${C} | awk -F"=" '{ print $2 }'`
  elif [[ ${C} == *-u*=* ]]; then
    UPDATES=`echo ${C} | awk -F"=" '{ print $2 }'`
  elif [[ ${C} == *-c*=* ]]; then
    COMP=`echo ${C} | awk -F"=" '{ print $2 }'`
  elif [[ ${C} == --linux ]]; then
    OS="linux"
  elif [[ ${C} == --macosx ]]; then
    OS="darwin"
  elif [[ ${C} == --debug ]]; then
    DEBUG="on"
  elif [[ ${C} == --optimize* ]]; then
    OPT="on"
  elif [[ ${C} == *-h* ]]; then
    echo ""
    confhelp
    exit 0
  else
    echo ""
    echo "ERROR: Unknown command line option: ${C}"
    echo "       See \"./configure --help\" for a list of options"
    exit 1
  fi
done


# Everything to lower case:
OS=`echo ${OS} | tr '[:upper:]' '[:lower:]'`
OPT=`echo ${OPT} | tr '[:upper:]' '[:lower:]'`
DEBUG=`echo ${DEBUG} | tr '[:upper:]' '[:lower:]'`
COMP=`echo ${COMP} | tr '[:upper:]' '[:lower:]'`
UPDATES=`echo ${UPDATES} | tr '[:upper:]' '[:lower:]'`


# provide feed back and perform error checks:

if [[ ${OS} == l* ]]; then
  OS="linux"
  echo " * Using operating system architecture Linux"
elif ( [[ ${OS} == d* ]] || [[ ${OS} == m* ]] ); then
  OS="darwin"
  echo " * Using operating system architecture Darwin (Mac OS X)"
else
  echo " "
  echo "ERROR: Unknown operating system architecture: ${OS}"
  confhelp
  exit 1
fi


if ( [[ ${OPT} == of* ]] || [[ ${OPT} == no ]] ); then
  OPT="off"
  echo " * Using no code optimization"
elif ( [[ ${OPT} == nor* ]] || [[ ${OPT} == on ]] || [[ ${OPT} == y* ]] ); then
  OPT="normal"
  echo " * Using normal code optimization"
elif ( [[ ${OPT} == s* ]] || [[ ${OPT} == h* ]] ); then
  OPT="strong"
  echo " * Using strong code optimization"
else
  echo " "
  echo "ERROR: Unknown code optimization: ${OPT}"
  confhelp
  exit 1
fi


if ( [[ ${DEBUG} == of* ]] || [[ ${DEBUG} == no ]] ); then
  DEBUG="off"
  echo " * Using no debugging code"
elif ( [[ ${DEBUG} == on ]] || [[ ${DEBUG} == y* ]] || [[ ${DEBUG} == nor* ]] ); then
  DEBUG="normal"
  echo " * Using debugging code"
elif ( [[ ${DEBUG} == st* ]] || [[ ${DEBUG} == h* ]] ); then
  DEBUG="strong"
  echo " * Using more debug flags"
else
  echo " "
  echo "ERROR: Unknown debugging code selection: ${DEBUG}"
  confhelp
  exit 1
fi


if ( [[ ${COMP} == g* ]] ); then
  COMP="gcc"
  command -v g++ >/dev/null 2>&1 || { echo " "; echo "Error: gnu gcc is not installed!"; exit 1; }
  echo " * Using gnu compiler"
elif ( [[ ${COMP} == c* ]] ); then
  COMP="clang"
  command -v clang++ >/dev/null 2>&1 || { echo " "; echo "Error: clang is not installed!"; exit 1; }
  echo " * Using clang compiler"
elif ( [[ ${COMP} == i* ]] ); then
  COMP="icc"
  command -v icc >/dev/null 2>&1 || { echo " "; echo "Error: icc is not installed!"; exit 1; }
  echo " * Using icc compiler"
else
  echo " "
  echo "ERROR: Unknown compiler option: ${COMP}"
  confhelp
  exit 1
fi


if ( [[ ${UPDATES} == of* ]] || [[ ${UPDATES} == n* ]] ); then
  UPDATES="off"
  echo " * Don't check for updates"
elif ( [[ ${UPDATES} == on ]] || [[ ${UPDATES} == y* ]] ); then
  UPDATES="on"
  echo " * Check for updates if the user has write access to the MEGAlib installation"
else
  echo " "
  echo "ERROR: Unknown option for updates: ${UPDATES}"
  confhelp
  exit 1
fi


# Part 4:
# Check if all programs are available


# Start configuration
echo ""
echo ""
echo "(2) Testing paths and programs:"



# Check for path to MEGAlib
echo ""
echo "(a) MEGAlib"
echo ""
if ( `test -d $MEGALIB` && [ "$MEGALIB" != "" ] ); then
  echo "Found MEGAlib: $MEGALIB";
else
  echo "MEGAlib installation directory not found!";
  echo ""
  echo "--> Please add the path to MEGAlib to your resource file (e.g. .bashrc or .tcshrc)";
  echo "    Example for .bashrc: export MEGALIB=$HOME/MEGAlib";
  echo "    Example for .tcshrc: setenv MEGALIB ${HOME}/MEGAlib";
  echo "--> If you are trying to run this script with sudo, your existing environment variables might not be transferred";
  echo "    Instead of \"sudo ./configure ...\", try \"sudo bash\" and then configure."
  echo ""
  exit 1
fi


# Check for ROOT
echo ""
echo "(b) ROOT"
echo ""
bash ${MEGALIB}/config/configure_checkpath exe root
FoundROOTExe=$?;
if [ $FoundROOTExe -eq 0 ]; then
  echo "ROOT program not found or not executable!"
  echo ""
  echo "--> If ROOT is not installed, then install it first!"
  echo "--> If ROOT is installed, make sure that your PATH variable contains a folder which contains root,"
  echo "    that you have read access to the ROOT directory, and that ROOT is executable"
  echo "--> If ROOT is installed, the PATH is set, and you run this script via sudo, then you have to make"
  echo "    sure you have set the PATH globally and not just for the user as the PATH variable might not be"
  echo "    transferred via sudo"
  echo "    Thus instead of \"sudo -E ./configure ...\", try \"sudo bash\" and then configure."
  echo ""
  exit 0;
fi

bash ${MEGALIB}/config/configure_checkpath lib libCore
FoundROOTLibs=$?;
if [ $FoundROOTLibs -eq 0 ]; then
  echo "ROOT libraries not found or not readable/accessable (test case: the \"Core\" library)!"
  echo ""
  echo "--> If ROOT is not installed, then install it first!"
  echo "--> If ROOT is installed, make sure your LD_LIBRARY_PATH variable contains a folder "
  echo "    which contains the root libraries (on Mac it's the DYLD_LIBRARY_PATH) and"
  echo "    that you have read access to the libraries"
  echo ""
  exit 0;
fi

echo "Found ROOT: $(which root)";

bash ${MEGALIB}/config/configure_rootversiontest -s;
RootVersionOK=$?;
if [ $RootVersionOK -eq 1 ]; then
  exit 1
fi


# Check for Geant4
echo ""
echo "(c) GEANT4"
echo ""

Geant4Found=1;
Geant4DawnFileFound=1;
Geant4OpenGLFound=1;

bash ${MEGALIB}/config/configure_checkpath lib libG4event
FoundGeant4Libs=$?;
if [ $FoundGeant4Libs -eq 0 ]; then
  echo "Geant4 libraries not found (test case: the \"G4event\" library)!"
  echo ""
  echo "Geant4 is not required for all parts of MEGAlib:"
  echo "--> This is only a problem if you want to do simulations with Cosima, "
  echo "    you can use the rest of MEGAlib without it."
  echo "    If you reinstall GEANT4 later, please rerun configure and recompile"
  echo ""
  echo "But if you want to do simulations:"
  echo "--> If Geant4 is not installed, then install it first!"
  echo "--> If Geant4 is installed, make sure your LD_LIBRARY_PATH variable contains a folder,"
  echo "    which contains the Geant4 libraries (on Mac it's the DYLD_LIBRARY_PATH) and "
  echo "    make sure you have read access to the libraries!"
  Geant4Found=1
else
  GEANT4CONFIG=`type -P geant4-config`
  if ([ "${GEANT4CONFIG}" != "" ]); then
    echo "Found Geant4: $(geant4-config --prefix)";
  else
    echo "Found Geant4: ${G4INSTALL} on ${G4SYSTEM}";
  fi
  Geant4Found=0;

  bash ${MEGALIB}/config/configure_geant4versiontest -s;
  Geant4VersionOK=$?;
  if [ $Geant4VersionOK -eq 1 ]; then
    Geant4Found=1;
  fi
  
  Geant4OpenGLFound=1
  if [ "${G4VIS_USE_OPENGLX}" == "1" ]; then
    echo "Found Geant4 visualization: OPENGLX";
    Geant4OpenGLFound=0;
  fi; 
fi

# Check for path to HEAsoft
echo ""
echo "(d) HEAsoft (optional)"
echo ""

HEAsoftFound=1

HEADir=""
if ( [ "$HEADAS" != "" ] && [ -d $HEADAS ] ); then
  HEADir="$HEADAS"
elif ( [ "$HEASOFT" != "" ] && [ -d $HEASOFT ] ); then
  HEADir=$HEASOFT
fi

if ( [ "${HEADir}" != "" ] ); then
  if ( [ -f ${HEADir}/lib/libcfitsio.a ] || [ -f ${HEADir}/lib/libcfitsio.so ] ); then 
    echo "Found HEAsoft: $HEADir";
    HEAsoftFound=0
  else
    echo "HEAsoft directory found, but there is no libcfitsio.[so or dylib] library in $HEADir/lib!"
    HEAVersionedLib=`ls $HEADir/lib/libcfitsio_*.*`
    if ( [ "$HEAVersionedLib" != "" ] ); then
      echo "However I found a libcfitsio with a version number: $HEAVersionedLib"
      echo "If you want to use HEAsoft please make a link, e.g., on Linux in the directory of the library do:" 
      echo "sudo ln -s libcfitsio_X.XX.so licfitsio.so"
    fi
    echo ""
    echo "-> HEAsoft is only required if you want to do simulations with MGGPOD and convert the fits files via ConvertMGGPOD.";
    echo "   This is very rarely the case. Thus you might just ignore that message."
    echo "   If you reinstall HEAsoft later, please re-run configure and recompile";
    HEAsoftFound=1
  fi
else 
  echo "HEAsoft installation not found!";
  echo ""
  echo "-> HEAsoft is only required if you want to do simulations with MGGPOD and convert the fits files via ConvertMGGPOD.";
  echo "   This is very rarely the case. Thus you might just ignore that message."
  echo "   If you reinstall HEAsoft later, please re-run configure and recompile";
  HEAsoftFound=1
fi



# Check for MPI tools
echo ""
echo "(e) MPI tools (optional)"
echo ""

MPIFound=0

if ( [ -f /usr/include/mpi/mpi.h ] ); then 
  echo "Found MPI header";
  if hash mpirun 2>/dev/null; then
    echo "Found mpirun executable"
  else
    echo "-> Couldn't find the MPI run executable."
    echo "   Deactivating the compilation of the MPI parts of MEGAlib."
    echo "   But don't worry. Everything is fine. You normally wouldn't need them anyway."
    MPIFound=1
  fi
else 
  echo "-> Couldn't find the MPI header file in /usr/include/mpi."
  echo "   Deactivating the compilation of the MPI parts of MEGAlib."
  echo "   But don't worry. Everything is fine. You normally wouldn't need them anyway."
  MPIFound=1
fi  



# Check for other little helper programs
echo ""
echo "(f) Miscellaneous helper tools"
echo ""

bash ${MEGALIB}/config/configure_misctools -s;
MiscTest=$?;

if [ $MiscTest -eq 1 ]; then
  echo ""
  echo "-> The miscellaneous helper tools are not mandatory, and only required by secondary programs and functions."
  echo "   Thus you can continue, if one is missing and install it later when you need it."
  echo ""
fi




# Part 5:
# Setup the make environment

echo ""
echo ""
echo "(3) Preparing the Makefiles:"
echo ""

# Choose main Makefile
if [[ ${OS} == linux ]]; then
  if [[ ${COMP} == gcc ]]; then
    echo "Configuring for Linux with gnu gcc compiler ..."
    cp config/Makefile.linuxgcc config/Makefile.config 
  elif [[ ${COMP} == icc ]]; then
    echo "Configuring for Linux with Intel icc compiler ..."
    cp config/Makefile.linuxicc config/Makefile.config
  elif [[ ${COMP} == clang ]]; then
    echo "Configuring for Linux with clang compiler ..."
    cp config/Makefile.linuxclang config/Makefile.config
  else
    echo " "
    echo "ERROR: Compiler not supported for linux: ${COMP}"
    confhelp
    exit 1    
  fi
elif [[ ${OS} == darwin ]]; then
  if [[ ${COMP} == gcc ]]; then
    echo "Configuring for MaxOSX ..."
    cp config/Makefile.macosx config/Makefile.config
  else
    echo " "
    echo "ERROR: Compiler not supported for linux: ${COMP}"
    confhelp
    exit 1    
  fi
else
  echo " "
  echo "ERROR: Unknown operating system architecture: ${OS}"
  confhelp
  exit 1
fi


# Set default values for the options
OPTIONS=""

if [[ ${OPT} == normal ]]; then
  if [[ ${COMP} == gcc ]] && [[ ${DEBUG} !=  off ]]; then 
    OPTIONS+=" -Og"
  else
    OPTIONS+=" -O -DNDEBUG"
  fi
elif  [[ $OPT == strong ]]; then
  if [[ ${COMP} == gcc ]]; then 
    if [[ ${DEBUG} !=  off ]]; then 
      OPTIONS+=" -Og"
    else 
      OPTIONS+=" -O3 -mtune=native -fno-strict-aliasing -DNDEBUG"
    fi
  else 
    OPTIONS+=" -O2 -DNDEBUG"
  fi
fi

G4DEBUG="G4DEBUG = 0"
if [[ ${DEBUG} == normal ]] || [[ ${DEBUG} == strong ]]; then
  G4DEBUG="G4DEBUG = 1"
  OPTIONS+=" -g"
  if  [[ ${DEBUG} == strong ]]; then
    OPTIONS+=" -DDEBUG1"
  fi
  if [[ ${COMP} == gcc ]] && [[ ${OS} == linux ]]; then
    OPTIONS+=" -fstack-protector-all"
  fi
fi
                


# Dump the options
rm -f config/Makefile.options

if ([ "${OPTIONS}" != "" ]); then
  echo ""
  echo "Adding the following compiler optimizations: "
  echo "OPT =${OPTIONS}"
  if ( [ $Geant4Found -eq 0 ] ); then 
    echo "$G4DEBUG"
  fi
fi

echo "# Additional platform independend Makefile options" >> config/Makefile.options
echo "# " >> config/Makefile.options
echo "# This file is overwritten the next time configure is called." >> config/Makefile.options
echo "# If you want to define your own user options, then defined them in Makefile.user" >> config/Makefile.options
echo " " >> config/Makefile.options

echo "# " >> config/Makefile.options
echo "# Section A: Additional libraries" >> config/Makefile.options
echo "# " >> config/Makefile.options
echo "# Important: Don't modify this sections by yourself " >> config/Makefile.options
echo " " >> config/Makefile.options
echo "GEANT4INSTALLED  = ${Geant4Found}" >> config/Makefile.options
echo "HEASOFTINSTALLED = ${HEAsoftFound}" >> config/Makefile.options
echo "MPIINSTALLED = ${MPIFound}" >> config/Makefile.options
echo " " >> config/Makefile.options

echo "# " >> config/Makefile.options
echo "# Section B: Compiler optimizations" >> config/Makefile.options
echo "# " >> config/Makefile.options
echo "# Important comments" >> config/Makefile.options
echo "# " >> config/Makefile.options
echo "# If you want to eliminate all massert, mdebug, etc. code use: -DNDEBUG" >> config/Makefile.options
echo "# If you want to produce debug infos in your executables use: -g" >> config/Makefile.options
echo "# The default optimization level is: -O" >> config/Makefile.options
echo "# You can combine all those options: -O -g -DNDEBUG" >> config/Makefile.options
echo "# " >> config/Makefile.options
if [[ ${COMP} = icc ]]; then
    cat config/Makefile.icc_optimizations >> config/Makefile.options
fi
if [[ ${ARCH} == linux ]]; then
    cat config/Makefile.gcc_optimizations >> config/Makefile.options
fi
echo "Please see the file config/Makefile.options for more optimization options for the Intel and GNU compiler"
echo "" >> config/Makefile.options
echo "OPT = ${OPTIONS}" >> config/Makefile.options
if ( [ $Geant4Found -eq 0 ] ); then 
    echo "$G4DEBUG" >> config/Makefile.options
fi
echo "" >> config/Makefile.options
echo "# " >> config/Makefile.options
echo "# Section C: Geant4 visualization options" >> config/Makefile.options
echo "# " >> config/Makefile.options
echo "# Important: Only OpenGL and DawnFile can be detected by this script " >> config/Makefile.options
echo "#            If you have anything else, set it in Makefile.user " >> config/Makefile.options
echo "# " >> config/Makefile.options
echo "" >> config/Makefile.options
if ( [ $Geant4OpenGLFound -eq 0 ] ); then 
    echo "G4VIS_USE_OPENGLX=1" >> config/Makefile.options
fi
if ( [ $Geant4DawnFileFound -eq 0 ] ); then 
    echo "G4VIS_USE_DAWNFILE=1" >> config/Makefile.options
fi
echo "" >> config/Makefile.options


# If the file config/Makefile.user not exists, create it
if (`test ! -f config/Makefile.user`); then
  echo "# Addional user options for the makefile can be set here" >> config/Makefile.user
  echo "# This file is not overwritten during the configure process" >> config/Makefile.user
  echo " " >> config/Makefile.user
  echo " " >> config/Makefile.user
fi


# Part 6:
# Final preparations and clean up

echo ""
echo ""
echo "(4) Preparing for compilation:"

# Check if all directories are present, if not create them
if (`test ! -d include`); then
  echo ""
  echo "Creating directory include"
  mkdir include
fi
if (`test ! -d lib`); then
  echo "Creating directory lib"
  mkdir lib
fi

# Cosima paths --- we are performing some removes, thus try to make sure we don't remove anything wrong
if ( [ $Geant4Found -eq 0 ] && [ "${G4SYSTEM}" != "" ] ); then
  rm -rf src/cosima/bin
  cd bin
  if (`test -d ${G4SYSTEM}`); then
    rm -r ${G4SYSTEM}
  fi
  cd ..
  #ln -s ../../bin src/cosima/bin
  #ln -s ../bin bin/${G4SYSTEM}
fi

# Create a developer list
echo ""
echo "Creating list of developers and contributors by parsing through all cpp, cxx, cc, etc. files..."
bash ${MEGALIB}/config/configure_developers -s;

# Store the current options:
echo "${CMD}" >> config/configure_lastgoodoptions

# Set the updates interval:
if [[ ${UPDATES} == off ]]; then
  echo ""
  echo "Making config/UpdateCheck.txt read-only to prevent periodical update checks..."
  touch config/UpdateCheck.txt
  chmod a-w config/UpdateCheck.txt
else
  echo ""
  echo "Setting up config/UpdateCheck.txt for periodical update checks..."
  rm -f config/UpdateCheck.txt
  cp config/Version.txt config/UpdateCheck.txt
fi

# Remove the old build
echo ""
echo "Removing old build..."
make clean

echo ""
echo ""
echo "Done! Now type 'make' to compile and link MEGAlib"
echo ""
     

exit 0
