
class TwinSpecViewer : object
{
image profile	
number Cube1ID,Cube2ID,ProfileID,Sel_ID
number depth1,depth2,depth, FastPix
number List1,List2,ListP,ListW1,ListW2

image GetSpectrum(object self,image Cube,roi Select,number depth)
	{
	number top,left,bottom,right
	Select.ROIGetRectangle(top,left,bottom,right)
	
	if(bottom==top) exit(0)
	if(right==left) exit(0)
	
	image fragm = Cube[left,top,0,right,bottom,depth]
	return fragm.MSA112_Render3DtoPixel()/(bottom-top)/(right-left)
	}

void RemoveAll(object self)
	{
	image Cube1 := Cube1ID.FindImageByID()
	image Cube2 := Cube2ID.FindImageByID()
	imageDisplay imdisp1 = Cube1.ImageGetImageDisplay(0)
	imageDisplay imdisp2 = Cube2.ImageGetImageDisplay(0)
	imdisp1.ImageDisplayRemoveEventListener(List1)
	imdisp2.ImageDisplayRemoveEventListener(List2)
	if(Profile.ImageIsValid())
		{
		ImageDocument SpecDoc = ProfileID.GetImageDocumentByID()
		SpecDoc.ImageDocumentGetWindow().WindowRemoveWindowListener(ListP)
		}

	roi Sel = GetRoiFromID(Sel_ID)
	if(imdisp1.ImageDisplayDoesROIExist("Selection"+Sel_ID)) imdisp1.ImageDisplayDeleteROI(Sel)
	if(imdisp2.ImageDisplayDoesROIExist("Selection"+Sel_ID)) imdisp2.ImageDisplayDeleteROI(Sel)

	ImageDocument doc1 = Cube1.ImageGetOrCreateImageDocument()
	if(doc1.MSA112_CheckImageWindow()) 
		{
		DocumentWindow Win1 = doc1.ImageDocumentGetWindow()
		Win1.WindowRemoveWindowListener(ListW1)
		}
	ImageDocument doc2 = Cube2.ImageGetOrCreateImageDocument()
	if(doc2.MSA112_CheckImageWindow()) 
		{
		DocumentWindow Win2 = doc2.ImageDocumentGetWindow()
		Win2.WindowRemoveWindowListener(ListW2)
		}		
	}

void UpdateProfiles(object self,roi sel)
	{
	imageDisplay imDispP = Profile.ImageGetImageDisplay(0)
	imDispP{0}[0,0,1,depth1] = self.GetSpectrum(Cube1ID.FindImageByID(),Sel,depth1)
	imDispP{1}[0,0,1,depth2] = self.GetSpectrum(Cube2ID.FindImageByID(),Sel,depth2)
	}

void SetOneRoiAsTheOther(object self,roi RoiSource,number ImageDestID)
	{
	number top,left,bottom,right
	RoiSource.ROIGetRectangle(top,left,bottom,right)	
	if(bottom<=top) bottom=top+1
	if(right<=left) right =left+1
	ImageDestID.FindImageByID().ImageGetImageDisplay(0).ImageDisplayLookupROIByID(Sel_ID).ROISetRectangle(top,left,bottom,right)			
	}
		
void RoiChanged1(object self,number e_fl,imageDisplay imdisp,number r_fl,number r_fl2,ROI Sel1)
	{
//result("\nchanged "+e_fl+" "+r_fl+" "+r_fl2)
	if(ROIGetID(Sel1)==Sel_ID)//if(ROIGetLabel(Sel1)=="Y")
		{
		self.SetOneRoiAsTheOther(Sel1,Cube2ID)
		self.UpdateProfiles(sel1)
		}
	}

void RoiChanged2(object self,number e_fl,imageDisplay imdisp,number r_fl,number r_fl2,ROI Sel2)
	{
//result("\nchanged "+e_fl+" "+r_fl+" "+r_fl2)
	if(ROIGetID(Sel2)==Sel_ID)//if(ROIGetLabel(Sel2)=="Y")
		{			
		self.SetOneRoiAsTheOther(Sel2,Cube1ID)	
		self.UpdateProfiles(sel2)	
		}
	}

void RoiShifted1(object self,number e_fl,imageDisplay imdisp,number r_fl,number r_fl2,ROI Sel)
	{
	number top,left,bottom,right
	Sel.ROIGetRectangle(top,left,bottom,right)
//result("\n"+top+" "+left+" "+bottom+" "+right)	

	number e_fl,r_fl,r_fl2 
	if(((bottom-top)*(right-left) <= FastPix))  self.RoiChanged1(e_fl,imdisp,r_fl,r_fl2,Sel)
	}

void RoiShifted2(object self,number e_fl,imageDisplay imdisp,number r_fl,number r_fl2,ROI Sel)
	{
	number top,left,bottom,right
	Sel.ROIGetRectangle(top,left,bottom,right)
//result("\n"+top+" "+left+" "+bottom+" "+right)	

	number e_fl,r_fl,r_fl2 
	if(((bottom-top)*(right-left) <= FastPix))  self.RoiChanged2(e_fl,imdisp,r_fl,r_fl2,Sel)
	}
	
void RoiRemoved(object self,number e_fl,imageDisplay imdisp,number r_fl,number r_fl2,ROI Sel)
	{
	if(Sel.roiGetID()==Sel_ID)
		{
	self.RemoveAll()
		}
	}

void SpectrumRemoved(object self, number e_fl, DocumentWindow Win)
    {
    self.RemoveAll()
	}

void CubeRemoved(object self, number e_fl, DocumentWindow Win)
    {
	self.RemoveAll()
	}
	
void init(object self)
	{
result("\nTwinSpecViewer initialized")

	//check if there are two SI datacubes in front
	image Cube1,Cube2
	string Name1,Name2
	
	try{
		Cube2 := GetFrontImage()
		if(Cube2.ImageGetNumDimensions()!=3)
			{
			OkDIalog("3D spectrum-image should be in front !!")
			exit(0)
			}
		}
	catch
		{
		OkDIalog("spectrum-image should be in front !!")
		exit(0)
		}
	
	Cube1 := FindNextImage(Cube2)
	if(!Cube1.ImageIsValid())
		{
		OkDIalog("No back spectrum-image !!")
		exit(0)
		}
	
	if((Cube1.ImageGetNumDimensions()!=3)||(Cube2.ImageGetNumDimensions()!=3)) 
		{
		OkDIalog("Two 3D SI of the same width/height should be front most !!")
		exit(0)
		}
	Cube1ID = Cube1.ImageGetID()
	Cube2ID = Cube2.ImageGetID()
	Name1 = getName(Cube1)
	Name2 = getName(Cube2)
	
	//get windows
	DocumentWindow Win1 = Cube1.ImageGetOrCreateImageDocument().ImageDocumentGetWindow()
	DocumentWindow Win2 = Cube2.ImageGetOrCreateImageDocument().ImageDocumentGetWindow()
	
	//check compatibility of datacubes
	number width,height,width2,height2
	Cube1.get3DSize(width,height,depth1)
	Cube2.get3DSize(width2,height2,depth2)
	depth = max(depth1,depth2)	
//result("\n"+width+"x"+height+"x"+depth1+ "   "+width2+"x"+height2+"x"+depth2)
	if((width!=width2)||(height!=height2)) 
		{
		OkDIalog("Two spectrum-images of the same width/height should be front most !!")
		exit(0)
		}
	
	//set Fast Pixel value
	FastPix = 2048/depth*MSA112P_FastPixel() // GMS1: 6x6 pixels at 2048 Depth
	
	//check calibration
	number origin,disp,origin2,disp2
	string units,units2
	Cube1.ImageGetDimensionCalibration(2,origin,disp,units,1)
	Cube2.ImageGetDimensionCalibration(2,origin2,disp2,units2,1)
	if((disp!=disp2)||(units!=units2)) 
		{
		OkDIalog("Two front most spectrum images must have the same energy calibration !!")
		exit(0)
		}
	
	//setROI	
	roi Sel = NewRoi()
	Sel_ID = Sel.roiGetID()
	Sel.ROISetName("Selection"+Sel_ID)
result(" ID "+Sel_ID)

	number inileft = width/2, iniright = inileft+1
	number initop = height/2, inibottom = initop+1
	Sel.ROISetRectangle(initop,inileft,inibottom,iniright)
	Sel.ROISetColor(0,1,0)
	Sel.ROISetLabel("Y")
	
	imageDisplay imDisp1 = Cube1.ImageGetImageDisplay(0)
	imDisp1.ImageDisplayAddROI(Sel)
	imageDisplay imDisp2 = Cube2.ImageGetImageDisplay(0)
	imDisp2.ImageDisplayAddROI(Sel)
	
	//set ground spectrum
	Profile := realImage("Overlaid spectrum",4,depth,1)	
	Profile.ImageSetDimensionCalibration(0,origin,disp,units,1)
	Profile.showimage()
	
	//make overlaid of two spectra
	imageDisplay imDispP = Profile.ImageGetImageDisplay(0)
	image Profile2 = imageclone(Profile)
	Profile2.ImageSetDimensionCalibration(0,origin2,disp,units,1)
	ImageDisplaySetSliceLabelByID(imdispP,ImageDisplayGetSliceIDByIndex(imdispP,0),Name1)
	imdispP.imageDisplayAddImage(Profile2,Name2)
	
	//initial spectra
	self.UpdateProfiles(sel)

	//attach listeners
	imageDocument SpecDoc = getFrontImageDocument()
	ProfileID = SpecDoc.ImageDocumentGetID()
	DocumentWindow SpecWin = SpecDoc.ImageDocumentGetWindow()
	ListP = SpecWin.WindowAddWindowListener(self,"window_closed:SpectrumRemoved")
	ListW1 = Win1.WindowAddWindowListener(self,"window_closed:CubeRemoved")
	ListW2 = Win2.WindowAddWindowListener(self,"window_closed:CubeRemoved")
	string messageMap1 = "roi_removed:RoiRemoved;roi_end_track:RoiChanged1;roi_changed:RoiShifted1"
	string messageMap2 = "roi_removed:RoiRemoved;roi_end_track:RoiChanged2;roi_changed:RoiShifted2"
	List1 = imDisp1.ImageDisplayAddEventListener(self,messageMap1)
	List2 = imDisp2.ImageDisplayAddEventListener(self,messageMap2)	
	}
	
~TwinSpecViewer(object self) 
	{
	result("\nTwinSpectrumViewer destroyed")
	}
}

void createall()
{
alloc(TwinSpecViewer).init(); 
}

createall()