#!/usr/bin/python


import sys
from optparse import OptionParser
from ConfigParser import SafeConfigParser, NoOptionError, NoSectionError
from os.path import join, expanduser, dirname
import os.path
import os
from tempfile import mkdtemp
#import pexpect
from datetime import datetime
import subprocess , shlex
import signal

listOfProcesses = []

def receive_signal(signum, stack):
    # while True:
    # print '------------------'
    # print 'Received:', signum
    # print '------------------'
    for proc in listOfProcesses:
        proc.terminate()
        print '---------------------------------'
        print 'Reconstruction terminated by user'
        print '---------------------------------'
        sys.exit()
    return False

def main(argv):
    #parse args
    cmd = argv[0]
    pointInString = cmd.rfind('/')
    pathToCmd = cmd[0:pointInString+1]
    print "---------------------------------- %s" % pathToCmd
    parser = OptionParser()
    parser.add_option("--input"                 , dest="inputFile")
    parser.add_option("--output-dir"                , dest="outputDir",default="./")
    parser.add_option("--inner-radius"          , dest="rmin",default=125)
    parser.add_option("--rotation-angle"          , dest="rotationAngle",default=0)
    parser.add_option("--crystal-length"        , dest="crylength",default=15)
    parser.add_option("--radial-sectors"        , dest="repsec",default=60)
    parser.add_option("--module-repetitions-x"    , dest="repmodx",default=1)
    parser.add_option("--module-repetitions-y"    , dest="repmody",default=1)
    parser.add_option("--module-repetitions-z"    , dest="repmodz",default=16)
    parser.add_option("--module-distance-x"     , dest="arraymodx",default=13)
    parser.add_option("--module-distance-y"     , dest="arraymody",default=13)
    parser.add_option("--module-distance-z"     , dest="arraymodz",default=13)
    parser.add_option("--submodule-repetitions-x" , dest="repsubx",default=1)
    parser.add_option("--submodule-repetitions-y" , dest="repsuby",default=4)
    parser.add_option("--submodule-repetitions-z" , dest="repsubz",default=4)
    parser.add_option("--submodule-distance-x"  , dest="arraysubx",default=3.2)
    parser.add_option("--submodule-distance-y"  , dest="arraysuby",default=3.2)
    parser.add_option("--submodule-distance-z"  , dest="arraysubz",default=3.2)
    parser.add_option("--crystal-repetitions-x"  , dest="repcryx",default=1)
    parser.add_option("--crystal-repetitions-y"  , dest="repcryy",default=2)
    parser.add_option("--crystal-repetitions-z"  , dest="repcryz",default=2)
    parser.add_option("--crystal-distance-x"   , dest="arraycryx",default=1.6)
    parser.add_option("--crystal-distance-y"   , dest="arraycryy",default=1.6)
    parser.add_option("--crystal-distance-z"   , dest="arraycryz",default=1.6)
    parser.add_option("--energy-resolution-fwhm", dest="energyResolutionFWHM",default=0.12)
    parser.add_option("--doi-resolution-fwhm"   , dest="doiResolutionFWHM",default=2.8)
    parser.add_option("--time-resolution-fwhm"   , dest="timeResolutionFWHM",default=200)
    parser.add_option("--smeared-energy"        , dest="smearedEnergy",default=1)
    parser.add_option("--smeared-doi"           , dest="smearedDoi",default=1)
    parser.add_option("--smeared-time"           , dest="smearedTime",default=1)
    parser.add_option("--eff-steps"             , dest="effSteps",default=11)
    parser.add_option("--energy-low"            , dest="enMin",default=100)
    parser.add_option("--energy-high"           , dest="enMax",default=700)
    parser.add_option("--time-window"           , dest="dMax",default=4)
    parser.add_option("--binary"                , dest="binary",default=False,action="store_true")
    parser.add_option("--listmode"              , dest="listmode",default=True,action="store_false")
    parser.add_option("--no-background"         , dest="nobackground",default=False,action="store_true")
    parser.add_option("--stir"                  , dest="stir",default=False,action="store_true")
    parser.add_option("--sensitivity-file"      , dest="sensitivityfile")
    parser.add_option("--normalization-file"      , dest="normalizationfile")
    parser.add_option("--filter-fwhm"           , dest="ffwhm", default=1.5)
    parser.add_option("--filter-power"          , dest="fmp", default=0)
    parser.add_option("--iterations", dest="iterations", default=6)
    parser.add_option("--voxel-size"            , dest="voxelSize", default=2)
    parser.add_option("--rays"                  , dest="rays", default=0)
    parser.add_option("--fov-rotation-axis"     , dest="fovRotationAxis")
    parser.add_option("--fov-rotation-angle"    , dest="fovRotationAngle", default=90.0)
    # parser.add_option("--no-osem"               , dest="osem", default=True, action="store_false")

    (options, argv) = parser.parse_args(argv)



    #put first params in parameters
    parameters = {
                  'inputFile':           options.inputFile,
                  'pointsFile':          None,
                  'outputFile':          None,
                  'outputDir':          options.outputDir,
                  'rmin':                options.rmin,
                  'rotationAngle':       options.rotationAngle,
                  'crylength':           options.crylength,
                  'repsec':              options.repsec,
                  'repmodx':             options.repmodx,
                  'repmody':             options.repmody,
                  'repmodz':             options.repmodz,
                  'arraymodx':           options.arraymodx,
                  'arraymody':           options.arraymody,
                  'arraymodz':           options.arraymodz,
                  'repsubx':             options.repsubx,
                  'repsuby':             options.repsuby,
                  'repsubz':             options.repsubz,
                  'arraysubx':           options.arraysubx,
                  'arraysuby':           options.arraysuby,
                  'arraysubz':           options.arraysubz,
                  'repcryx':             options.repcryx,
                  'repcryy':             options.repcryy,
                  'repcryz':             options.repcryz,
                  'arraycryx':           options.arraycryx,
                  'arraycryy':           options.arraycryy,
                  'arraycryz':           options.arraycryz,
                  'energyResolutionFWHM':options.energyResolutionFWHM,
                  'doiResolutionFWHM':   options.doiResolutionFWHM,
                  'timeResolutionFWHM':   options.timeResolutionFWHM,
                  'smearedDoi':          options.smearedDoi,
                  'smearedEnergy':       options.smearedEnergy,
                  'smearedTime':         options.smearedTime,
                  'binary':              options.binary,
                  'listmode':            options.listmode,
                  'nobackground':        options.nobackground,
                  'stir':                options.stir,
                  'effSteps':            options.effSteps,
                  'enMin':               options.enMin,
                  'enMax':               options.enMax,
                  'dMax':                options.dMax,
                  'sensitivityfile':     options.sensitivityfile,
                  'normalizationfile':     options.normalizationfile,
                  'ffwhm':               options.ffwhm,
                  'fmp':                 options.fmp,
                  'voxelSize':           options.voxelSize,
                  'osem':                False,
                  'rays':                options.rays,
                  'iterations':          options.iterations,
                  'fovRotation':         False,
                  'fovRotationAxis':     options.fovRotationAxis,
                  'fovRotationAngle':    options.fovRotationAngle,
                  'scatter_total_events_file': 'scatter_total.txt'
                  }

    if parameters['inputFile'] == None:
        print 'ERROR: you need to provide at least an input file!!!'
        print 'Syntax: %(cmd)s --input <name of input root file>' %locals()
        return 1
    if parameters['fovRotationAxis'] == None:
        print 'No rotation of FOV'
    else:
        parameters['fovRotation'] = True

    baseFile = parameters['inputFile'][0:len(parameters['inputFile'])-5]
    print baseFile

    baseFolder = parameters['outputDir']
    baseName = baseFile[baseFile.rfind('/')+1:len(baseFile)]

    print "-------------------"
    print baseFolder
    print baseName
    print "-------------------"
    parameters['pointsFile'] = baseFile + '_points.root'
    parameters['outputFile'] = baseFile + '.elm2'


    if parameters['outputDir'] != None:
        print 'aaaaaaaaaaaaaaaaaaa'
        parameters['pointsFile'] = baseFolder + baseName + '_points.root'
        parameters['outputFile'] = baseFolder + baseName + '.elm2'
    print  parameters['pointsFile']
    print parameters['outputFile']

    #Give feedback to the user...
    print ''
    print '|-----------------------------|'
    print '|        Reconstruction       |'
    print '|-----------------------------|'
    print ''
    print 'inputFile            = %(inputFile)s' %parameters
    print 'pointsFile           = %(pointsFile)s' %parameters
    print 'outputFile           = %(outputFile)s' %parameters
    print 'rmin                 = %(rmin)s' %parameters
    print 'rotationAngle        = %(rotationAngle)s' %parameters
    print 'crylength            = %(crylength)s' %parameters
    print 'repsec               = %(repsec)s' %parameters
    print 'repmodx              = %(repmodx)s' %parameters
    print 'repmody              = %(repmody)s' %parameters
    print 'repmodz              = %(repmodz)s' %parameters
    print 'arraymodx            = %(arraymodx)s' %parameters
    print 'arraymody            = %(arraymody)s' %parameters
    print 'arraymodz            = %(arraymodz)s' %parameters
    print 'repsubx              = %(repsubx)s' %parameters
    print 'repsuby              = %(repsuby)s' %parameters
    print 'repsubz              = %(repsubz)s' %parameters
    print 'arraysubx            = %(arraysubx)s' %parameters
    print 'arraysuby            = %(arraysuby)s' %parameters
    print 'arraysubz            = %(arraysubz)s' %parameters
    print 'repcryx              = %(repcryx)s' %parameters
    print 'repcryy              = %(repcryy)s' %parameters
    print 'repcryz              = %(repcryz)s' %parameters
    print 'arraycryx            = %(arraycryx)s' %parameters
    print 'arraycryy            = %(arraycryy)s' %parameters
    print 'arraycryz            = %(arraycryz)s' %parameters
    print 'energyResolutionFWHM = %(energyResolutionFWHM)s' %parameters
    print 'doiResolutionFWHM    = %(doiResolutionFWHM)s' %parameters
    print 'timeResolutionFWHM    = %(timeResolutionFWHM)s' %parameters
    print 'smearedDoi           = %(smearedDoi)s' %parameters
    print 'smearedEnergy        = %(smearedEnergy)s' %parameters
    print 'smearedTime          = %(smearedTime)s' %parameters
    print 'binary               = %(binary)s' %parameters
    print 'listmode             = %(listmode)s' %parameters
    print 'nobackground         = %(nobackground)s' %parameters
    print 'stir                 = %(stir)s' %parameters
    print 'effSteps             = %(effSteps)s' %parameters
    print 'enMin                = %(enMin)s' %parameters
    print 'enMax                = %(enMax)s' %parameters
    if parameters['fovRotation']:
        print 'fovRotationAxis      = %(fovRotationAxis)s' %parameters
        print 'fovRotationAngle     = %(fovRotationAngle)s' %parameters

    simToData_cmd = pathToCmd
    simToData_cmd += "simToData " \
                    "-i %(inputFile)s " \
                    "-o %(pointsFile)s " \
                    "--inner-radius %(rmin)s " \
                    "--crystal-length %(crylength)s " \
                    "--radial-sectors %(repsec)s " \
                    "--module-repetitions-x %(repmodx)s " \
                    "--module-repetitions-y %(repmody)s " \
                    "--module-repetitions-z %(repmodz)s " \
                    "--module-distance-x %(arraymodx)s " \
                    "--module-distance-y %(arraymody)s " \
                    "--module-distance-z %(arraymodz)s " \
                    "--submodule-repetitions-x %(repsubx)s " \
                    "--submodule-repetitions-y %(repsuby)s " \
                    "--submodule-repetitions-z %(repsubz)s " \
                    "--submodule-distance-x %(arraysubx)s " \
                    "--submodule-distance-y %(arraysuby)s " \
                    "--submodule-distance-z %(arraysubz)s " \
                    "--crystal-repetitions-x %(repcryx)s " \
                    "--crystal-repetitions-y %(repcryy)s " \
                    "--crystal-repetitions-z %(repcryz)s " \
                    "--crystal-distance-x %(arraycryx)s " \
                    "--crystal-distance-y %(arraycryy)s " \
                    "--crystal-distance-z %(arraycryz)s " \
                    "--energy-resolution-fwhm %(energyResolutionFWHM)s " \
                    "--doi-resolution-fwhm %(doiResolutionFWHM)s " \
                    "--time-resolution-fwhm %(timeResolutionFWHM)s " \
                    "--smeared-energy %(smearedEnergy)s " \
                    "--smeared-time %(smearedTime)s " \
                    "--smeared-doi %(smearedDoi)s " %parameters
    if parameters['fovRotation']:
        simToData_cmd += "--fov-rotation-axis %(fovRotationAxis)s " \
                         "--fov-rotation-angle %(fovRotationAngle)s " %parameters



    print simToData_cmd

    print ">>>Extracting points..."
    simToData_args = shlex.split(simToData_cmd)
    print simToData_args
    simToData = subprocess.Popen(simToData_args)
    listOfProcesses.append(simToData)
    simToData.wait()
    listOfProcesses.remove(simToData)

    dataset_cmd = pathToCmd
    dataset_cmd += "dataset " \
                  "-i %(pointsFile)s " \
                  "-o %(outputFile)s " \
                  "--inner-radius %(rmin)s " \
                  "--eff-steps  %(effSteps)s " \
                  "--energy-fwhm %(energyResolutionFWHM)s " \
                  "--rotation-angle %(rotationAngle)s " %parameters


    if parameters['binary'] == True:
        dataset_cmd += '--binary-output '

    if parameters['listmode'] == True:
        dataset_cmd += '--listmode-output '


    if parameters['nobackground'] == True:
        dataset_cmd += '--no-background '

    if parameters['stir'] == True:
        dataset_cmd += '--stir-output '

    print dataset_cmd
    print ">>>Generating elm2 files..."
    dataset_args = shlex.split(dataset_cmd)
    print dataset_args
    dataset = subprocess.Popen(dataset_args)
    listOfProcesses.append(dataset)
    dataset.wait()
    listOfProcesses.remove(dataset)


    #RECOSTRUCTION PART

    #first look for or produce sensitivity
    # elm2todkfz_cmd = "%(binPath)s/elm2todkfz -o %(lmf_name)s --randoms-file %(rand_acq)s " \
                        #  "--energy-low %(eMin)f --energy-high %(eMax)f " \
                        #  "--time-window %(dMax)f --scatter-total-events %(scatter_total_events_file)s " \
                        #  "%(cat_fifo)s" % fmt_params
    # recon_cmd = "nice -n 19 %(binPath)s/ClearPEM_LMRec -i %(lmf_name)s -o %(output_prefix)s " \
                    # " -d %(distance)f -n %(norm_prefix)s --pixel-length %(voxelSize)f " \
                    # " --rays %(rays)d " \
                    # " --iterations %(iterations)d --osem %(osem)d " \
                    # " --filter-fwhm %(ffwhm)f --filter-power %(fmp)d" % fmt_params
    # tmpDir = os.getcwd()
    # cat_fifo = join(tmpDir, "data.cat.fifo")
    # os.mkfifo(cat_fifo)
    #
    # lmf_name = join(tmpDir, "data.lm")
    # rand_acq = join(tmpDir, "rand_acq.lm")
    # rand_name = join(tmpDir, "rand_data.lm")
    # rand_combined = join(tmpDir, "rand_comb.lm")
    # lmf_name_corr = join(tmpDir, "data_corr.lm")
    # rand_combined_corr = join(tmpDir, "rand_corr.lm")
    # output_prefix = join(tmpDir, "data_img")
    # mesh_name = "tfinal_mesh.vtk" # mesh_name is hardcoded in MeshCreator
    # binPath = '/home/marco/Universita/Ideas/ComptonRecovery/listmode-reco/pem-sonic-tools'
    # distance = options.rmin * 2;
    # normalizationfile = "vvv"
    # prefix = join(tmpDir, "norm")
    # lmfName = prefix + '.lm.fifo';
    # NormCatFifo = join(tmpDir, "norm.cat.fifo")
    #
    # reco_params = {
    #   'enMin':                     parameters['enMin'],
    #   'enMax':                     parameters['enMax'],
    #   'dMax':                      parameters['dMax'],
    #   'sensitivityfile':           parameters['sensitivityfile'],
    #   'scatter_total_events_file': 'scatter_total.txt',
    #   'cat_fifo':                  cat_fifo,
    #   'NormCatFifo':               NormCatFifo,
    #   'lmf_name':                  lmf_name,
    #   'lmfName':                   lmfName,
    #   'binPath':                   binPath,
    #   'rand_acq':                  rand_acq,
    #   'output_prefix':             output_prefix,
    #   'distance':                  distance,
    #   'norm_prefix':               normalizationfile,
    #   'voxelSize':                 parameters['voxelSize'],
    #   'rays':                      parameters['rays'],
    #   'iterations':                parameters['iterations'],
    #   'osem':                      parameters['osem'],
    #   'ffwhm':                     parameters['ffwhm'],
    #   'fmp':                       parameters['fmp']
    # }
    #
    # if parameters['sensitivityfile'] == None:
    #     print 'No sensitivity provided, generating one...'
    #
    #     if parameters['normalizationfile'] == None:
    #         print 'ERROR: No normalization or sensitivity provided, you need to give at least one!'
    #         print 'Aborting...'
    #         os.remove(cat_fifo)
    #         return 1
    #     else:
    #         elm2Name = parameters['normalizationfile']
    #
    #         os.mkfifo(NormCatFifo)
    #         if elm2Name[len(elm2Name)-2:] == 'gz':
    #             catCmd = "pigz -d -c %(elm2Name)s > %(NormCatFifo)s" % locals()
    #         else:
    #             catCmd = "cat %(elm2Name)s > %(NormCatFifo)s" % locals()
    #         print catCmd
    #
    #
    #         os.mkfifo(lmfName);
    #         elm2todkfz_sens_cmd = "%(binPath)s/elm2todkfz --energy-low %(enMin)f --energy-high %(enMax)f "\
    #                               "--time-window %(dMax)f --use-direct-correction "\
    #                               "-o %(lmfName)s %(NormCatFifo)s" % reco_params
    #         print elm2todkfz_sens_cmd
    #
    #         normGenCmd = "nice -n 19 %(binPath)s/Norm_Total_Gen %(distance)f %(voxelSize)f %(anglesFileName)s "\
    #                     "--rays %(rays)d "\
    #                     "%(lmfName)s %(normPrefix)s" % reco_params
    #         os.remove(NormCatFifo)
    #         os.remove(lmfName)
    #         # cat = pexpect.spawn("sh -c '%s'" % catCmd)
    #
    # elm2todkfz_cmd = "%(binPath)s/elm2todkfz -o %(lmf_name)s --randoms-file %(rand_acq)s " \
    #                      "--energy-low %(enMin)s --energy-high %(enMax)s " \
    #                      "--time-window %(dMax)s --scatter-total-events %(scatter_total_events_file)s " \
    #                      "%(cat_fifo)s" % reco_params
    # recon_cmd = "nice -n 19 %(binPath)s/ClearPEM_LMRec -i %(lmf_name)s -o %(output_prefix)s " \
    #                 " -d %(distance)f -n %(norm_prefix)s --pixel-length %(voxelSize)f " \
    #                 " --rays %(rays)d " \
    #                 " --iterations %(iterations)d --osem %(osem)d " \
    #                 " --filter-fwhm %(ffwhm)f --filter-power %(fmp)d" % reco_params
    # print  elm2todkfz_cmd
    # print  recon_cmd
    # os.remove(cat_fifo)




if __name__ == '__main__':
    main(sys.argv)
