import config.package

class Configure(config.package.Package):
  def __init__(self, framework):
    config.package.Package.__init__(self, framework)
    self.download     = ['http://www.tetgen.org/1.5/src/tetgen1.6.0.tar.gz',
                         'https://web.cels.anl.gov/projects/petsc/download/externalpackages/tetgen1.6.0.tar.gz']
    self.liblist      = [['libtet.a']]
    self.includes     = ['tetgen.h']
    self.buildLanguage= 'Cxx'
    return

  def setupHelp(self, help):
    import nargs
    config.package.Package.setupHelp(self, help)
    help.addArgument('TETGEN', '-download-tetgen-build-exec=<bool>', nargs.ArgBool(None, False, 'Build and install the tetgen executable in addition to the library'))
    return

  def setupDependencies(self, framework):
    config.package.Package.setupDependencies(self, framework)
    self.languages       = framework.require('PETSc.options.languages',   self)
    self.sharedLibraries = framework.require('PETSc.options.sharedLibraries', self)
    self.mathlib         = framework.require('config.packages.mathlib',self)
    self.deps            = [self.mathlib]
    return

  def Install(self):
    import os, sys
    import config.base
    import fileinput

    libDir         = self.libDir
    includeDir     = os.path.join(self.installDir, 'include')
    binDir     = os.path.join(self.installDir, 'bin')
    makeinc        = os.path.join(self.packageDir, 'make.inc')
    configheader   = os.path.join(self.packageDir, 'configureheader.h')

    # This make.inc stuff is completely unnecessary for compiling TetGen. It is
    # just here for comparing different PETSC_ARCH's
    self.pushLanguage('C++')
    g = open(makeinc,'w')
    g.write('SHELL            = '+self.programs.SHELL+'\n')
    g.write('CP               = '+self.programs.cp+'\n')
    g.write('RM               = '+self.programs.RM+'\n')
    g.write('MKDIR            = '+self.programs.mkdir+'\n')
    g.write('OMAKE            = '+self.make.make+' '+self.make.noprintdirflag+'\n')

    g.write('CLINKER          = '+self.getLinker()+'\n')
    g.write('AR               = '+self.setCompilers.AR+'\n')
    g.write('ARFLAGS          = '+self.setCompilers.AR_FLAGS+'\n')
    g.write('AR_LIB_SUFFIX    = '+self.setCompilers.AR_LIB_SUFFIX+'\n')
    g.write('RANLIB           = '+self.setCompilers.RANLIB+'\n')
    g.write('SL_LINKER_SUFFIX = '+self.setCompilers.sharedLibraryExt+'\n')

    g.write('TETGEN_ROOT      = '+self.packageDir+'\n')
    g.write('PREFIX           = '+self.installDir+'\n')
    g.write('LIBDIR           = '+libDir+'\n')
    g.write('INSTALL_LIB_DIR  = '+libDir+'\n')
    g.write('TETGENLIB        = $(LIBDIR)/libtet.$(AR_LIB_SUFFIX)\n')
    g.write('SHLIB            = libtet\n')

    cflags = self.updatePackageCFlags(self.getCompilerFlags())
    cflags += ' '+self.headers.toString('.')
    cflags += ' -fPIC'
    cflags_exe = cflags
    cflags += ' -DTETLIBRARY'
    predcflags = '-O0 -fPIC'    # Need to compile without optimization

    g.write('CC             = '+self.getCompiler()+'\n')
    g.write('CFLAGS         = '+cflags+'\n')
    g.write('PREDCXXFLAGS   = '+predcflags+'\n')
    g.close()

    # Now compile & install
    if self.installNeeded('make.inc'):
      self.framework.outputHeader(configheader)
      try:
        self.logPrintBox('Compiling & installing TetGen; this may take several minutes')
        output,err,ret = config.package.Package.executeShellCommand('mkdir -p '+os.path.join(self.installDir,'lib'), timeout=2500, log=self.log)
        output,err,ret = config.package.Package.executeShellCommand('mkdir -p '+os.path.join(self.installDir,'include'), timeout=2500, log=self.log)
        output1,err1,ret1  = config.package.Package.executeShellCommand('cd '+self.packageDir+' && make CXX="'+ self.getCompiler() + '" CXXFLAGS="' + cflags + '" PREDCXXFLAGS="' + predcflags + '" tetlib && cp *.a ' + libDir + ' && rm *.a *.o', timeout=2500, log = self.log)
        if self.argDB['download-tetgen-build-exec']:
          output2,err2,ret2  = config.package.Package.executeShellCommand('cd '+self.packageDir+' && make CXX="'+ self.getCompiler() + '" CXXFLAGS="' + cflags_exe + '" PREDCXXFLAGS="' + predcflags + '" tetgen && cp tetgen ' + binDir + ' && rm tetgen', timeout=2500, log = self.log)
      except RuntimeError as e:
        raise RuntimeError('Error running make on TetGen: '+str(e))
      output2,err2,ret2  = config.package.Package.executeShellCommand('cp -f '+os.path.join(self.packageDir, 'tetgen.h')+' '+includeDir, timeout=60, log = self.log)
      self.postInstall(output1+err1+output2+err2,'make.inc')

    self.popLanguage()
    return self.installDir

  def configureLibrary(self):
    config.package.Package.configureLibrary(self)
    include = '#include <tetgen.h>'
    body = \
'''
  char args[] = "";
  tetgenio in,out;
  tetrahedralize(args, &in, &out);
'''
    self.pushLanguage('Cxx')
    oldFlags = self.compilers.CXXPPFLAGS
    oldLibs  = self.compilers.LIBS
    self.compilers.CXXPPFLAGS += ' '+self.headers.toString(self.include)
    self.compilers.LIBS = self.libraries.toString(self.lib)+' '+self.compilers.LIBS
    if not self.checkCompile(include,body):
      self.compilers.CXXPPFLAGS += ' -DTETLIBRARY'
      if self.checkCompile(include,body):
        self.addDefine('HAVE_TETGEN_TETLIBRARY_NEEDED',1)
      else:
        raise RuntimeError('Unable to compile with TetGen')
    if not self.checkLink(include,body):
      raise RuntimeError('Unable to link TetGen')
    self.compilers.CXXPPFLAGS = oldFlags
    self.compilers.LIBS = oldLibs
    self.popLanguage()
