/********************************************
Copyright Pavel Potapov, 2013-2016
distributed under GNU General Public License
********************************************/
	
/******************************************************************
class : STARTER
******************************************************************/
class BatchRecording112: UIFrame112
{
//image container
TagGroup ImList 	//image container
number N,lastM		//number of images and maximized images in container
number Xi,Xf,Yi,Yf,Wframe // container window borders
number SortState	//kind of sorting 1: sorted by creation time	2: sorted manually

//acquisition parameters
number tV,bV,zV	// View: acquisition, binning, zoom
number tR,bR,sR	// Record: acquisition, binning, zoom

//recording
number ccdWidth,ccdHeight	//camera dimensions

//live Search
number ViewID		//ID of live Search imageDocument
number KeyListener	//Key listener ID to be attached to live Search

//live FFT
number FFTID		//ID of FFT imageDocument

//zoom view
number ZoomID		//ID of Zoom ImageDocument
number zoom0,zoom,width0,height0
number ZoomMotherID, RoiID,ROIListenerID

//saving batch images
number dig 		//registers in storing images,e.g. dig = 2 means maximum 99 images



/*********************GRAPHICS***************/
image IView(object self,number size, number Bcgrd, number Rahm)
	{	
	image im:=integerImage("",1,0,size*1.5,size)
	im = Bcgrd
	
	im = tert(iradius<0.25*size,0,im)
	im = tert((iradius-irow)>0.1*size&&(iradius-irow)<0.3*size,0,im)
	im = tert((iradius+irow-size)>0.1*size&&(iradius+irow-size)<0.3*size,0,im)

	im[0,0,size,0.1*Size] = Bcgrd 
	im[0,size*1.45,size,1.5*Size] = Bcgrd 

	return self.IRahm(im,Rahm,Rahm,Bcgrd)
	}	

image IRecord(object self,number size, number Bcgrd, number Rahm)
	{
	image im:=integerIMage("",1,0,size*1.5,size)
	
	im = Bcgrd
	im[size*0.25,size*0.25,size*0.9,size*1.3]=0
	im[size*0.1,size*0.5,size*0.3,size*1.0]=0
	im= tert(iradius<0.2*size,Bcgrd,im)
	
	return self.IRahm(im,Rahm,Rahm,Bcgrd)
	}

image Isort(object self,number size, number Bcgrd, number Rahm)
	{	
	image im = self.Ibcgrd(size,Bcgrd)
	
	size /= 18
	im[0*size,0*size,6*size,2*size]=0
	im[4*size,0*size,6*size,6*size]=0
	
	im[0*size,6*size,10*size,8*size]=0
	im[8*size,8*size,10*size,12*size]=0

	im[0*size,12*size,14*size,14*size]=0
	im[12*size,12*size,14*size,18*size]=0
	
	return self.IRahm(im,Rahm,Rahm,Bcgrd)
	}

image IAnchor(object self, number size, number Bcgrd, number Rahm)	
	{
	image im = self.Ibcgrd(size,Bcgrd)

	im[0.1*size,0.45*Size,0.9*size,0.6*size] = 0
	im[0.2*size,0.3*Size,0.3*size,0.8*size] = 0
	im = tert((iradius>0.25*size)&&(iradius<0.4*size)&&(irow>0.6*size),0,im)	
	
	return self.IRahm(im,Rahm,Rahm,Bcgrd)
	}

image Imax(object self, number size, number Bcgrd, number Rahm)
	{
	number Outline = 2
	size -= 2*Outline
	image im = self.Ibcgrd(size,Bcgrd)	
	
	return self.IRahm(self.IRahm(im,Outline,Outline,0),Rahm,Rahm,Bcgrd)
	}
	
/****************needed to read/write items in pop-up list *********************/

number GetBinningFromList(object self,number BinningTable)
	{
	number Binning 
	if(BinningTable==1) Binning = 1
	if(BinningTable==2) Binning = 2
	if(BinningTable==3) Binning = 4
	if(BinningTable==4) Binning = 8
	
	return Binning
	}
	
number SetBinningInList(object self,number Binning)
	{
	number BinningTable
	if(Binning==1) BinningTable = 1
	if(Binning==2) BinningTable = 2
	if(Binning==4) BinningTable = 3
	if(Binning==8) BinningTable = 4
	
	return BinningTable
	}
	
number GetSizeFromList(object self,number SizeTable)
	{
	number Size
	if(SizeTable==1) Size = 4
	if(SizeTable==2) Size = 3
	if(SizeTable==3) Size = 2
	if(SizeTable==4) Size = 1
	
	return Size
	}
	
number SetSizeInList(object self,number Size)
	{
	number SizeTable 
	if(Size==4) SizeTable = 1
	if(Size==3) SizeTable = 2
	if(Size==2) SizeTable = 3
	if(Size==1) SizeTable = 4
	
	return SizeTable
	}

/*******************this creates tags for acquisition parameters***************/
	
TagGroup AcqParameters(object self,number &t,string tIdent,number bin,string bIdent)
	{
	TagGroup Parameters  = DLGCreateDialog("")
	Parameters.DLGTableLayout(1,2,0).DLGAnchor("West")
	
	Parameters.DLGAddElement(DLGCreateRealField(t,7,2).DLGIdentifier(tIdent))

	TagGroup BinItem
	Parameters.DLGAddElement(DLGCreatePopup(BinItem,self.SetBinningInList(bin)).DLGIdentifier(bIdent))
					BinItem.DLGAddPopupItemEntry("1")	//binning 1
					BinItem.DLGAddPopupItemEntry("2")	//binning 2
					BinItem.DLGAddPopupItemEntry("4")	//binning 4
					BinItem.DLGAddPopupItemEntry("8")	//binning 8		
	return Parameters
	}

TagGroup CreateCoupleInPanel(object self,TagGroup TG1,TagGroup TG2)
	{
	TagGroup Couple = DLGCreateDialog("").DLGTableLayout(1,2,0)//.DLGAnchor("West")
	Couple.DLGAddElement(TG1)
	if(TagGroupIsValid(TG2)) Couple.DLGAddElement(TG2)
	else Couple.DLGAddElement(DLGCreateGraphic(28,22))
	
	return Couple
	}



//DLG Tags	
TagGroup CreateDialog(object self,number bckg,string Batch)
	{
	TagGroup PanelUp = DLGCreateDialog("").DLGTableLayout(8,1,0).DLGAnchor("West")

	PanelUp.DLGAddElement(self.AcqParameters(tV,"tV",bV,"bV"))

		TagGroup Vbutton = self.Button112(self.Iview(23,bckg,4),"ViewImage").DLGIdentifier("View")
		TagGroup dummyTG 
	PanelUp.DLGAddElement(self.CreateCoupleInPanel(Vbutton,dummyTG))
	
		TagGroup Zbutton = self.Button112(self.GraphicFromString("zoom",12,"",1,bckg),"ZoomImage")	
		TagGroup FFTbutton = self.Button112(self.GraphicFromString("  FFT ",12,"",1,bckg),"FFTimage")	
	PanelUp.DLGAddElement(self.CreateCoupleInPanel(Zbutton ,FFTbutton))
	
		TagGroup Kbutton = self.Button112(self.Iplus(12,bckg,4),"AddImages")
		TagGroup Sbutton = self.Button112(self.Imax(12,bckg,4),"MaximizeAll")
	PanelUp.DLGAddElement(self.CreateCoupleInPanel(Kbutton ,Sbutton ))
	
		TagGroup Abutton = self.Button112(self.Ianchor(18,bckg,1),"UpdateIniLastPositions")
		TagGroup Obutton = self.Button112(self.Isort(18,bckg,1),"ReFresh")
	PanelUp.DLGAddElement(self.CreateCoupleInPanel(Abutton ,Obutton))
	
		TagGroup Hbutton = self.Button112(self.GraphicFromString("resort",12,"",1,bckg),"SortByHand")	
		TagGroup Tbutton = self.Button112(self.GraphicFromString("initial",12,"",1,bckg),"SortByTime")	
	PanelUp.DLGAddElement(self.CreateCoupleInPanel(Hbutton ,Tbutton))
	
		TagGroup Rbutton = self.Button112(self.IRecord(23,bckg,4),"SnapShot").DLGIdentifier("Record")
		TagGroup ZoomItem
		TagGroup ZoomList = DLGCreatePopup(ZoomItem,self.SetSizeInList(sR),"ChangedSize").DLGIdentifier("sR")
					ZoomItem.DLGAddPopupItemEntry("A")	//size 4 (maximal)
					ZoomItem.DLGAddPopupItemEntry("B")	//size 3
					ZoomItem.DLGAddPopupItemEntry("C")	//size 2	
					ZoomItem.DLGAddPopupItemEntry("D")	//size 1 (minimal)
	PanelUp.DLGAddElement(self.CreateCoupleInPanel(Rbutton ,ZoomList))
	
	PanelUp.DLGAddElement(self.AcqParameters(tR,"tR",bR,"bR"))
			
	
	TagGroup PanelDown = DLGCreateBox("").DLGTableLayout(3,1,0).DLGAnchor("West")
	PanelDown.DLGAddElement(DLGCreateStringField(Batch,48).DLGIdentifier("BatchName"))
	PanelDown.DLGAddElement(DLGCreatePushButton("save", "SaveBatch").DLGAnchor("East"))
	PanelDown.DLGAddElement(DLGCreatePushButton("open", "OpenBatch").DLGAnchor("East"))

	TagGroup Dialog = DLGCreatedialog("")	
	Dialog.DLGAddElement(PanelUp)
	Dialog.DLGAddElement(PanelDown)

	return Dialog
	}
	
//change size of image window	
void ResizeAndDisplayImage(object self,imagedocument imdoc,number sizeR)
	{
	//size R	:	1,2,3,4
	image im:= imdoc.ImageDocumentGetImage(0)
	
	number Width =im.ImageGetDimensionSize(0)
	number desiredZoom = (sizeR/4)*(1024/Width)
			//For 1024x1024 image, size 4 means zoom 1
	number Zoom = SetDesiredZoom112(imdoc,desiredZoom)
//result(" desired zoom "+desiredZoom + " adapted "+Zoom)	
	}

//Find the image window width for given size (nneded only at first lunch)
number FindImageWindowWidth(object self,number sizeR)
	{
	if(ccdWidth==0) return 600		//No microscope control detected
									//600 is more or less reasonable image window width
	image test := integerimage("",1,0,ccdWidth,ccdWidth)
	test.showimage()
	imagedocument imdoc = test.imageGetOrCreateImageDocument()
	documentwindow Win = imdoc.ImageDocumentGetWindow()
	
	self.ResizeAndDisplayImage(imdoc,sizeR)		
	number width,height
	win.WindowGetFrameSize(width,height)
//result("\nWidth "+WIdth)
	
	test.deleteImage()

	return width
	}	

//Initialization	
void init(object self,number digP, number Bcgrd, string Package, string HeadName)
	{	
	dig = digP
	
	//check if this is off-line DigitalMicrograph
	number OffLine
	try {CCDWidth=ExecuteScriptString("number W; number H;SSCgetSize(W,H);exit(W)");}
	catch {	
			result("\nWARNING: Camera is not found\nThis is probably off-line system");
			result("\nConsider installation of 'temDm virtualTEM'")
			OffLine=1;
			break;
			}
	if(!ccdWidth==0) 
		{
		try {CCDHeight=ExecuteScriptString("number W; number H;SSCgetSize(W,H);exit(H)");}
		catch {break;}
result("\nccd camera "+ccdWidth+"x"+CCDHeight)
		}
	
	self.SetPackageName(Package)	//this is needed for right path of loaded parameters
	tV = self.LoadNumber112(0.1,"View:exposure")
	bV = self.LoadNumber112(4,"View:binning")
	tR = self.LoadNumber112(0.5,"Record:exposure")
	bR = self.LoadNumber112(1,"Record:binning")
	sR = self.LoadNumber112(2,"Record:size")
	
	//initialize UIFrame112
	self.initUIFrame112(self.CreateDialog(Bcgrd,HeadName),Package,"Starter")

	//disable acquisition button when off-line
	if(offLine)
		{
		self.SetElementIsEnabled("View",0)
		self.SetElementIsEnabled("Record",0)
		}
		
	//create image container
	ImList = NewTagList()
	Wframe = self.LoadNumber112(0,"Container width")
	if(Wframe==0) Wframe = self.FindImageWindowWidth(sR)	//derive from image size
	self.LoadRect112(Yi,Xi,Yf,Xf,0,0,0,0,"Container area")
	if((Xi==0)&&(Yi==0)&&(Xf==0)&&(Yf==0))
		{ 
		//set dafault container position
		DLGBuildPositionFromApplication().taggroupGetTagAsShortRect("Reference",Yi,Xi,Yf,Xf)
		}
result("\nXY ("+Yi+","+Xi+")->("+Yf+","+Xf+")"+" width "+Wframe)		

	}

//store all parameters when UIFrame112 is closed; clean up listeners
number AboutToCloseUIFrame112( object self, number verify )
	{	
	//store acquisition parameters
	tV = self.LookUpElement("tV").DLGGetValue()
	bV = self.GetBinningFromList(self.LookUpElement("bV").DLGGetValue() )
	tR = self.LookUpElement("tR").DLGGetValue()
	bR = self.GetBinningFromList(self.LookUpElement("bR").DLGGetValue() )
	sR = self.GetSizeFromList(self.LookUpElement("sR").DLGGetValue() )

	self.StoreNumber112(tV,"View:exposure")
	self.StoreNumber112(bV,"View:binning")
	self.StoreNumber112(tR,"Record:exposure")
	self.StoreNumber112(bR,"Record:binning")
	self.StoreNumber112(sR,"Record:size")

	//store container area
	self.StoreRect112(Yi,Xi,Yf,Xf,"Container area")
	self.StoreNumber112(Wframe,"Container width")
result("\nXY ("+Yi+","+Xi+")->("+Yf+","+Xf+")"+" width "+Wframe)
	
	//remove key handler from liveView image if exist
	ImageDocument docV = ViewID.getImageDocumentByID()
	if(docV.ImageDocumentIsValid())
		{
		try
			{	
			imagedisplay dispV = docV.ImageDocumentGetImageModeDisplay()
			dispV.ImageDisplayRemoveKeyHandler(KeyListener)
result("\nKeyhandler removed")
			}
			catch{break;}
		}
		
	//check if there are images in container
	if(N>0)
		{
		OKDialog("there are still image(s) in the list\nthey will NOT be deleted  but\nImager cannot manage them anymore") 
		number ID,IDL
		for(number i=(N-1);i>=0;i--)
			{
			try
				{
				ImList.TagGroupGetTagAsLong("["+i+"]:ID",ID)
				ImList.TagGroupGetTagAsLong("["+i+"]:IDL",IDL)
				documentWindow Win = GetImageDocumentByID(ID).ImageDocumentGetWindow()
//result("\ni "+i+" ID "+ID+" IDL " +IDL)
				Win.WindowRemoveWindowListener(IDL)
				ImList.TagGroupDeleteTagWithIndex(i)
				}
			catch
				{
				result("\nWarning: Could not proper clean image container !!")
				return 0
				}
			}
		}
	
	return 1
	}
	

/************** Methods to manupulate images in container ********************/	

//access ImageDocument of given index in container
imageDocument GetFromList(object self,number index)
	{
	number ID
	ImList.TagGroupGetTagAsLong("["+index+"]:ID",ID)
	
	return GetImageDocumentByID(ID)
	}

//get window top,left positions and width of ImageDocument of given index in container
void GetWindowPositionByIndex(object self,number index,number &X,number &Y,number &Width,number &Height)
	{
	imageDocument imdoc = self.GetFromList(index)
	
	if(imdoc.CheckImageWindow112()) 
		{
		documentwindow Win = imdoc.ImageDocumentGetWindow()
		
		number top,left,bottom,right
		win.WindowGetFrameBounds(top,left,bottom,right)
		X = left
		Y = top
		Width = right-left
		Height = bottom-top
		}
	else {X=0;Y=0;Width=0;Height=0;}
	}

//update position of FIRST (Xi,Yi) and LAST image in container (Xf,Yf)	 
void UpdateIniLastPositions	(object self) 
	{
	number Width,Height
	if(N>0)self.GetWindowPositionbyIndex(0,Xi,Yi,Width,Height) //left-upper corner
	if(N>1)
		{
		number X,Y
		self.GetWindowPositionbyIndex(N-1,X,Y,Width,Height)
result("\nXf "+Xf+" Yf "+Yf +" Width "+Width+ "HeighgetWindowFromImageDisplay112t "+Height)
		if(X>Xi) Xf = X + Width		//right-lower corner of first image
		if(Y>Yi) Yf = Y + Height	//right-lower corner of last image
		
		Wframe = Width
		}
result("\nXi "+Xi+" Yi "+Yi+" Xf "+Xf+" Yf "+Yf +" Width "+Wframe)
	}

//return the total number of images in container
number GetNumberImages(object self) return N

//return the number of maximized images in container
number GetNumberOpenImages(object self)
	{
	number M = 0
	for(number i=0;i<N;i++)
		{
		imagedocument imdoc	= self.GetFromList(i)	
		if(imdoc.CheckImageWindow112())
			{
			if(imdoc.ImageDocumentGetWindow().WindowGetViewState()==0) M++	
			}
		}
		
//result("\nM "+M)
	return M
	}

//set the positions of all images in container as a cascade from FIRST to LAST images		
void ReFresh(object self) 
	{
	//if Shift key pressed, the method just select FIRST image in container
	if(N>1) if(ShiftDown()) 
		{
		self.GetFromList(0).ImageDocumentGetWindow().WindowSelect()
		exit(0)	//No refreshig proceed
		}

	//if Space key pressed, the method just select FIRST image in container
	if(N>1) if(OptionDown()) 
		{
		self.GetFromList(N-1).ImageDocumentGetWindow().WindowSelect()
		exit(0)	//No refreshig proceed
		}

	//Refreshing positions
//result("\nrefresh XY ("+Yi+","+Xi+")->("+Yf+","+Xf+")")
	number M = self.GetNumberOpenImages()
	
	if(M>1)
		{	
		//refresh positions of all maximized images
		number j=0
		number k=0
		for(number i=0;i<N;i++)
			{
			imagedocument imdoc = self.GetFromList(i)
			if(imdoc.CheckImageWindow112())
				{			
				documentWindow Win = imdoc.ImageDocumentGetWindow()

				number wW,wH
				Win.WindowGetFrameSize(wW,wH)
				number winRatio = wH/wW
				
				if(win.WindowGetViewState()==0) //only maximized image
					{
					self.ResizeAndDisplayImage(imdoc,sR)
					number x = Xi+(Xf-Wframe-Xi)*j/(M-1)
					number y = Yi+(Yf-Wframe*winRatio-Yi)*j/(M-1)
					j++
					Win.WindowSetFramePosition(x,y)
					Win.WindowSelect()
					}
				else 
					{
					ImList.TagGroupSetTagAsLong("["+i+"]:Manu",10**dig+k)
					//minimized images removed to the very end of list
					k++
					}
				}	
			}	
		}
	}

//maximize all minimized images in container
void MaximizeAll(object self)
	{		
	for(number i=0;i<N;i++)
		{
		imagedocument imdoc = self.GetFromList(i)
		if(imdoc.CheckImageWindow112())
			{
			documentWindow Win = imdoc.ImageDocumentGetWindow()

			if(win.WindowGetViewState()!=0) win.WindowSetViewState(0);
			}
		}			
	}

//resort images in container according their rang stored in "position" array	
TagGroup ResortImList(object self,TagGroup IniList,image position)
	{
	TagGroup FinList = NewTagList()

	number minpos,dummy
	for(number i=0;i<N;i++)
		{
		min(position,minpos,dummy)
		TagGroup CurrTg
		TagGroupGetIndexedTagAsTagGroup(IniList,minpos,CurrTg)
		TagGroupAddTagGroupAtEnd(FinList,CurrTg)
		position.setPixel(minpos,0,infinity())
		}
		
	return FinList
	}

//Time code is one number created from the time tags (needed to order images by creation time)	
number GenerateTimeCode(object self,image im)	
	{
	string TimeString,DateString
	GetStringNote(im,"DataBar:Acquisition Date",DateString)
	GetStringNote(im,"DataBar:Acquisition Time",TimeString)
	
	number d2 = ReadStringWithDeliminator112(DateString,"/").val()	//12/15/2015
	number d3 = ReadStringWithDeliminator112(DateString,"/").val()
	number d1 = ReadStringWithDeliminator112(DateString,"/").val()
	d1 -= 2000

	number t1 = ReadStringWithDeliminator112(TimeString,":").val()	//2:23:28 PM
	number t2 = ReadStringWithDeliminator112(TimeString,":").val()
	number t3 = ReadStringWithDeliminator112(TimeString," ").val()
	number  t0
	if(DateString=="PM") t0 = 1
	else t0 = 0

	number code = t3+t2*60+t1*3600+t0*43200+d3*86400+d2*2678400+d1*32140800

	return code
	}
	
number  AddToList(object self,imagedocument imdoc)
	{
	if(!imdoc.ImageDocumentIsValid()) return 0
	
	number NewID = ImageDocumentGetID(imdoc)
	string NewName = imdoc.ImageDocumentGetImage(0).ImageGetName()
//result("\nimdocID "+newID)

	//check if the image already exsists in the container
	number exist = 0
	for(number i=0;i<N;i++)
		{
		number ID
		string name
		ImList.TagGroupGetTagAsLong("["+i+"]:ID",ID)
		//check if image with such ID is already in container
		if(ID==NewID)			
			{
			exist = 1	
			break
			}
		//check if image with same Name is already in container
		if(NewName!="Frame")	//This name may be repeated
			{	
			if(NewName==ID.GetImageDocumentByID().ImageDocumentGetImage(0).ImageGetName())
				{	
				exist = 1	
				break
				}	
			}
		}
	
	//actually add		
	if(exist==0)
		{
		imdoc.ImageDocumentsetDoIntegralZoom(0) //images in container must have Integral zoom	
		
		self.ResizeAndDisplayImage(imdoc,sR)	//images must have specified size
	
		//add image in container
		TagGroup tg = NewTagGroup()
		tg.TagGroupSetTagAsLong("ID",NewID)
		documentWindow Win = ImageDocumentGetWindow(imdoc)
		tg.TagGroupSetTagAsLong("IDL",win.WindowAddWindowListener(self,"window_closed:OneWindowClosed;"))
		tg.TagGroupSetTagAsLong("Time",self.GenerateTimeCode(imdoc.ImageDocumentGetImage(0)))
		tg.TagGroupSetTagAsLong("Manu",N)
		TagGroupAddTagGroupAtEnd(ImList,tg)	
		N++
		
		//set position of new image
		if(N>1) Win.WindowSetFramePosition(Xf-Wframe,Yf-Wframe)
		else Win.WindowSetFramePosition(Xi,Yi)

		//refresh positions of all images
		self.reFresh()
		}
	else return 0
	
	SortState = 1	//Sorting by Time
	
	return 1
	}

//add extra images (that were not recorded by this tool) to container	
void AddImages(object self )
	{
	if(ControlDown())	//add all opened images in DM
		{
		for(number i=0;i<countimagedocuments();i++)
			{
			imageDocument imdoc = getImageDocument(i)
			string preName=ImageDocumentGetName(imdoc)
result("\n"+i+" image document "+imdoc.ImageDocumentGetID())

			//such images are forbidden to add
			if((!(preName=="View"))&&(!(preName=="FFT of View"))&&(!(preName=="Live FFT of View")))
			
				{
				//only maximized images are added
				if(imdoc.ImageDocumentGetWindow().WindowGetViewState()==0)
					{
					if(self.AddToList(imdoc)) result(" added")			
					}
				}	
			}
		}
	else self.AddToList(GetFrontImageDocument())	//add frontmost image
	}

//place one image in container to given position	
void MoveImage(object self,number index,number X,number Y,number lowerCorner)
	{
	imageDocument imdoc = self.GetFromList(index)
	if(imdoc.CheckImageWindow112())
		{
		documentWindow Win = imdoc.ImageDocumentGetWindow()

		if(lowercorner==1)	//here position is interpreted as lower-right corner
				{			//instead of standard upper-left one
				number wW,wH
				Win.WindowGetFrameSize(wW,wH)
				X -= wW
				Y -= wH
				}
		Win.WindowSetFramePosition(X,Y)
		}
	}

//remove image from container	
void RemoveFromList(object self,imagedocument imdoc)
	{
	number DocID = ImageDocumentGetID(imdoc)
	
	//find image in container
	number index = (-1) 	//if it stays negative -> no such image in container
	for(number i=0;i<N;i++)
		{
		number ID
		ImList.TagGroupGetTagAsLong("["+i+"]:ID",ID)
		if(ID==DocID) index = i
		}
		
	if(index>=0)
		{
		//remove listener
		if(imdoc.CheckImageWindow112())
			{
			DocumentWindow win = ImageDocumentGetWindow(imdoc)
			number IDL 
			if(ImList.TagGroupGetTagAsLong("["+index+"]:IDL",IDL))
				{
				win.WindowRemoveWindowListener(IDL)	
				}
			}
			
		//clean position in list
		ImList.TagGroupDeleteTagWithIndex(index)
		N--

		//auto-move only 1st or last image in container
		if(imdoc.ImageDocumentGetWindow().WindowGetViewState()==0)
			{
			if(index==0) self.MoveImage(0,Xi,Yi,0)		
			if(index==N) if(N>1) self.MoveImage(N-1,Xf,Yf,1)		
			}
		}
	}	
	
//check if the specified size fit the total DM area	
number OverSizedWindow(object self,number Ci,number Cf,number Width)
	{
	if(Cf<(Ci+Width)) return 1
	else return 0
	}

//change the size of displayed images	
void ChangedSize(object self,taggroup ListItem)
	{
	//load new size from UIFrame
	number sRnew = self.GetSizeFromList(ListItem.DLGGetValue())
	
	number Width
	number OverSized = 0
	if(N>0)
		{	
		//check oversize using the first image in container
		imageDocument imdoc = self.GetFromList(0)
		self.ResizeAndDisplayImage(imdoc,sRnew)
		number X,Y,height
		self.GetWindowPositionbyIndex(0,X,Y,width,height) 	//learn new width, heigh assumed same 
		OverSized = self.OverSizedWindow(Xi,Xf,width)		//check if oversized in X
		OverSized = self.OverSizedWindow(Yi,Yf,height)
//result("\nwidth "+width+" Xf "+Xf+" oversized "+OverSized)
		if(OverSized) self.ResizeAndDisplayImage(imdoc,sR)	//restore 1st image
		}
	else
		{
		//check oversize using  image derived from camera size
		width = self.FindImageWindowWidth(sRnew)	
		OverSized = self.OverSizedWindow(Xi,Xf,width)
		OverSized = self.OverSizedWindow(Yi,Yf,width)
		}

	if(!OverSized)
			{
			sR = sRnew	//accept new size
			Wframe = Width	//accept new width
			}
		else  	
			{
			//reject new size
			self.LookUpElement("sR").DLGValue(self.SetSizeInList(sR))
			throw("Initial and final positions do not allow such image size !!")							
			}
			
	//resize existing images	
	if(N>0)
		{		
		for(number i=0;i<N;i++)
			{
			imagedocument imdoc = self.GetFromList(i)
			self.ResizeAndDisplayImage(imdoc,sR)
			}	
		
		self.Refresh()
		}	
	}


//change the rang of images according their current positions
void Rearrange(object self )
	{
	number YtoX = (Yf-Yi)/(Xf-Xi)	//Y/X ratio of the whole container area
	image location := integerimage("",2,0,N,1)	//this array stores location rangs of images	
	number T,L //actual top,left of the image window
	for(number i=0;i<N;i++)
		{
		ImageDocument imdoc = self.GetFromList(i)
		if(imdoc.CheckImageWindow112())
			{
			documentWindow Win = imdoc.ImageDocumentGetWindow()
			win.WindowGetFramePosition(L,T)
				
//result("\n"+T+" "+L)				
			location.setPixel(i,0,L+YtoX*T) //rang of each window is calculated
			}
		}
	
	//rang of images is set as natural number in tags
	number j=0			
	for(number i=0;i<N;i++)
		{
		number minLoc,dummy 
		location.min(minLoc,dummy)
		ImList.TagGroupSetTagAsLong("["+minLoc+"]:Manu",j)	//manually resorted
		location.setPixel(minLoc,0,infinity())
		j++
		}
		
result("\nrearranged")	
	}


//General method; can be appended byTime,/byHand	
void SortBy(object self,string ByWhat )	
	{
//result("\nsort N "+N)
	if(N>1)
		{
		image position := integerimage("",4,0,N,1)
		for(number i=0;i<N;i++)
			{
			number Code
			ImList.TagGroupGetTagAsLong("["+i+"]:"+ByWhat,Code)
//result("\ni "+i+" code "+code)
			//buld sorting array
			position.setPixel(i,0,Code)	
			}
			
		ImList = self.ResortImList(ImList,position)
		
		self.ReFresh()
		}
	}

//Sorting by Time	
void SortByTime(object self )
	{

	if(SortState==1) {self.SortBy("Time");}
	
	SortState = 0	//ordered by creation time
	}

//Sorting by Hand	
void SortByHand(object self )
	{
	if(SortState==0) {self.SortBy("Manu");}
	else {self.Rearrange();self.SortBy("Manu");}
	
	SortState = 1	//ordered by manual resorting
	}

//action if one window in container closed	
void OneWindowClosed(object self, number e_fl, DocumentWindow Win)
    {
    self.RemoveFromList(ImageWindowGetImageDocument(Win))  
    }


//Start live Search from Camera Menu	
void ViewImage(object self )
	{
	//read desired exposure and binning and set them in CameraManager tags
	tV = self.LookUpElement("tV").DLGGetValue()
	bV = self.GetBinningFromList(self.LookUpElement("bV").DLGGetValue())
	setCameraBinning112("View","Search",bV)
	setCameraExposure112("View","Search",tV)
	
	//Choose Command from Menu
	ChooseMenuItem("Camera","","Search")
	ImageDocument docV = getImageDocumentByTitle112("View")
	ViewID = docV.ImageDOcumentGEtID()
	documentWindow winV = docV.ImageDocumentGetWindow()
	imagedisplay dispV = docV.ImageDocumentGetImageModeDisplay()
	
	//wrap imagedocument to Frame112
	alloc(Frame112).initFrame112(docV,self.GetPackageName(),"LiveView")
	
	//add key listener
	KeyListener = dispV.ImageDisplayAddKeyHandler(self, "KeyShortcut" )	
	}

//Create live FFT of Frontmost image
void FFTImage(object self )
	{	
	imageDocument FFTdoc = FFTID.GetImageDocumentByID()
	if(!FFTdoc.CheckImageWindow112()) 
		{
		ImageDocument imdoc = GetFrontImageDocument()
		
		//create live FFT from Frontmost image
		FFTdoc = CreateFFTfromImageDocument112(imdoc)
		FFTID = FFTdoc.ImageDocumentGetID()
		
		//wrap it into ChildFrame112
		if(!alloc(ChildFrame112).initChildFrame112(FFTdoc,imdoc,self.GetPackageName(),"FFT")) throw("Cannot build live FFT !!")
		}
	else FFTdoc.ImageDocumentGetWindow().WindowSelect()
		//if FFT already exists, just select it
		//only one FFT at a given time is allowed
	}


//action in response of changed zoom area
void ZoomAreaChanged(object self, roi theroi)
	{
	//get zoom area
	number top,left,bottom,right
	roiGetRectangle(theROI,top,left,bottom,right)

	//ensure correct rectangular
	if((bottom-top)<=0) bottom=top+1
	if((right-left)<=0) right=left+1

	//change zoom if ROI too small / too large
	if((zoom*(bottom-top)<zoom0*height0*0.75)&&(zoom*(right-left)<zoom0*width0*0.75)) zoom *= 2
	if((zoom*(bottom-top)>zoom0*height0*1.5)&&(zoom*(right-left)>zoom0*width0*1.5))  zoom /= 2

	//in ViewCoord, reduced by zoom
	number topV =top/zoom
	number leftV =left/zoom
	number bottomV =bottom/zoom
	number rightV =right/zoom
	number HightV = (bottom-top)*zoom
	number WidthV = (right-left)*zoom
	
	imageDocument Zoomdoc = ZoomID.GetImageDocumentByID()
	ZoomDoc.ImageDocumentGetWindow().WindowSetContentSize(WidthV,HightV)

	ZoomDoc.ImageDocumentShow()
	ZoomDoc.ImageDocumentSetRectInView(topV,leftV,bottomV,rightV,0,0,HightV,WidthV)
	ZoomDoc.imageDocumentGetImage(0).setZoom(zoom)	
	}

//Create live zoom  of Frontmost image	
void ZoomImage(object self )
	{	
	imageDocument Zoomdoc = ZoomID.GetImageDocumentByID()
	if(!ZoomDoc.CheckImageWindow112())
		{
		//get Front (assumedly live) image and set all its dependies
		imageDocument imdoc = getFrontImageDocument()
		if(!imdoc.ImageDocumentIsvalid()) exit(0)
		ZoomMotherID = imdoc.ImageDocumentGetID()
		documentWindow imwin = imdoc.ImageDocumentGetWindow()
		image im := imdoc.ImageDocumentGetImage(0)
		imagedisplay imdisp = im.ImageGetImageDisplay(0)
		
		//set width,height and zoom of source image
		im.getSize(width0,height0)
		zoom0 = im.getZoom()
		
		//make initial ROI
		ROI theRoi = NewROI()
		RoiID = ROIgetID(theRoi)
		number width,height
		im.getSize(width,height)
		ROIsetRectangle(theRoi,height*3/8,width*3/8,height*5/8,width*5/8) 	
		imdisp.ImageDisplayAddROI(theRoi)
		theRoi.ROISetVolatile(0)
		theRoi.ROISetColor(0,1,0)
		theRoi.ROISetLabel("zoom")
	
		//prepare zoom document
		ZoomDoc =	NewImageDocument("")
		ZoomID = ZoomDoc.ImageDocumentGetID()
		ImageDocumentShow(ZoomDoc) 
		ImageDocumentAddImage(ZoomDoc,im)  //same live image as in imDoc
		ImageDocumentSwitchToImageMode(ZoomDoc,im.ImageGetImageDisplay(0))
		
		//initiate zoom as a childFrame112 from imdoc
		if(!alloc(ChildFrame112).initChildFrame112(ZoomDoc,imdoc,self.GetPackageName(),"Zoom")) exit(0)

		//set initial zoom for zoomed image
		zoom = 4*zoom0
		SetDesiredZoom112(ZoomDoc,Zoom)
		self.ZoomAreaChanged(theROI)
		
		//add ROI listener
		string RoiListener //this is dummy
		documentWindow ZoomWin = ZoomDoc.ImageDocumentGetWindow()	
		ConnectObject(RoiID,"changed",RoiListener,self,"ZoomAreaChanged")
		
		//add listener for closing zoom window
		ROIListenerID = ZoomWin.WindowAddWindowListener(self,"window_closed:ClosedZoomWindow")
		}
	//No action if Zoom aleady exist
		//only one Zoom is allowed at a given time
	}

//clean up when Zoom window is closed
void ClosedZoomWindow(object self, number e_fl, DocumentWindow Win)
	{	//fired many times after single closing
	
	//disconnect ROI listener
	Win.WindowRemoveWindowListener(ROIListenerID)
	
	//delete ROI if exists
	imagedocument imdoc = ZoomMotherID.GetImageDocumentByID()
	imagedisplay imdisp = imdoc.ImageDocumentGetImageModeDisplay()

	try{ImageDisplayDeleteROI(imdisp,GetROIFromID(RoiID));}
	catch{break;} 
	}


//recording image from Tool	
void SnapShot(object self )
	{
	//read desired exposure and binning 
	tR = self.LookUpElement("tR").DLGGetValue()		//update parameters from starter
	bR = self.GetBinningFromList(self.LookUpElement("bR").DLGGetValue())
	sR = self.GetSizeFromList(self.LookUpElement("sR").DLGGetValue())
	
result("\nRecord: exposure "+tR+" binning "+bR)
	image im:= Record112(tR,bR,CCDWidth)
	im.showimage()
	
	//create imageDocument and add it to the container
	imagedocument imdoc = im.ImageGetOrCreateImageDocument()
	self.AddToList(imdoc)	
	}

//Shortcut added to the live Search	
//act only when live Search window is frontmost !!
number 	KeyShortcut(object self, ImageDisplay disp, object key) 
	{
	number done = 0
	
	//CNTR hold causes restart of stopped live view
	if (key.MatchesKeyDescriptor("control")) //restart paused acquisition
		{
		ChooseMenuItem("Camera","",RestartMenu112())
		done = 1
		}
	
	//when looking at live view image, SHIFT click causes snapshot 	
	if (key.MatchesKeyDescriptor("shift")) 	//snapshot is trigered by Shift
		{	
		self.SnapShot()	
		done = 1
		}	
	
	//return live Search image in front
	DocumentWindow winV = disp.getWindowFromImageDisplay112()
	winV.WindowSelect()

	return done	
	}



/*******************saving and opening batch***********************/

//This save all images in the container under the bach headname appending consequential number
void SaveBatch(object self ) 
	{
	if(N>0)
		{
		string BatchName = self.LookUpElement("BatchName").DLGgetStringValue()
		number FolderChosen = 0
		string FileName, directoryName,Folder,SeqNum

		//scroll throught container
		for(number i=0;i<N;i++)
			{
			imageDocument imdoc = self.GetFromList(i)

			fileName = BatchName+"-"+SequentialNumber112(i,dig)
			
			//user choice of folder
			if(FolderChosen==0)
				{
				if(!SaveAsDialog("choose folder", FileName, directoryName) ) exit(0)
				Folder=left(DirectoryName,len(directoryName)-len(FileName))
				FolderChosen = 1
				if(DoesFileExist(directoryName+".dm3")) if(!OKcancelDialog("Files with such name already exist!!\nOverwrite?")) exit(0)
				}
			
			//saving	
			SetName(ImageDocumentGetImage(imdoc,0),FileName)	
			SaveAsGatan(ImageDocumentGetImage(imdoc,0),Folder+FileName)	
result("\nimage "+FileName+ " saved")			
			}
		}
	}


//open one image from file and put it into container
number OpenOneImage(object self,string name)
	{
	//output number 	1 - opened and added to the container 
	//					0 - not valid dm file
	//					-1 - opened but not added to container because alredy there
	string ext = PathExtractExtension(name,0)

	if((ext == "dm3")||(ext == "dm4"))  //only dm files are opened
		{
		image im := openimage(Name)
		if(!self.AddToList(im.ImageGetOrCreateImageDocument())) 
			{
			deleteimage(im)	
			return (-1)
			}
		else return 1
		}
		
	return 0
	}

//opening all appropriated files in folder when clicking one file from the batch	
void OpenBatch(object self )
	{
	string full
	//choose one file that belongs to the batch
	if (!OpenDialog(full)) exit(0);
	string path = full.PathExtractDirectory(0)
	string name = full.PathExtractFileName(0)

	//check if this satisfy the batch name format ("HeadName-01","HeadName-02",...)
	string BatchName = ExtractBatchName112(name,dig)
	if(BatchName == "X") {OKdialog("This does not seem to be a batch !!");exit(0);}
	
	//open all files belonging to the batch
    TagGroup tg,tagi 
    tg = GetFilesInDirectory(path,3)
    number NoFiles = tg.TagGroupCountTags()
	for (number i=0; i<NoFiles; i++)
		{
		tg.TagGroupGetIndexedTagAsTagGroup(i,tagi)
		if(tagi.TagGroupGetTagAsString("Name",name)) 
			{
			if(ExtractBatchName112(name,dig) == BatchName) 
				{
				number success = self.OpenOneImage(path+name)
				if(success==1) result("\nimage "+name+" opened")
				if(success==0) result("\n"+name+" ignored")
				if(success==(-1)) result("\nimage "+name+ " already in list")
				}
			}
		}	
	
	//set batch HeadName
	self.LookUpElement("BatchName").DLGValue(BatchName)	
	}

	
}

//safely lunch BatchRecorder		
void CreateAll()  
{
//check if there is a tag about the nice background level to display UIFrame
string lab = "_temDM-Scripts"
number Bcgrd 
if(!getPersistentNumberNote(lab+":"+"background",Bcgrd ))
	{
	Bcgrd = 210 //default background
	}


string Package = "_temDM-Scripts:BatchRecording"
string HeadName = "HeadName"
alloc(BatchRecording112).init(2,Bcgrd,Package,HeadName);		
}

CreateAll()


