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

class monitorIO(multiprocessing.Process):
    def __init__(self, neonRedis, refreshtime, myDict, logger):
        super(monitorIO, self).__init__()
        self.refreshtime=refreshtime
        self.neonRedis_write=neonRedis
        self.neonRedis_read=neonRedis
        #self.monitorList=monitorList
        self.logger=logger
        self.myDict=myDict
        self.confJudge = True

    def get1Ddata(self,path):
        data=[]
        _json=self.neonRedis_read.get(path)
        data=jsonArray.jsonDecoder(_json)
        return data
 
    def get2Ddata(self, path):
        data=[]
        _json=self.neonRedis_read.get(path)
        _array=jsonArray.jsonDecoder(_json)
        for ix in _array:
            for iy in ix:
                data.append(iy)
        return data

    def createWorkspace(self):
        self.logger.debug(str(len(self.monPid))+" "+str(len(self.monTof))+" "+str(len(self.mon1Value)))
        LoadCSNSRaw(OutputWorkspace="monitor1", PixelID_bank=[0,1], TimeOfFlight_bank=[0,8], Counts_bank=[1,1], PixelID_monitor=self.monPid, TimeOfFlight_monitor=self.monTof, Counts_monitor=self.mon1Value)
        LoadInstrument(Workspace="monitor1_2", Filename='./instrument/monitor1.xml', RewriteSpectraMap='True')
        SaveNexus(InputWorkspace='monitor1_2', Filename='./monitor1.nxs')
        self.logger.debug(str(len(self.monTof))+" "+str(len(self.mon2Value)))
        LoadCSNSRaw(OutputWorkspace="monitor2", PixelID_bank=[0,1], TimeOfFlight_bank=[0,8], Counts_bank=[1,1], PixelID_monitor=[1], TimeOfFlight_monitor=self.monTof, Counts_monitor=self.mon2Value)
        LoadInstrument(Workspace="monitor2_2", Filename='./instrument/monitor2.xml', RewriteSpectraMap='True')
        SaveNexus(InputWorkspace='monitor2_2', Filename='./monitor2.nxs')
        self.logger.debug(str(len(self.monTof))+" "+str(len(self.mon3Value)))
        LoadCSNSRaw(OutputWorkspace="monitor3", PixelID_bank=[0,1], TimeOfFlight_bank=[0,8], Counts_bank=[1,1], PixelID_monitor=[2], TimeOfFlight_monitor=self.monTof, Counts_monitor=self.mon3Value)
        LoadInstrument(Workspace="monitor3_2", Filename='./instrument/monitor3.xml', RewriteSpectraMap='True')
        SaveNexus(InputWorkspace='monitor3_2', Filename='./monitor3.nxs')
        ConvertUnits(InputWorkspace='monitor2_2', OutputWorkspace='monitor2', Target='Wavelength')
        ConvertUnits(InputWorkspace='monitor3_2', OutputWorkspace='monitor3', Target='Wavelength')
	name1=mtd['monitor2_2']
	print "create workspace raw:", sum(name1.readY(0))
	
	name=mtd['monitor2']
	print "create workspace :", sum(name.readY(0))
	
    def setXYData(self):
        # set XY data
        xaxis=[]
        yaxis=[]
        counts=[]
        name=mtd["monitor1_2"]
        for j in range(name.getNumberHistograms()):
            det=name.getDetector(j)
            pos=det.getRelativePos()
            xaxis.append(pos.X())
            yaxis.append(pos.Y())
            counts.append(sum(name.readY(j)))
        xaxis=list(set(xaxis))
        yaxis=list(set(yaxis))
        xaxis.sort()
        yaxis.sort()
        for i in range(len(xaxis)):
            xaxis[i]=xaxis[i]*1000
        for i in range(len(yaxis)):
            yaxis[i]=yaxis[i]*1000

        vaxis=[[] for m in range(len(yaxis))]
        n=0
        for j in range(len(yaxis)):
            for k in range(len(xaxis)):
                vaxis[j].append(counts[n])
                n=n+1
        self.neonRedis_write.set("/SANS/workspace/MantidData/monitor1/xy_image/x",jsonArray.jsonEncoder(xaxis))
        self.neonRedis_write.set("/SANS/workspace/MantidData/monitor1/xy_image/y",jsonArray.jsonEncoder(yaxis))
        self.neonRedis_write.set("/SANS/workspace/MantidData/monitor1/xy_image/value",jsonArray.jsonEncoder(vaxis))
        self.logger.debug("set xy data for  monitor1 !!!")

    def setTofData(self, monitor):
        # set tof counts
        if monitor == "monitor1":
            SumSpectra(InputWorkspace='monitor1_2', OutputWorkspace="tofCounts", IncludeMonitors=True)
            name=mtd["tofCounts"]
        elif monitor == "monitor2":
	        name=mtd["monitor2_2"]
        elif monitor == "monitor3":
	        name=mtd["monitor3_2"]

        tof=[]
        counts=[]
        counts=name.readY(0)
        _tmp=name.readX(0)
        for j in range(len(_tmp)-1):
            tof.append(_tmp[j]+(_tmp[j+1]-_tmp[j])/2)
        self.neonRedis_write.set("/SANS/workspace/MantidData/"+monitor+"/tof", jsonArray.jsonEncoder(tof))
        self.neonRedis_write.set("/SANS/workspace/MantidData/"+monitor+"/counts", jsonArray.jsonEncoder(counts))
        self.logger.debug("set tof and counts data for "+monitor)

    def setWaveData(self, monitor):
        # set tof counts
        if monitor == "monitor1":
	    ConvertUnits(InputWorkspace='monitor1_2', OutputWorkspace='tmp_wave', Target='Wavelength', AlignBins=True)
            SumSpectra(InputWorkspace='tmp_wave', OutputWorkspace="waveCounts", IncludeMonitors=True)
            name=mtd["waveCounts"]
        elif monitor == "monitor2":
	    #ConvertUnits(InputWorkspace='monitor2_2', OutputWorkspace='tmp_wave', Target='Wavelength')
	    name=mtd["monitor2"]
        elif monitor == "monitor3":
	    #ConvertUnits(InputWorkspace='monitor3_2', OutputWorkspace='tmp_wave', Target='Wavelength')
	    name=mtd["monitor3"]

        wave=[]
        counts=[]
        counts=name.readY(0)
	#print counts
        _tmp=name.readX(0)
        for j in range(len(_tmp)-1):
            wave.append(_tmp[j]+(_tmp[j+1]-_tmp[j])/2)
        self.neonRedis_write.set("/SANS/workspace/MantidData/"+monitor+"/wavelength", jsonArray.jsonEncoder(wave))
        self.neonRedis_write.set("/SANS/workspace/MantidData/"+monitor+"/intensity", jsonArray.jsonEncoder(counts))
        self.logger.debug("set wave and counts data for "+monitor)

    def setTransData(self):
        SmoothData(InputWorkspace="monitor2",OutputWorkspace="mon2_smooth", NPoints=5)
        Rebin(InputWorkspace="mon2_smooth", OutputWorkspace="monitor22", Params='0.5, 0.01, 8')
        Rebin(InputWorkspace="monitor3", OutputWorkspace="monitor33", Params='0.5, 0.01, 8')
        name1=mtd["monitor22"]
        name2=mtd["monitor33"]
        v2=name1.readY(0)
        v3=name2.readY(0)
        self.neonRedis_write.set("/SANS/workspace/MantidData/tmp/counts1", jsonArray.jsonEncoder(v2))
        self.neonRedis_write.set("/SANS/workspace/MantidData/tmp/counts2", jsonArray.jsonEncoder(v3))
	vres=[]
	for i in range(len(v2)):
	    if(v2[i]==0):
		vres.append(v3[i])
	    else:
	    	vres.append(v3[i]/v2[i])


	#vres=v3/v2

        #imax=np.argmax(v2)
        #_v2=v2[imax:]
        #_v3=v3[imax:]
        #vres=np.zeros_like(_v2)
        #for i in range(len(_v2)):
	#        if _v2[i]==0:
	#    	    vres[i]=0
	#        else:
	#	        vres[i]=_v3[i]/_v2[i]
        #_max=vres[0]*1.3
        #for i in range(len(vres)):
	#        if vres[i]> _max: vres[i]=0
        #vres=vres.tolist()
        wave=[]
        _tmp=name1.readX(0)
        for j in range(len(_tmp)-1):
            wave.append(_tmp[j]+(_tmp[j+1]-_tmp[j])/2)
            #wave=wave[imax:]

        self.neonRedis_write.set("/SANS/workspace/MantidData/trans/wavelength", jsonArray.jsonEncoder(wave))
        self.neonRedis_write.set("/SANS/workspace/MantidData/trans/transmission", jsonArray.jsonEncoder(vres))
        self.logger.debug("set transmission!")

    def process(self):
        if self.myDict['configure']:
            if self.confJudge:
                self.monPid=[]
                self.monTof=[]
                try:
                    self.monPid=self.get1Ddata("/SANS/workspace/monitor1/pid")
                    self.monTof=self.get1Ddata("/SANS/workspace/monitor1/tof")
                except:
                    self.logger.error("no data in Pid and Tof in monitor")
                    self.myDict['error']=True
                    self.myDict['configure']=False

		path.clearRedis(self.neonRedis_write)
                self.logger.debug("finish configure")
                self.confJudge=False
            else:
                pass
        else:
            self.confJudge=True
	
        if self.myDict['running']:
            self.logger.debug("start running program for monitor")
            self.mon1Value=[]
            self.mon2Value=[]
            self.mon3Value=[]
            try:
                self.mon1Value=self.get2Ddata("/SANS/workspace/monitor1/value")
            except:
                self.logger.warning("no data for monitor1")
                npid=len(self.monPid)
                ntof=len(self.monTof)
                for i in range(npid*(ntof-1)):
                    self.mon1Value.append(0)
            try:
                self.mon2Value=self.get2Ddata("/SANS/workspace/monitor2/value")
                self.mon3Value=self.get2Ddata("/SANS/workspace/monitor3/value")
            except:
                self.logger.warning("no data for monitor1")
                for i in range(len(self.monTof)-1):
                    self.mon2Value.append(0)
                    self.mon3Value.append(0)
            self.neonRedis_write.set("/SANS/workspace/MantidData/monitor1/neutroncounts",json.dumps(sum(self.mon1Value))) 
            self.neonRedis_write.set("/SANS/workspace/MantidData/monitor2/neutroncounts",json.dumps(sum(self.mon2Value))) 
            self.neonRedis_write.set("/SANS/workspace/MantidData/monitor3/neutroncounts",json.dumps(sum(self.mon3Value))) 
            if (len(self.mon1Value)!=(len(self.monTof)-1)*len(self.monPid)):
                self.logger.warning("data size doesn't match!")
            else:
                if self.myDict['running']:
                    try:
                        self.createWorkspace()
                    #'''
                    except:
                        self.myDict['error']=True
                        self.myDict['running']=False
                        self.logger.error("error in create workspace")
                    #'''
                    if self.myDict['running']:
                        try:
                            self.logger.debug("   INFO: dataSet")
                            self.setXYData()
                        except:
                            self.myDict['error']=True
                            self.myDict['running']=False
                            self.logger.error("error in set xy data for monitor")
                        try:
                            self.setTofData("monitor1")
                            self.setTofData("monitor2")
                            self.setTofData("monitor3")
                        except:
                            self.myDict['error']=True
                            self.myDict['running']=False
                            self.logger.error("error in set tof counts data for monitor")
                        self.setWaveData("monitor1")
                        self.setWaveData("monitor2")
                        self.setWaveData("monitor3")
		        try:
			    shutil.move("./monitor1.nxs","./tmp/monitor1.nxs" )
			except:
			    self.logger.warning("no monitor1.nxs!!!")
			try:
			    shutil.move("./monitor2.nxs","./tmp/monitor2.nxs" )
			except:
			    self.logger.warning("no monitor2.nxs!!!")
			try:
			    shutil.move("./monitor3.nxs","./tmp/monitor3.nxs" )
			except:
			    self.logger.warning("no monitor3.nxs!!!")
                        #try:
                        self.setTransData()
			'''
                        except:
                            self.myDict['error']=True
                            self.myDict['running']=False
                            self.logger.error("error in set trans data for monitor")
			'''
                    else:
                        pass
                else:
                    pass
        else:
            pass

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

