#!/usr/bin/env python
# coding: utf-8
#
#    Project: Azimuthal integration
#             https://github.com/silx-kit/pyFAI
#
#    Copyright (C) 2015-2018 European Synchrotron Radiation Facility, Grenoble, France
#
#    Principal author:       Jérôme Kieffer (Jerome.Kieffer@ESRF.eu)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

"""Dummy test to run first to check for relative imports
"""

from __future__ import absolute_import, division, print_function


__author__ = "Jérôme Kieffer"
__contact__ = "Jerome.Kieffer@ESRF.eu"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
__date__ = "15/03/2018"

import subprocess

import unittest
import sys
import logging
import shutil
import os
import numpy
import glob

from .utilstest import UtilsTest

logger = logging.getLogger(__name__)

def get_results(radice):
    import os
    import glob
    result={}
    result["vol"] = glob.glob(radice+"/vol*.vol")+glob.glob(radice+"/reconstruction*.vol")
    lf = glob.glob(radice+"/*.edf")
    result["edf"] = [ t for t in lf if ("histo" not in t and "phase1" not in t and "phase2" not in t )]
    return result


def get_project_name(root_dir):
    """Retrieve project name by running python setup.py --name in root_dir.

    :param str root_dir: Directory where to run the command.
    :return: The name of the project stored in root_dir
    """
    logger.debug("Getting project name in %s", root_dir)
    
    exists = os.path.isfile(os.path.join( root_dir,   "setup.py"    )   )
    if exists :
        p = subprocess.Popen([sys.executable, "setup.py", "--name"],
                             shell=False, cwd=root_dir, stdout=subprocess.PIPE)
        name, _stderr_data = p.communicate()
        logger.debug("subprocess ended with rc= %s", p.returncode)
        print(" PROJECT ", name ) 
        print(" PROJECT ", name.split()[-1].decode('ascii') ) 
        return name.split()[-1].decode('ascii')
    else:
        fns = glob.glob(os.path.join(root_dir,"*"))
        print( fns)
        for n in fns:
            if n[:] == "PyHST2_":
                return n
            
    raise Exception( " unable to find project name "   )
        
                        
        
def compara_vols(ref, new , tol ):
    
    class parInfo:
        LOWBYTEFIRST=1
        os.system("sync")
        s = open(ref+".info").read()
        s=s.replace("!","#")
        exec( s )
    print( ref)
    print( new)
    f_ref = open(ref,"rb")
    f_new = open(new,"rb")
    maxerr=-1
    overerr = 0
    miz=-1
    nprocs=1
    

    err_list=[]
    
    for iz in range(parInfo.NUM_Z):

        sr = f_ref.read( parInfo.NUM_X*parInfo.NUM_Y * 4 )
        sn = f_new.read( parInfo.NUM_X*parInfo.NUM_Y * 4 )

        r  = numpy.reshape(numpy.fromstring(sr,"f"), [   parInfo.NUM_Y, parInfo.NUM_X ] )
        n  = numpy.reshape(numpy.fromstring(sn,"f"), [   parInfo.NUM_Y, parInfo.NUM_X ] )
        err = (r-n)
        err=(err*err).sum()
        rsum = (r*r).sum()
        nsum = (n*n).sum()

        err_list.append( [  err , rsum, nsum  ] )

        
        if rsum==0 and nsum==0 :
            err = -1

    assert(len( err_list))
    err_list = numpy.array(err_list)
    mm = err_list[:,1].max()
    ma = err_list[:,0].max()
    
    print( " SCARTI ", ma ,"/", mm )
    
    if ma > tol * mm:
        
        raise Exception(" Too big error ")
    

def compara_edfs(ref, new , tol ):
    import fabio
    
    maxerr=-1
    overerr = 0
    miz=-1
    done =0

    NN = len( list(zip (ref, new )))

    err_list=[]

    assert( len(ref)  == len(new) )
    
    for iz,(rname, nname) in enumerate(list(zip (ref, new ))) :
        done=1

        r  = fabio.open(rname).data
        n  = fabio.open(nname).data
        err = (r-n)
        err=(err*err).sum() 
        rsum = (r*r).sum()
        nsum = (n*n).sum()

        err_list.append( [  err , rsum, nsum  ] )


        
        if err> maxerr:
            maxerr=err
            dr = r
            dn = n
            overerr = (r*r).sum()
            mrname = rname
            mnname = nname 
 
    assert(len( err_list))
    err_list = numpy.array(err_list)
    mm = err_list[:,1].max()
    ma = err_list[:,0].max()    
    if ma > tol*mm:
        raise Exception(" Too big error ")
    print( " SCARTI ", ma ,"/", mm ) 




def class_provider ( testcase,case_subdir , skip_check=False  ) :
    
    class TestDummy(unittest.TestCase):
        mytests=["standard","nslino","nslinogpu","oar", "oargpu", "achille", "achillegpu"]
        my_case_dir = case_subdir
        my_testcase = testcase
        my_skip_check = skip_check
        def __repr__(self):
            s="TESTCLASS__"+self.my_case_dir+"____"+self.my_testcase
            return s
        def test_dummy(self):
            PROJECT = get_project_name(".")
            if PROJECT not in sys.modules:
                PyHST  = __import__(PROJECT  )
            else:
                PyHST  =   sys.modules[PROJECT]
            logger.info("here is project  %s",PROJECT )

            PREFIX="/scisoft/users/mirone/WORKS/TEST_PYHST/DATASETS/"

            if self.my_testcase =="nslino":
                LAUNCHING_INSTRUCTION  = "%s  input.par  " %PROJECT
            if self.my_testcase =="nslinogpu":
                LAUNCHING_INSTRUCTION  = "%s  input.par  scisoft12,0" %PROJECT
                
            if self.my_testcase =="achille":
                LAUNCHING_INSTRUCTION  = "%s  input.par  " %PROJECT
                
            if self.my_testcase =="achillegpu":
                LAUNCHING_INSTRUCTION  = "%s  input.par  achille,0" %PROJECT

            if self.my_testcase in ["oargpu"]:
                LAUNCHING_INSTRUCTION  = "%s  input.par  " %PROJECT


            outputprefix="tests_results_nobackup/"
            inputprefix ="TEST_PYHST/INPUTS"


            print("   inputprefix " , inputprefix)
            print( "  self.my_case_dir " , self.my_case_dir)
            direttorio_input = os.path.join( inputprefix,self.my_case_dir)
            direttorio_output = os.path.join(outputprefix,self.my_case_dir)
            # direttorio_reference = os.path.join(os.path.expanduser("~"),"pyhst_tests_results", self.my_case_dir)
            direttorio_reference = os.path.join( "/data/scisofttmp/mironetest/","pyhst_tests_results", self.my_case_dir)

            os.system("rm -rf %s"% direttorio_output)
            os.makedirs(direttorio_output)

            print  (" DI R" , os.getcwd())

            print("direttorio_input " , direttorio_input )
            
            s=open(os.path.join( direttorio_input  , "input.par") ,"r" ).read()
            s="PREFIX=\"%s\" \n"%PREFIX +s
            open( os.path.join( direttorio_output  , "input.par" ) ,"w").write(s) 

            savedPath = os.getcwd()
            os.chdir( direttorio_output)

            print(LAUNCHING_INSTRUCTION)
            
            os.system( LAUNCHING_INSTRUCTION )
            os.system("sync")
            # os.system("sleep 60")
            os.chdir(savedPath)

            ress_ref = get_results(direttorio_reference)
            ress_new = get_results(direttorio_output)

            if ( len(ress_ref["vol"])==0 and  len(ress_ref["edf"])==0   ):
                print (  direttorio_reference    )
                
                if self.my_skip_check :
                    print ("The reference directory contains no results!! " +direttorio_reference)
                else:
                    raise Exception("The reference directory contains no results!! "+direttorio_reference)
                
            if ( len(ress_new["vol"])==0 and  len(ress_new["edf"])==0   ):
                print(direttorio_output)
                
                if self.my_skip_check :
                    print ("The OUTPUT directory contains no results!! " +direttorio_output )
                else:
                    raise Exception("NO DATA PRODUCED!! " +direttorio_output)

            if len(ress_ref["vol"]):
                assert( len(ress_ref["vol"])==1)
                ress_vol = ress_ref["vol"][0]
                new_vol  = ress_new["vol"][0]
                
                tol = 0.01
                
                if "abs_" in os.path.basename( self.my_case_dir) :
                    tol = 0.03
                    
                compara_vols(ress_vol,  new_vol , tol  )



                    
            if len(ress_ref["edf"]):
                ress_edf = ress_ref["edf"]
                new_edf  = ress_new["edf"]
                ress_edf.sort()
                new_edf .sort()
                tol = 0.01
                if "abs_" in os.path.basename( self.my_case_dir) :
                    tol = 0.03
                compara_edfs(ress_edf,  new_edf , tol  )

    return TestDummy



def test_classes(testcase):
    myclassi={}
    casi = {
        # "CRAYON/TESTS/"                 : ( False     , 0,[ "pag_una"]),
        "CRAYON/TESTS/"                 : ( False     , 0,[ "abs_solo_tutte", "abs_solo_unaslice", "pag_molte_edf", "pag_tutte", "pag_una"]),
        # "HELICOIDAL/TESTS/"              : ( False      , 0,[ "abs_solo_una"]),
        # "ID11_SNOW/TESTS/"              : ( False      , 1,[ "chambolle_pock"]),
        
        # # "SINO_THRESHOLD/TESTS/"         : ( False     , 1,[ "threshold_unsharp"]),  # provvisoriamente tolta da nslino
        # "HEIKKI/TESTS/"                 : ( False   , 1,[ "big"]),  # provvisoriamente tolta da nslino
        
        # "MULTIPAGANIN/TESTS/"           : ( False   , 1,[ "volume"]),
        # #  "SIRT_LENA/TESTS/"              : ( True   , 1,[ "oneslice_sirt"]),
        # # "PATCHES_VECTORIAL/TESTS/"      : ( False   , 1,[ "patches", "patches_preconditioned"]),
        # "PATCHES_VECTORIAL/TESTS/"      : ( False   , 1,[  "patches_preconditioned"]),
        # "LENA/TESTS/"                   : ( False   , 1,[ "dictio"]),
        # "LENA_MULTIRINGS/TESTS/"         : ( False   , 1,[ "multiring"]),
        # # "MOUSSE/TESTS/"                 : ( False   , 1,[ "DL"]),
        # # "NANOPOINTS/TESTS/"             : ( False   , 1,[ "DL"]),
        # "BIG/TESTS/"                    : ( False   , 1,[ "pag_tutte"])
        # ##### "NNFBP/TESTS/CRAYON/"                  : (       True             , 1    ,[ "phase1"]),  # provvisoriamente tolta da nslino
        # # "NNFBP/TESTS/CRAYON/"                  : (       True             , 1    ,[ "phase2"]),  # provvisoriamente tolta da nslino
        # # "NNFBP/TESTS/CRAYON/"                  : ( False, 1    ,[ "phase3"]),                    # provvisoriamente tolta da nslino
    }
    for case  , (skip_check, level, subdirs) in casi.items():
        print ( "  SKIP  testcase ??", testcase ) 
        if skip_check == -1 :
            continue
        
        if level%4 ==1 :
            if "gpu" not in testcase:
                continue 
            if "nslino" in testcase:
                continue

        if level%4 ==2 :
            if "2gpu" not in testcase:
                continue
            
        if level>= 4 :
            if "oar" not in testcase :
                continue
        


        for subdir in subdirs:

            case_subdir = case+"/"+subdir

            TestDummy = class_provider ( testcase,case_subdir , skip_check= skip_check )

            TestDummy.__name__ =        "TestDummy_"+ TestDummy.my_case_dir +"___"+testcase   
            myclassi[case_subdir] = TestDummy

    return myclassi


        
def suite(testcase):
    testsuite = unittest.TestSuite()
    myclassi = test_classes( testcase  )
    for name, classe in myclassi.items():    
        if testcase in classe.mytests:
            loader = unittest.defaultTestLoader.loadTestsFromTestCase
            testsuite.addTest(loader(classe))

    return testsuite


if __name__ == '__main__':
    runner = unittest.TextTestRunner()
    runner.run(suite())
    UtilsTest.clean_up()
