#! /usr/bin/env python
# -*- coding: utf-8 -*-

###
#
# @file plasma.py
#
#  PLASMA is a software package provided by Univ. of Tennessee,
#  Univ. of California Berkeley and Univ. of Colorado Denver
#
# @version 2.8.0
# @author Julie Langou
# @author Mathieu Faverge
# @date 2010-11-15
#
###

from utils import writefile, runShellCommand, downloader
import sys
import os
import framework
import shutil

class Plasma(framework.Framework):
    """ This class takes care of the PLASMA installation. """
    def __init__(self, argv, config):
        framework.Framework.__init__(self, argv, config)

    def resume(self):
        print '\n','='*40
        print '  PLASMA installer is starting now. Buckle up!'
        print '='*40

        if self.src:
            self.version = 'svn'
            self.write_makeinc()
        else:
            self.down_install()

        framework.Framework.resume(self)

    def write_makeinc(self):
        """ Writes the make.inc file for PLASMA installation """

        sdir = os.getcwd()
        print 'Writing make.inc...',
        sys.stdout.flush()
        old = 0
        for ver in self.oldversions:
            if self.version == ver :
                old = 1
                break

        if old == 1:
            print "Version under 2.3.0 are not handle by this installer, please use the release 1.2.0"
            exit
            makeinc = """
#/////////////////// P /// L /// A /// S /// M /// A //////////////////
#/// PLASMA is a software package provided by Univ. of Tennessee,  ///
#/// Univ. of California Berkeley and Univ. of Colorado Denver     ///
#//////////// M /// A /// K /// E /// . /// I /// N /// C /////////////

#///////////// U /// S /// E /// R ////// P /// A /// R /// T //////////

PLASMA_DIR  = """+sdir+"""

CC          = """+self.config.cc+"""
FC          = """+self.config.fc+"""
LINKER      = $(FC)

ARCH        = ar
ARCHFLAGS   = """+self.config.arflags+"""
RANLIB      = """+self.config.ranlib+"""

OPTS        = """+self.config.ccflags+""" """+self.mangling+"""
FOPTS       = """+self.config.fcflags+"""
LDOPTS      = """+self.config.ldflags_fc+' '+self.config.ld_fcmain+"""

# Blas Library
LIBBLAS     = """+self.config.blaslib+"""
#///// D /// O ////// N /// O /// T ////// T /// O /// U /// C /// H /////

# Include directory
INC         = -I$(PLASMA_DIR)/include

# Location of the libraries.
LIBDIR      = -L$(PLASMA_DIR)/lib

# Location and name of the PLASMA library.
LIBCBLAS      = $(PLASMA_DIR)/lib/libcblas.a
LIBCORELAPACK = $(PLASMA_DIR)/lib/libcorelapack.a
LIBCOREBLAS   = $(PLASMA_DIR)/lib/libcoreblas.a
LIBPLASMA     = $(PLASMA_DIR)/lib/libplasma.a

#  All libraries required by the tester.
LIB           = -lplasma -lcoreblas -lcorelapack -lcblas $(LIBBLAS) -lpthread -lm

#//////////////////////////////////////////////////////////////////////////
"""
        else:
            if self.config.blasname == "mkl":
                if self.config.compiler == "GNU" or self.config.compiler == "Intel":
                    self.config.ccflags += " -DPLASMA_WITH_MKL"
            elif self.config.blasname == "acml":
                if self.config.compiler == "GNU" or self.config.compiler == "Intel":
                    self.config.ccflags += " -DPLASMA_WITH_ACML"

            makeinc ="""
#/////////////////// P /// L /// A /// S /// M /// A //////////////////
#/// PLASMA is a software package provided by Univ. of Tennessee,  ///
#/// Univ. of California Berkeley and Univ. of Colorado Denver     ///
#//////////// M /// A /// K /// E /// . /// I /// N /// C /////////////
# make.inc automatically generated by plasma-installer

# Install directory
prefix      = """+self.prefix+"""

# To speed up the compilation
MAKE        = make -j 8

CC          = """+self.config.cc+"""
FC          = """+self.config.fc+"""
LOADER      = $(FC)

ARCH        = ar
ARCHFLAGS   = """+self.config.arflags+"""
RANLIB      = """+self.config.ranlib+"""

CFLAGS      = """+self.config.ccflags+""" """+self.mangling+"""
FFLAGS      = """+self.config.fcflags+"""
LDFLAGS     = """+self.config.ldflags_fc+' '+self.config.ld_fcmain+"""

# To compile Fortran 90 interface
PLASMA_F90  = """+str(self.config.withf90)+"""

# To compile Plasma with EZTrace library in order to trace events
# (Don't forget to set correctly PKG_CONFIG_PATH to make `pkg-config --libs eztrace` works)
PLASMA_TRACE= 0

# By sequential kernel
# CFLAGS += -DTRACE_BY_KERNEL

# By parallel plasma function (Works only with dynamic scheduler)
# CFLAGS += -DTRACE_BY_FUNCTION

# Blas Library
LIBBLAS     = """+self.config.blaslib+"""
# CBlas library
LIBCBLAS    = """+self.config.cblaslib+"""
# lapack and tmg library (lapack is included in acml)
LIBLAPACK   = """+self.config.lapacklib+"""
INCCLAPACK  = """+self.config.lapackinc+"""
LIBCLAPACK  = """+self.config.lapclib+"""
"""
        writefile('make.inc',makeinc)

        self.plasmadir = sdir
        print 'done.'

    def down_install(self):
        """ Download and install PLASMA """

        savecwd = os.getcwd()

        # creating the build and lib dirs if don't exist
        if not os.path.isdir(os.path.join(self.prefix,'lib')):
            os.mkdir(os.path.join(self.prefix,'lib'))

        if not os.path.isdir(os.path.join(self.prefix,'include')):
            os.mkdir(os.path.join(self.prefix,'include'))

        if not os.path.isdir(os.path.join(os.getcwd(),'log')):
            os.mkdir(os.path.join(os.getcwd(),'log'))

        versions = self.versions

        for ver in versions:
            cur_fname = "plasma_" + ver + ".tar.gz"

            if not os.path.isfile(os.path.join(os.getcwd(), cur_fname)):
                cur_url = self.urlbase + "/" + cur_fname
                print 'Downloading PLASMA from', cur_url
                downloader(cur_url, self.downcmd)
            else:
                print 'Already downloaded PLASMA to', cur_fname

            if os.path.isfile(os.path.join(os.getcwd(), cur_fname)):
                self.version = ver
                break

        comm = "gunzip -f " + cur_fname
        (output, error, retz) = runShellCommand(comm)
        if retz:
            print "\n\nPLASMA: cannot unzip " + cur_fname
            print "stderr:\n",'*'*40,'\n',error,'\n','*'*40
            sys.exit()

        cur_tar = cur_fname[:-3]
        comm = "tar xf " + cur_tar
        (output, error, retz) = runShellCommand(comm)
        if retz:
            print "\n\nPLASMA: cannot untar " + cur_tar
            print 'stderr:\n','*'*40,'\n',error,'\n','*'*40
            sys.exit()
        os.remove(cur_tar)

        # os.chdir(os.path.join(os.getcwd(),'plasma'))
        comm = 'ls -1 | grep plasma_ | grep -v tar | head -n 1'
        (output, error, retz) = runShellCommand(comm)
        if retz:
            print '\n\PLASMA: error changing to PLASMA dir'
            print 'stderr:\n','*'*40,'\n','   ->  no plasma directory found','\n','*'*40
            sys.exit()
        rep_name = output.replace ("\n","")
        print 'Installing ',rep_name,'...'
        rep_name = os.path.join(os.getcwd(),rep_name)

        os.chdir(rep_name)

        self.write_makeinc()

        print 'Compiling PLASMA...',
        sys.stdout.flush()
        comm = self.make+' lib'
        (output, error, retz) = runShellCommand(comm)
        if retz:
            print '\n\nPLASMA: error building PLASMA'
            print 'stderr:\n','*'*40,'\n',error,'\n','*'*40
            writefile(os.path.join(savecwd,'log/plasmalog'), output+error)
            sys.exit()

        liblog = os.path.join(savecwd,'log/plasmalog')
        writefile(liblog, output+error)
        print 'Installation of PLASMA successful.'
        print '(log is in ',liblog,')'

        # Testings
        if self.testing == 1:

            # Open the file for writing the output and errors
            testlog = os.path.join(savecwd,'log/plasmatestlog')
            f = open(testlog, 'w')

            # Compiling tests
            print 'Compiling tests...',
            sys.stdout.flush()
            comm = self.make+ ' test'
            (output, error, retz) = runShellCommand(comm)
            if retz:
                print '\n\nPLASMA: error building PLASMA test routines'
                print 'stderr:\n','*'*40,'\n',error,'\n','*'*40
                f.write(output+error)
                f.close()
                sys.exit()
            print 'done'
            f.write(output+error)

            # Running in
            os.chdir(os.path.join(os.getcwd(),'testing'))
            print 'Running PLASMA tests on',self.nbcores, 'cores...(takes some time, feel free to grab a coffee!)'
            print '--> testing ...',
            sys.stdout.flush()
            comm = './plasma_testing.py -c ' + str(self.nbcores)
            (output, error, retz) = runShellCommand(comm, sys.stdout)
            if retz:
                print '\n\nPLASMA: Testing failed... '
                print 'stderr:\n','*'*40,'\n',error,'\n','*'*40
                f.write(output+error)
                f.close()
                sys.exit()
            print 'done'
            print error
            f.write(output+error)

            # Running testing/lin
            os.chdir(os.path.join(os.getcwd(),'lin'))
            print '--> testing/lin...',
            sys.stdout.flush()
            comm = './lapack_testing.py'
            (output, error, retz) = runShellCommand(comm, sys.stdout)
            if retz:
                print '\n\nPLASMA: Testing failed... '
                print 'stderr:\n','*'*40,'\n',error,'\n','*'*40
                f.write(output+error)
                f.close()
                sys.exit()
            print 'done'
            print error
            f.write(output+error)

            f.close()
            print '(log is in ',testlog,')'

            os.chdir(os.path.join(os.getcwd(),'../..'))

        # Install
        print '--- Install PLASMA ---',
        sys.stdout.flush()
        if (self.version in self.oldversions) :
            shutil.copy('lib/libplasma.a',    os.path.join(self.prefix,'lib/libplasma.a'))
            shutil.copy('lib/libcoreblas.a',  os.path.join(self.prefix,'lib/libcoreblas.a'))
            shutil.copy('include/plasma.h',   os.path.join(self.prefix,'include/plasma.h'))
            shutil.copy('include/plasmaf.h',  os.path.join(self.prefix,'include/plasmaf.h'))
            shutil.copy('include/plasma_m.h', os.path.join(self.prefix,'include/plasma_m.h'))
            shutil.copy('include/plasma_z.h', os.path.join(self.prefix,'include/plasma_z.h'))
            shutil.copy('include/plasma_c.h', os.path.join(self.prefix,'include/plasma_c.h'))
            shutil.copy('include/plasma_d.h', os.path.join(self.prefix,'include/plasma_d.h'))
            shutil.copy('include/plasma_s.h', os.path.join(self.prefix,'include/plasma_s.h'))
        else:
            comm = 'make install'
            (output, error, retz) = runShellCommand(comm, sys.stdout)
            if retz:
                print '\nPLASMA: make install failed... '
                print 'stderr:\n','*'*40,'\n',error,'\n','*'*40
                f.write(output+error)
                f.close()
                sys.exit()

        self.plasmalib     = os.path.join(self.prefix,'lib/libplasma.a ')
        self.coreblaslib   = os.path.join(self.prefix,'lib/libcoreblas.a ')

        os.chdir(savecwd)
        print "done. PLASMA is installed. Use it in moderation :-)"
