	FUNCTION GET_VDS_WIN, DEW, MODE, ERRMSG=ERRMSG
;+
; Project     :	SOHO - CDS
;
; Name        :	GET_VDS_WIN()
;
; Purpose     :	Calculate VDS windows from data windows
;
; Explanation :	This procedure takes a desired data extraction window list, and
;		calculates the corresponding VDS window list.  The VDS window
;		list will depend on the VDS readout mode.  In the standard
;		readout mode, all VDS windows are in the first quadrant, and
;		are reflected into all other quadrants.
;
;		Any overlapping data windows are merged together in the
;		resulting VDS window list.  Also, no matter how may data
;		windows are passed, a maximum of 10 VDS windows will be
;		returned.
;
; Use         :	VDSWIN = GET_VDS_WIN( DEW, MODE )
;
; Inputs      :	DEW	= Integer array of dimensions (N,4) where N is the
;			  number of data extraction windows, and the second
;			  dimension has the meaning:
;
;				(Xstart, Ystart, Xlength, Ylength)
;
;		MODE	= VDS readout mode, i.e.
;
;				1	Full quadrature readout (A,B,C,D)
;				2	Readout through quadrants A,D only
;				3	Readout through quadrants B,C only
;				4	Readout through quadrant A only
;				5	Readout through quadrant B only
;				6	Readout through quadrant C only
;				7	Readout through quadrant D only
;
; Opt. Inputs :	None.
;
; Outputs     :	The result of the function is an array of dimensions (M,4)
;		where M is the number of calculated VDS windows, and the second
;		dimension has the same meaning as in the input array.
;
; Opt. Outputs:	None.
;
; Keywords    :	ERRMSG	= If defined and passed, then any error messages will
;			  be returned to the user in this parameter rather than
;			  depending on the MESSAGE routine in IDL.  If no
;			  errors are encountered, then a null string is
;			  returned.  In order to use this feature, ERRMSG must
;			  be defined first, e.g.
;
;				ERRMSG = ''
;				Result = GET_VDS_WIN(DEW,MODE,ERRMSG=ERRMSG)
;				IF ERRMSG NE '' THEN ...
;
; Calls       :	None.
;
; Common      :	None.
;
; Restrictions:	This routine assumes that all data extraction windows are
;		valid, although some may have zero widths.
;
; Side effects:	None.
;
; Category    :	Planning, Technical.
;
; Prev. Hist. :	None.  However, influenced by TP_FIRST_QUAD by C. D. Pike.
;
; Written     :	William Thompson, GSFC, 3 January 1995
;
; Modified    :	Version 1, William Thompson, GSFC, 3 January 1995
;		Version 2, William Thompson, GSFC, 17 May 1996
;			Force windows to go across entire CCD
;
; Version     :	Version 2, 17 May 1996
;-
;
	ON_ERROR, 2
;
;  Check the number of input parameters.
;
	MESSAGE = ''
	SZ = SIZE(DEW)
	IF N_PARAMS() NE 2 THEN BEGIN
		MESSAGE = 'Result = GET_VDS_WIN( DEW, MODE )'
		GOTO, HANDLE_ERROR
	ENDIF
;
;  Check the input array.
;
	IF (SZ(0) NE 2) OR (SZ(2) NE 4) THEN BEGIN
		MESSAGE = 'Input array must have dimensions (N,4)'
		GOTO, HANDLE_ERROR
	ENDIF
;
;  Check the readout mode.
;
	IF N_ELEMENTS(MODE) NE 1 THEN BEGIN
		MESSAGE = 'MODE must be a scalar'
		GOTO, HANDLE_ERROR
	ENDIF
;
	IF (MODE NE FIX(MODE)) OR (MODE LT 1) OR (MODE GT 7) THEN BEGIN
		MESSAGE = 'MODE must be 1, 2, 3, 4, 5, 6, or 7'
		GOTO, HANDLE_ERROR
	ENDIF
;
;  If the input array has any zero-length elements, then ignore them.
;
	W = WHERE((DEW(*,2) GT 0) AND (DEW(*,3) GT 0), COUNT)
	IF COUNT EQ 0 THEN RETURN,INTARR(1,4)
	WIN = DEW(W,*)
;
;  Convert the window list into the format (Xfirst, Yfirst, Xlast, Ylast).
;
	WIN(0,2) = WIN(*,0) + WIN(*,2) - 1
	WIN(0,3) = WIN(*,1) + WIN(*,3) - 1
;
;  Force each window to go across the entire CCD.
;
	WIN(*,0) = 0
	WIN(*,2) = 1023
;
;  Depending on the VDS readout mode, reflect the windows into the appropriate
;  quadrants, and split apart any windows that cross quadrant boundaries.
;  Unless the readout mode is through a single quadrant, one needs to reflect
;  windows from bottom to top.
;
	IF MODE LT 4 THEN BEGIN
;
;  Step through all the windows.  Don't use a FOR loop because the number of
;  windows might change.
;
		N_WINDOWS = N_ELEMENTS(WIN)/4
		I = 0
		WHILE I LT N_WINDOWS DO BEGIN
;
;  First check to see if the window needs to be split.
;
			IF (WIN(I,1) LE 511) AND (WIN(I,3) GE 512) THEN BEGIN
				NEW_WIN = WIN(I,*)
				WIN(I,3) = 511
				NEW_WIN(1) = 512
				IF I EQ (N_WINDOWS - 1) THEN BEGIN
					WIN = [WIN(0:I,*),NEW_WIN]
				END ELSE BEGIN
					WIN = [WIN(0:I,*),NEW_WIN,WIN(I+1:*,*)]
				ENDELSE
				N_WINDOWS = N_ELEMENTS(WIN)/4
			ENDIF
;
;  Reflect the window if necessary.
;
			IF WIN(I,1) GE 512 THEN BEGIN
				SAVE_WIN = WIN(I,*)
				WIN(I,0) = 1023 - SAVE_WIN(2)
				WIN(I,1) = 1023 - SAVE_WIN(3)
				WIN(I,2) = 1023 - SAVE_WIN(0)
				WIN(I,3) = 1023 - SAVE_WIN(1)
			ENDIF
			I = I + 1
		ENDWHILE
	ENDIF
;
;  Only in full quadrature readout mode does one need to reflect windows right
;  to left.
;
	IF MODE EQ 1 THEN BEGIN
		N_WINDOWS = N_ELEMENTS(WIN)/4
		I = 0
		WHILE I LT N_WINDOWS DO BEGIN
;
			IF (WIN(I,0) LE 511) AND (WIN(I,2) GE 512) THEN BEGIN
				NEW_WIN = WIN(I,*)
				WIN(I,2) = 511
				NEW_WIN(0) = 512
				IF I EQ (N_WINDOWS - 1) THEN BEGIN
					WIN = [WIN(0:I,*),NEW_WIN]
				END ELSE BEGIN
					WIN = [WIN(0:I,*),NEW_WIN,WIN(I+1:*,*)]
				ENDELSE
				N_WINDOWS = N_ELEMENTS(WIN)/4
			ENDIF
;
			IF WIN(I,0) GE 512 THEN BEGIN
				SAVE_WIN = WIN(I,*)
				WIN(I,0) = 1023 - SAVE_WIN(2)
				WIN(I,2) = 1023 - SAVE_WIN(0)
			ENDIF
			I = I + 1
		ENDWHILE
	ENDIF
;
;  Find any overlapping windows and merge them.  Step through each window in
;  turn and find any windows that overlap it.
;
CHECK_OVERLAP:
	I = 0
	N_WINDOWS = N_ELEMENTS(WIN)/4
	WHILE I LT (N_WINDOWS-1) DO BEGIN
		W = WHERE((WIN(I,0) LE WIN(I:*,2)) AND	$
			  (WIN(I,2) GE WIN(I:*,0)) AND	$
			  (WIN(I,1) LE WIN(I:*,3)) AND	$
			  (WIN(I,3) GE WIN(I:*,1)), COUNT) + I
;
;  If overlapping windows were found, then find the window that includes all
;  the overlapping window.
;
		IF COUNT GT 1 THEN BEGIN
			WIN(I,0) = MIN(WIN(W,0))
			WIN(I,1) = MIN(WIN(W,1))
			WIN(I,2) = MAX(WIN(W,2))
			WIN(I,3) = MAX(WIN(W,3))
;
;  Remove the overlapping windows from the list, and start checking again from
;  the beginning.
;
			WIN(W(1:*),2) = -1
			W = WHERE(WIN(*,2) GE 0)
			WIN = WIN(W,*)
			N_WINDOWS = N_ELEMENTS(WIN)/4
			I = 0
;
;  Otherwise, if no overlapping windows were found, then try the next window.
;
		END ELSE I = I + 1
	ENDWHILE
;
;  If the number of windows is greater than 10, then find the two closest
;  windows (i.e. the two windows that would take the least amount of extra
;  pixels to merge) and merge them.
;
	IF N_WINDOWS GT 10 THEN BEGIN
		I1 = 0
		I2 = 0
		N_EXTRA = 1024L^2
;
;  Step through each pair of windows, and calculate the number of pixels that
;  would be added by merging them.  If the number is smaller than the
;  previously found minimum, then save the indices into I1 and I2.
;
		FOR I = 0,N_WINDOWS-2 DO BEGIN
			FOR J = I+1,N_WINDOWS-1 DO BEGIN
				N1 = (WIN(I,2)-WIN(I,0)+1L) *		$
					(WIN(I,3)-WIN(I,1)+1L) +	$
				     (WIN(J,2)-WIN(J,0)+1L) *		$
					(WIN(J,3)-WIN(J,1)+1L)
				X1 = WIN(I,0) < WIN(J,0)
				Y1 = WIN(I,1) < WIN(J,1)
				X2 = WIN(I,2) > WIN(J,2)
				Y2 = WIN(I,3) > WIN(J,3)
				N2 = (X2-X1+1L) * (Y2-Y1+1L)
				IF N_EXTRA GT (N2 - N1) THEN BEGIN
					N_EXTRA = N2 - N1
					I1 = I
					I2 = J
				ENDIF
			ENDFOR
		ENDFOR
;
;  Merge the closest pair found, and check for overlaps again.
;
		WIN(I1,0) = WIN(I1,0) < WIN(I2,0)
		WIN(I1,1) = WIN(I1,1) < WIN(I2,1)
		WIN(I1,2) = WIN(I1,2) > WIN(I2,2)
		WIN(I1,3) = WIN(I1,3) > WIN(I2,3)
		IF I2 EQ (N_WINDOWS-1) THEN WIN = WIN(0:I2-1,*) ELSE	$
			WIN = [WIN(0:I2-1,*),WIN(I2+1:*,*)]
		GOTO, CHECK_OVERLAP
	ENDIF
;
;  Change the window list back into the format (Xstart,Ystart,Xlength,Ylength)
;  and return.
;
	WIN(0,2) = WIN(*,2) - WIN(*,0) + 1
	WIN(0,3) = WIN(*,3) - WIN(*,1) + 1
	RETURN, WIN
;
;  Handle any errors encountered.
;
HANDLE_ERROR:
	IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
		ERRMSG = MESSAGE
		RETURN, INTARR(1,4)
	ENDIF ELSE MESSAGE, MESSAGE
;
	END

