pro PLOOP, data, data2, data3, data4, $
	wait = wait, bounce = bounce, count = count, trim = trim, $
	xrange = xrange, yrange = yrange, loud = loud, verb = verb, $
	cx = cx, cy = cy, cerase = cerase, _extra = extra
	
;+ 
;
; Wrapper for plot_image to do image sequences. Lightweight routine for viewing
; movies or images
;
; INPUTS:
;	data	-	A 2D or 3D array of image data
;	data2	-	[OPTIONAL] A second array with the same dimensions as data. If
;				passed in, then the two are plotted in separate boxes in the same
;				window, frame by frame
;	data3, 4-	[OPTIONAL] Third and fourth arrays with the same dimensions as
;				data. If passed in, then a 2x2 matrix of movies is shown in the 
;				output window. Note that it won't let you only pass in three
;				arrays, it must be 1, 2 or 4
;
; KEYWORDS:
;	wait	-	can set to a delay time (in sec) between frames (to slow it down)
;	/bounce	-	if set, then it bounces back when it hits the end of the movie;
;				by default it wraps around. (In step mode it always wraps instead
;				of bouncing)
;	/trim	-	if set, then missing data are excluded
;	xrange/yrange	-	Set to indicate the pixel range to show
;	/loud	-	Print some instructions before running the movie
;	/verb	-	Same as /loud
;
;	/count	-	if set, then the frame number is printed on the screen with xyouts
;	cx, cy	-	Normalized X and Y coordinates of the frame counter in the window
;	/cerase	-	Set if the frame counter is outside of the image area and thus 
;				needs to be erased each time it is rewritten
;	csize	-	character size of the frame counter (default is 2)
;
;	_extra	-	pass through to plot_image. Especially consider using:
;	 	min		-	minimum data value (stops it from rescaling it frame by frame)
;		max		-	maximum data value (stops it from rescaling it frame by frame)
;
;		/nosquare-	if set, then the X and Y dimensions are not constrained
;				to be the same scale; by default, they are
;
; COMMITTED: PB 2014/05/01
;
;-

; Check out keywords and set defaults
if N_ELEMENTS(wait) eq 0 then wait = 0
if N_ELEMENTS(bounce) eq 0 then bounce = 0
if KEYWORD_SET(verb) then loud = 1
if not KEYWORD_SET(loud) then loud = 0
if not KEYWORD_SET(cerase) then cerase = 0
if not KEYWORD_SET(cx) then cx = 0.15
if not KEYWORD_SET(cy) then cy = 0.15
if not KEYWORD_SET(csize) then csize = 2

; Initialize some variables
oldpmulti = !p.multi
imsize = SIZE(data)
i = 0					;	Loop counter 
idx = 0					;	Frame ID to display (related to i)
stopit = 0				;	0/1 for keep going/exit on next repeat
dir = 0					;	0/1 for forwards/backwards
stepmode = 0			;	0/1 for run/step through images

; Check out the dimensions of the input array
if KEYWORD_SET(trim) then begin
	if imsize[0] gt 2 then imtot = TOTAL(data, 3) else imtot = data
	goodpoints = WHERE(imtot eq imtot, numgood)
	if numgood le 0 then RETURN
	xs = goodpoints mod imsize[1]
	ys = goodpoints / imsize[1]
	xlim = LIMITS(xs)
	ylim = LIMITS(ys)
endif else begin
	xlim = [0, imsize[1]-1]
	ylim = [0, imsize[2]-1]
endelse
if KEYWORD_SET(xrange) then xlim = xrange
if KEYWORD_SET(yrange) then ylim = yrange

; Display the first frame
if N_PARAMS() gt 1 then begin
	; run through image cubes on top of each other
	if N_ELEMENTS(data2) ne N_ELEMENTS(data) then BOX_MESSAGE, 'PLOOP: Both inputs should have same dimensions'
	case N_PARAMS() of
		2	:	!p.multi = [0, 1, 2]
		4	:	!p.multi = [0, 2, 2]
	endcase
	PLOT_IMAGE, data[xlim[0]:xlim[1],ylim[0]:ylim[1],idx], origin = [xlim[0], ylim[0]], $
		_extra = extra
	PLOT_IMAGE, data2[xlim[0]:xlim[1],ylim[0]:ylim[1],idx], origin = [xlim[0], ylim[0]], $
		_extra = extra
	if N_PARAMS() gt 2 then begin
		PLOT_IMAGE, data3[xlim[0]:xlim[1],ylim[0]:ylim[1],idx], origin = [xlim[0], ylim[0]], $
			_extra = extra
		PLOT_IMAGE, data4[xlim[0]:xlim[1],ylim[0]:ylim[1],idx], origin = [xlim[0], ylim[0]], $
			_extra = extra
	endif
endif else begin
	PLOT_IMAGE, data[xlim[0]:xlim[1],ylim[0]:ylim[1],idx], origin = [xlim[0], ylim[0]], $
		_extra = extra
endelse

; If the input is just a 2D image, then we're done here
if imsize[0] eq 2 then begin
	!p.multi = oldpmulti
	RETURN
endif

; Display instructions for looping through data
if loud then begin
	BOX_MESSAGE, ['PLOOP:', 'Use right / left arrow keys to step forward/backwards', $
		'Use down / up arrow keys to run forward/backwards', $
		'Press any other key to exit']
endif

; Input is 3D, so start looping through the data
while not stopit do begin
	PLOT_IMAGE, data[xlim[0]:xlim[1],ylim[0]:ylim[1],idx], /noerase, $
		origin = [xlim[0], ylim[0]], _extra = extra
	if N_PARAMS() gt 1 then PLOT_IMAGE, data2[xlim[0]:xlim[1],ylim[0]:ylim[1],idx], $
		origin = [xlim[0], ylim[0]], /noerase, _extra = extra
	if N_PARAMS() gt 2 then begin
		PLOT_IMAGE, data3[xlim[0]:xlim[1],ylim[0]:ylim[1],idx], /noerase, $ 
			origin = [xlim[0], ylim[0]], _extra = extra
		PLOT_IMAGE, data4[xlim[0]:xlim[1],ylim[0]:ylim[1],idx], /noerase, $ 
			origin = [xlim[0], ylim[0]], _extra = extra
	endif
	; Print a frame counter. 
	if KEYWORD_SET(count) then begin
		if (N_ELEMENTS(oldidx) gt 0) and (cerase eq 1) then $
			XYOUTS, size = csize, /norm, cx, cy, oldidx, col = 0
		XYOUTS, size = csize, /norm, cx, cy, idx
		oldidx = idx
	endif
	kb_inp = STRLOWCASE(GET_KBRD(stepmode, /key_name))
	case kb_inp of 
		''		:	begin			;	If in run mode and no key pressed, keep playing
			i = i + (1 - 2 * dir)
			if bounce then begin	;	Check if you need to switch directions
				if	( (dir eq 1) and (i eq 0) ) or $
					( (dir eq 0) and (i eq (imsize[3]-1)) ) $
					then dir = (dir + 1) mod 2
			endif
		end
		'left'	:	begin
			stepmode = 1
			i = i - 1
		end
		'right'	:	begin
			stepmode = 1
			i = i + 1
		end
		'up'	:	begin
			stepmode = 0
			i = i - 1
			dir = 1
		end
		'down'	:	begin
			stepmode = 0
			i = i + 1
			dir = 0
		end
		else	:	stopit = 1
	endcase
	idx = (( (i mod imsize[3]) + (imsize[3]-1) ) mod imsize[3])
	if wait then WAIT, wait
endwhile

!p.multi = oldpmulti

end

