from mantid.simpleapi import *
import jsonArray
import time
import datetime
import json
import multiprocessing
from multiprocessing import Process, Manager
import numpy
import shutil

class moduleIO(multiprocessing.Process):
    def __init__(self, neonRedis, refreshtime, module, myDict, logger):
        super(moduleIO, self).__init__()

        self.refreshtime=refreshtime
        self.neonRedis_write=neonRedis
        self.neonRedis_read=neonRedis
        self.module=module
        self.logger=logger
        self.myDict=myDict
        self.confJudge=True
        self.neonpathDetValue="/GPPD/workspace/detector/"+self.module+"/value"
        self.neonpathDetPid="/GPPD/workspace/detector/"+self.module+"/pid"
        self.neonpathDetTof="/GPPD/workspace/detector/"+self.module+"/tof"
        self.neonpathDetSet="/GPPD/workspace/MantidData/"+self.module

    def get1Ddata(self, path):
        data=[]
        _json=self.neonRedis_read.get(path)
        while _json is None:
            self.logger.warning("no 1D data in "+path+str(datetime.datetime.now()))
            _json=self.neonRedis_read.get(path)
            time.sleep(20)
        data=jsonArray.jsonDecoder(_json)
        return data 

    def getDataFromNeon(self):
        self.detValue = []
        _json=self.neonRedis_read.get(self.neonpathDetValue)
        while _json is None:
            self.logger.warning("no 2D data in "+path+" "+str(datetime.datetime.now()))
            _json=self.neonRedis_read.get(path)
            time.sleep(10)
        #_array=jsonArray.jsonDecoder(_json)

        _array=jsonArray.jsonDecoder(_json)
        a=0
        for ix in _array:
            a=a+sum(ix)
            for iy in ix:
                self.detValue.append(iy)
        print self.module, " counts: ",a

    def createWorkspace(self):
        be=time.time()
        LoadCSNSRaw(OutputWorkspace=self.module, PixelID_bank=self.detPid, TimeOfFlight_bank=self.detTof, Counts_bank=self.detValue, PixelID_monitor=[0,1], TimeOfFlight_monitor=[0,16], Counts_monitor=[1,1])
        #self.logger.debug("finish saving nexus for"+self.module)
        #time.sleep(60)
        _instname=str("./instrument/module/"+self.module+".xml")
        LoadInstrument(Workspace=self.module+"_1", Filename=_instname, RewriteSpectraMap='True')    
        SaveNexus(InputWorkspace=self.module+'_1', Filename='./'+self.module+'.nxs')

        #LoadCalFile(InputWorkspace=self.module+'_1', CalFilename='./instrument/calfile.cal', WorkspaceName=self.module+'_GPPD')
        #AlignDetectors(InputWorkspace=self.module+'_1', OutputWorkspace=self.module+'_alignD', OffsetsWorkspace=self.module+'_GPPD_offsets')
        #Rebin(InputWorkspace=self.module+'_alignD', OutputWorkspace=self.module+'_rebin', Params='0.3,0.001,4')
        #DiffractionFocussing(InputWorkspace=self.module+'_rebin', OutputWorkspace=self.module+'_dfocus', GroupingWorkspace=self.module+'_GPPD_group')
        ConvertUnits(InputWorkspace=self.module+'_1', OutputWorkspace=self.module+'_dfocus', Target='dSpacing', EMode='Elastic', AlignBins = True)
        SumSpectra(InputWorkspace=self.module+'_dfocus', OutputWorkspace=self.module+'_dfocus')
        Rebin(InputWorkspace=self.module+'_dfocus', OutputWorkspace=self.module+'_dfocus', Params='0.1,0.001,4.2')
        ConvertUnits(InputWorkspace=self.module+'_dfocus', OutputWorkspace=self.module+'_tof', Target='TOF')
        
        #SumSpectra(InputWorkspace=self.module+'_1', OutputWorkspace=self.module+'_tof')
        Rebin(InputWorkspace=self.module+'_tof', OutputWorkspace=self.module+'_tof', Params='1000,32,35000')

    def reductionByMon(self):
        Load(Filename="./tmp/monitor2.nxs", OutputWorkspace="mon")
        #LoadNexus(Filename="./tmp/monitor2.nxs", OutputWorkspace="mon")
        ConvertUnits(InputWorkspace=self.module+'_1', OutputWorkspace=self.module+'_wave', Target='Wavelength', EMode='Elastic', AlignBins = True)
        Rebin(InputWorkspace=self.module+"_wave", OutputWorkspace=self.module+"_wave", Params='0.001,0.005,8')
        RebinToWorkspace(WorkspaceToRebin="mon", WorkspaceToMatch=self.module+"_wave", OutputWorkspace="mon")
        Divide(LHSWorkspace=self.module+"_wave", RHSWorkspace="mon", OutputWorkspace=self.module+"_ans", AllowDifferentNumberSpectra=True)

        ConvertUnits(InputWorkspace=self.module+'_ans', OutputWorkspace=self.module+'_ans_dfocus', Target='dSpacing', EMode='Elastic', AlignBins = True)
        SumSpectra(InputWorkspace=self.module+'_ans_dfocus', OutputWorkspace=self.module+'_ans_dfocus')
        #DiffractionFocussing(InputWorkspace=self.module+'_rebin', OutputWorkspace=self.module+'_dfocus', GroupingWorkspace=self.module+'_GPPD_group')
        Rebin(InputWorkspace=self.module+'_ans_dfocus', OutputWorkspace=self.module+'_ans_dfocus', Params='0.1,0.001,4.2')
        ConvertUnits(InputWorkspace=self.module+'_ans_dfocus', OutputWorkspace=self.module+'_ans_tof', Target='TOF')
        Rebin(InputWorkspace=self.module+'_ans_tof', OutputWorkspace=self.module+'_ans_tof', Params='1000,32,35000')
        

    def set1DdataToNeon(self,wsname, path1, path2):
        name=mtd[wsname]
        x=[]
        tmpx=[]
        v=[]
        v=name.readY(0)
        _tmp=name.readX(0)
        #v1=numpy.array(v)
        #v1[numpy.isnan(v1)]=0
        #v1[numpy.isinf(v1)]=0
        #if wsname == 'module422_dfocus':
        #    print wsname," ", sum(v)
        #    for ix in v:
        #        print ix
        #    print wsname, " ", sum(v1)
        #    for ix in v1:
        #        print ix
        #for ix in v:
        #    v1.append(ix)
        #v1=v
        #_tmp=name.readX(0)
        for j in range(len(_tmp)-1):
            x.append(_tmp[j]+(_tmp[j+1]-_tmp[j])/2)
        #print wsname
        #print 22222222222, v
        #for i in range(len(v1)):
            #if not numpy.isnan(v1[i]) and numpy.isfinite(v1[i]):
        #    if not numpy.isnan(v1[i]):
        #        pass
        #    else:
        #        v1[i]=0.0
        #print v
        #for i in range(len(v)):
            #if v[i] > 0:
                #print "888888888: ", self.module, "   " ,v[i], " ", i
        #    if numpy.isnan(v[i]) or numpy.isfinite(v[i]):
        #        v1.append(0)
        #    else:
        #        print 99999
        #        v1.append(v[i])
        #print v1        
        self.neonRedis_write.set(path1, jsonArray.jsonEncoder(x))
        self.neonRedis_write.set(path2, jsonArray.jsonEncoder(v))
        #self.neonRedis_write.set(path2, jsonArray.jsonEncoder(v1))
        #self.logger.warning("name: "+wsname+" length : "+str(len(x))+" "+str(len(v1)))
        #print jsonArray.jsonEncoder(x), path1
        #v=self.neonRedis_read.get(path2)
        #self.logger.warning("get data length: "+str(len(jsonArray.jsonDecoder(v))))
        self.logger.debug("finish set 1D data: "+path1)

    def setReductionDataToNeon(self, wsname, path1, path2):
        name=mtd[wsname]
        tmpv=name.readY(0)
        tmpx=[]
        _tmp=name.readX(0)
        for j in range(len(_tmp)-1):
            tmpx.append(_tmp[j]+(_tmp[j+1]-_tmp[j])/2)
        x=[]
        v=[]
        for ix in tmpv:
            v.append(ix)
        #print "1111111111111111",v
        #for i in range(len(tmpv)):
        #    if not numpy.isnan(tmpv[i]) and numpy.isfinite(tmpv[i]):
        #        x.append(tmpx[i])
        #        v.append(tmpv[i])
        #    else:
                #print v[i]
        #        pass
        #for i in range(len(v)):
        #    if not numpy.isnan(v[i]) and numpy.isfinite(v[i]):
                #pass
        #    else:
        #        v[i]=0
                #print v[i]
        
        #if len(v)== 0:
        #    for i in range(len(tmpv)):
        #        v.append(0)
        #    self.neonRedis_write.set(path1, jsonArray.jsonEncoder(tmpx))
        #    self.neonRedis_write.set(path2, jsonArray.jsonEncoder(v))
        #    self.logger.debug("set zero data for monitor reduciton")
        #else:
        self.neonRedis_write.set(path1, jsonArray.jsonEncoder(tmpx))
        self.neonRedis_write.set(path2, jsonArray.jsonEncoder(tmpv))
        #print "11111",len(v)
        #print jsonArray.jsonDecoder(self.neonRedis_write.get(path2))
            
        self.logger.debug("set data for monitor reduciton")

    def setXYData(self, x, yaxis, counts):
        vaxis=[[] for r in range(len(yaxis))]
        num=0
        for p in range(len(yaxis)):
            for q in range(len(x)):
                vaxis[p].append(counts[num])
                num=num+1
        self.neonRedis_write.set(self.neonpathDetSet+"/xy_image/x", jsonArray.jsonEncoder(x))
        self.neonRedis_write.set(self.neonpathDetSet+"/xy_image/y", jsonArray.jsonEncoder(yaxis))
        self.neonRedis_write.set(self.neonpathDetSet+"/xy_image/value", jsonArray.jsonEncoder(vaxis))
        #numpy.savetxt("/home/mantid/online/simpleV/xy_"+self.module+".txt", vaxis, "%d")

    def dataSet(self):
        self.set1DdataToNeon(self.module+"_dfocus", "/GPPD/workspace/MantidData/"+self.module+"/d","/GPPD/workspace/MantidData/"+self.module+"/intensity")
        #self.set1DdataToNeon(self.module+"_tof", "/GPPD/workspace/MantidData/"+self.module+"/tof","/GPPD/workspace/MantidData/"+self.module+"/counts")
        counts=[]
        xaxis=[]
        yaxis=[]
        zaxis=[]
        name=mtd[str(self.module+'_1')]
        for j in range(name.getNumberHistograms()):
            counts.append(sum(name.readY(j)))
            _det=name.getDetector(j)
            _pos=_det.getPos()
            xaxis.append(_pos.X())
            yaxis.append(_pos.Y())
            zaxis.append(_pos.Z())
        xaxis=list(set(xaxis))
        yaxis=list(set(yaxis))
        zaxis=list(set(zaxis))
        xaxis.sort()
        yaxis.sort()
        zaxis.sort()
        for i in range(len(yaxis)):
            yaxis[i]=yaxis[i]*1000
        for i in range(len(zaxis)):
            zaxis[i]=zaxis[i]*1000
        for i in range(len(xaxis)):
            xaxis[i]=xaxis[i]*1000
        mNum=int(self.module[6])
        if mNum==3 or mNum==4:
            self.setXYData(zaxis, yaxis, counts)
        else:
            self.setXYData(xaxis, yaxis, counts)
        self.logger.debug("set x,y value for all bank! "+self.module+" "+str(datetime.datetime.now()))
        DeleteWorkspace(Workspace=self.module)        
        #DeleteWorkspace(Workspace=self.module+"_dfocus")        
        #DeleteWorkspace(Workspace=self.module+"_tof")        
        #DeleteWorkspace(Workspace=self.module+"_GPPD_cal")        
        #DeleteWorkspace(Workspace=self.module+"_GPPD_offsets")        
        #DeleteWorkspace(Workspace=self.module+"_GPPD_mask")        
        #DeleteWorkspace(Workspace=self.module+"_GPPD_group")        

    def process(self):
        if self.myDict['configure']:
            if self.confJudge:
                self.detTof=[]
                self.detPid=[]
                try:
                    self.detPid=self.get1Ddata(self.neonpathDetPid)
                    self.detTof=self.get1Ddata(self.neonpathDetTof)
                except:
                    self.logger.error("no data in Pid and Tof in "+self.module)
                    self.myDict['error']=True
                    self.myDict['configure']=False
                #path.clearRedis(self.neonRedis_write)
                #self.logger.debug("finish new configuring for "+self.module)
                self.confJudge=False
            else:
                pass
        else:
            self.confJudge=True
        
        if self.myDict['running']:
            self.logger.debug("start running program for"+self.module)
            try:
                self.getDataFromNeon()
            except:
                
                self.myDict['error']=True
                self.myDict['running']=False
                self.logger.error("error in get data from neon!")
            path="/GPPD/workspace/MantidData/"+self.module+"/neutroncounts"
            self.neonRedis_write.set(path, json.dumps(sum(self.detValue)))
            while (len(self.detValue)!=(len(self.detTof)-1)*len(self.detPid)):
                self.logger.warning("data size doesn't match! please waiting...")
                time.sleep(10)
                if self.myDict['running']:
                    self.getDataFromNeon()
                else:
                    break
            if self.myDict['running']:
                try:
                    #self.logger.debug("   INFO: createWorkspace"+str(datetime.datetime.now()))
                    self.createWorkspace()
                except:
                    self.myDict['error']=True
                    self.myDict['running']=False
                    self.logger.error("error in create workspace!")
                #reduction
                #self.reductionByMon()
                if self.myDict['running']:
                    #try:
                    #self.logger.debug("   INFO: dataSet"+str(datetime.datetime.now()))
                    self.dataSet()
                    #set reduction data
                    #self.setReductionDataToNeon(self.module+"_ans_dfocus","/GPPD/workspace/MantidData/reduction/"+self.module+"/d","/GPPD/workspace/MantidData/reduction/"+self.module+"/intensity")
                    #self.set1DdataToNeon(self.module+"_ans_dfocus","/GPPD/workspace/MantidData/reduction/"+self.module+"/d","/GPPD/workspace/MantidData/reduction/"+self.module+"/intensity")
                    #value=self.neonRedis_read.get("/GPPD/workspace/MantidData/reduction/"+self.module+"/intensity")
                    #print 222222, len(jsonArray.jsonDecoder(value))
                    #print jsonArray.jsonDecoder(value)
                    #self.setReductionDataToNeon(self.module+"_ans_tof","/GPPD/workspace/MantidData/reduction/"+self.module+"/tof","/GPPD/workspace/MantidData/reduciton/"+self.module+"/counts")
                    #self.set1DdataToNeon(self.module+"_ans_tof","/GPPD/workspace/MantidData/reduction/"+self.module+"/tof","/GPPD/workspace/MantidData/reduction/"+self.module+"/counts")
                    shutil.move("./"+self.module+".nxs","./tmp/"+self.module+".nxs" )
                    self.logger.debug("finish "+self.module)
                    #except:
                    #    self.myDict['error']=True
                    #    self.myDict['running']=False
                    #    self.logger.error("error in set data!")
                else:
                    pass
            else:
                pass
        else:
            pass

    def run(self):
        while True:
            self.process()
            time.sleep(0.5)

