;This GUI displays FUV or NUV/SJI images and the user can select up to
;8 readout regions. These regions are automatically mirrored to show
;what will be read out and the readout time is printed. The numbers
;display x0,x1,y0,y1 of the boxes.
;Use:
;IDL> iris_regions,/fuv
;or
;IDL>iris_regions,/nuv
;
;Features:
;- will merge regions if closer than 100 pix (on full frame)
;- will notify if region > 2048
;- will notify if region crosses CCD border
;- will notify if ROI crosses other ROI
;Limitations
;- does not include checks on pixel counts (divisible by 16), allowed
;  start/end rows/columns. Use the tablecreator to create CRS from the
;  box coordinates given here.
;- the 8 regions can be anywhere in NUV/SJI, unlike for real OBS where
;  NUV can have 6 ROI and SJI 2.
;changes
;-june 5, 2013: LK, created.
;-june 11, 2013: ROI that overlap not allowed anymore
;-june 12, 2013: SLFreeland - sim graphics file names relative to $SSW_IRIS

;------------------ calculate doppler shifts of lines ----------
FUNCTION dopplershift,lambda,vdoppler,spec=spec
;calculates dopplershift for given lambda and vdoppler for ccd spec=['fuv','nuv']
;vdoppler = [50,100,200,300]  ;km/s (can be a vector)

if spec eq 'fuv' then begin
   fuv1disp = 12.98             ;mA/px
   fuv2disp = 12.72             ;mA/px  ;not used right now, but it shouldn't really matter
   doppler1 = lambda*vdoppler/3e5 ;3e5 = c in km/s, result in A
   dopplerpix1 = doppler1*1e3/fuv1disp
endif else begin                ;for NUV
   nuv1disp = 25.46             ;mA/px
   doppler1 = lambda*vdoppler/3e5 ;3e5 = c in km/s, result in A
   dopplerpix1 = doppler1*1e3/nuv1disp
endelse

return,dopplerpix1
END

;------------------- tv and draw image -------------------------
;this procedure does tv of the image and calculates dopplershifts and
;draws these as lines in the spectra
;modify desired dopplershift here and also below

PRO tv_and_draw,arr
 tv,arr.image,/true
   vdoppler = arr.vdoppler ;km/s
   fuv_cii = arr.fuv_cii ;location of a CII line in pixel coord (this may change!)
   fuv_siv = arr.fuv_siv ;location of Si IV line
   nuv_mgh = arr.nuv_mgh ;location of Mg H (or K, I'm not sure)
   nuv_mgk = arr.nuv_mgk ;location of other Mg line

   if arr.spec eq 'fuv' then begin ;FUV
      dopplerpix1 = dopplershift(1334.5,vdoppler,spec='fuv')
      for i=0,3 do xyouts,(fuv_cii+dopplerpix1[i])/arr.xsize,150./arr.ysize,$
                   strcompress(string(vdoppler[i])),/norm,color=arr.boxcolor,align=.5
      dopplerpix2 = dopplershift(1402.8,vdoppler,spec='fuv')
      for i=0,3 do xyouts,(fuv_siv+dopplerpix2[i])/arr.xsize,150./arr.ysize,$
                   strcompress(string(vdoppler[i])),/norm,color=arr.boxcolor,align=.5
   endif else begin             ;NUV
      dopplerpix1 = dopplershift(2803.,vdoppler,spec='nuv')
      dopplerpix2 = dopplershift(2796.,vdoppler,spec='nuv')
      for i=0,3 do xyouts,(nuv_mgh+dopplerpix1[i])/arr.xsize,150./arr.ysize,$
                   strcompress(string(vdoppler[i])),/norm,color=0,align=.5
      for i=0,3 do xyouts,(nuv_mgk+dopplerpix2[i])/arr.xsize,150./arr.ysize,$
                   strcompress(string(vdoppler[i])),/norm,color=0,align=.5
      ypt = .1                  ;normalized diplay coords of text (y)
      xyouts,100./arr.xsize,ypt,'E',charsize=3.,/norm
      xyouts,1/4.-100./arr.xsize,ypt,'W',charsize=3.,/norm
      ;fuv sji labels
      xyouts,1/4.+100./arr.xsize,ypt,'W',charsize=3.,/norm
      xyouts,1/2.-100./arr.xsize,ypt,'E',charsize=3.,/norm
      ;nuv labels (nuv is flipped!)
      xyouts,1/2.+100./arr.xsize,ypt,'red',charsize=3.,/norm
      xyouts,1.-100./arr.xsize,ypt,'blue',charsize=3.,/norm
   endelse
END


;------------------- redraw regions -------------------------
PRO regions_redraw,arr 
;redraw regions on image
;arr is info array
   wset,arr.wid
   tv_and_draw,arr
   ;draw boxes
   for i=0,arr.ctr+1 do begin
      PlotS, [arr.sx[i], arr.sx[i], arr.dx[i], arr.dx[i], arr.sx[i]], $
             [arr.sy[i], arr.dy[i], arr.dy[i], arr.sy[i], arr.sy[i]], /Device, $
             Color=arr.boxColor
   endfor
END

;*************************************************************************
;------------------ GUI events ------------------------------------------
;*************************************************************************
PRO iris_regions_events, event

;---------- right click removes drawn windows ------------------------
if event.release eq 4 then begin
Widget_Control, event.top, Get_UValue=info, /No_Copy

maxroi:
  ;only delete content if some box has been drawn
   if info.pixid ne -1 then begin
      wset,info.wid
      tv_and_draw,info
   endif
 ;clear variables of coordinates
   info.sx = 0      & info.sy = 0
   info.dx = 0      & info.dy = 0
   info.ctr= 0
   Widget_Control, info.drawID, Draw_Motion_Events=0,/clear_events

endif else begin                ;if no right-click

   IF event.type GT 2 THEN RETURN
  ; Get the info structure.
   Widget_Control, event.top, Get_UValue=info, /No_Copy
   ; What kind of event is this?
   eventTypes = ['DOWN', 'UP', 'MOTION'] ;mouse button going down/up
   thisEvent = eventTypes[event.type]


CASE thisEvent OF
;----------------------------- mouse button moving down ------------------------------
   'DOWN': BEGIN
  
    ; Turn motion events on for the draw widget.
      Widget_Control, info.drawID, Draw_Motion_Events=1

    ; Create a pixmap (invisible window). Store its ID. Copy window contents into it.
      Window, /Free, /Pixmap, XSize=info.xsize, YSize=info.ysize
      info.pixID = !D.Window
      Device, Copy=[0, 0, info.xsize, info.ysize, 0, 0, info.wid]

    ; Get and store the static corner of the box.
      info.sx[info.ctr] = event.x
      if info.ctr eq 0 then info.sy[info.ctr] = event.y else info.sy[info.ctr] = info.sy[0]  ;enforce same box height
      ENDCASE

;---------------------- mouse button up ---------------------------------------------
   'UP': BEGIN
  
   ; Turn draw motion events off. Clear any events queued for widget.
      Widget_Control, info.drawID, Draw_Motion_Events=0, Clear_Events=1
     
   ; Order the box coordinates.
      sx = Min([info.sx[info.ctr], event.x], Max=dx)
      if info.ctr eq 0 then ycoord = event.y else ycoord=info.dy[0] ;enforce same box height
      sy = Min([info.sy[info.ctr], ycoord], Max=dy)

      ;store coordinates (info.ctr for left CCD, info.ctr+1 for right CCD,
      ;important for merging...)
      if dx lt 4144/info.binning-dx then begin
      info.dx[info.ctr] = dx
      info.dx[info.ctr+1] = 4144/info.binning-sx
      info.sx[info.ctr] = sx
      info.sx[info.ctr+1] = 4144/info.binning-dx
      endif else begin
      info.dx[info.ctr] = 4144/info.binning-sx
      info.dx[info.ctr+1] = dx
      info.sx[info.ctr] = 4144/info.binning-dx
      info.sx[info.ctr+1] = sx
      endelse

      info.dy[info.ctr] = dy
      info.sy[info.ctr] = sy
      info.dy[info.ctr+1] = dy
      info.sy[info.ctr+1] = sy

   ;---- make sure box doesn't cross middle of ccd --------
      if (sx le info.xsize/2 && dx ge info.xsize/2) then begin
         print,'Region goes over the CCD boundary. Try again...'
         info.sx[info.ctr] = 0 & info.sy[info.ctr] = 0
         info.dx[info.ctr] = 0 &  info.dy[info.ctr] = 0
         info.sx[info.ctr+1] = 0 & info.sy[info.ctr+1] = 0
         info.dx[info.ctr+1] = 0 &  info.dy[info.ctr+1] = 0
         info.ctr = info.ctr - 2 ;go back one region
         regions_redraw,info
      endif

    ;---- check for stupidity of user: box inside box  -------------
      for i=0,info.ctr do begin ;max 8 regions
         if info.sx[info.ctr] gt info.sx[i] && info.sx[info.ctr] lt info.dx[i] then begin
                                ;need gt and lt, otherwise first box has problem already
            print,'Do not draw ROI inside ROI! Try again...'
            info.sx[info.ctr] = 0 & info.sy[info.ctr] = 0
            info.dx[info.ctr] = 0 &  info.dy[info.ctr] = 0
            info.sx[info.ctr+1] = 0 & info.sy[info.ctr+1] = 0
            info.dx[info.ctr+1] = 0 &  info.dy[info.ctr+1] = 0
            info.ctr = info.ctr - 2 ;go back one region
            regions_redraw,info
         endif else begin  
            if info.dx[info.ctr] gt info.sx[i] && info.dx[info.ctr] lt info.dx[i] then begin
               print,'Do not draw ROI inside ROI! Try again...'
               info.sx[info.ctr] = 0 & info.sy[info.ctr] = 0
               info.dx[info.ctr] = 0 &  info.dy[info.ctr] = 0
               info.sx[info.ctr+1] = 0 & info.sy[info.ctr+1] = 0
               info.dx[info.ctr+1] = 0 &  info.dy[info.ctr+1] = 0
               info.ctr = info.ctr - 2 ;go back one region
               regions_redraw,info
            endif    
         endelse
     ;box outside of box
         if info.sx[info.ctr] lt info.sx[i] && info.dx[info.ctr] gt info.dx[i] then begin
            print,'Do not draw ROI that overlap! Try again...'
            info.sx[info.ctr] = 0 & info.sy[info.ctr] = 0
            info.dx[info.ctr] = 0 &  info.dy[info.ctr] = 0
            info.sx[info.ctr+1] = 0 & info.sy[info.ctr+1] = 0
            info.dx[info.ctr+1] = 0 &  info.dy[info.ctr+1] = 0
            info.ctr = info.ctr - 2 ;go back one region
            regions_redraw,info
         endif
      endfor

  
      ;--- check for merged regions -----------
     mergecheck: 
     currctr = info.ctr
     if info.ctr mod 2 eq 0 then start=1 else start=0

     for i=start,info.ctr,2 do begin ;max 8 regions
       ;check merging on right and left
       ;merging does not happen across CCDs and merging will happen for regular 
       ;and mirrored region at the same time
       if abs(info.dx[info.ctr+1] - info.sx[i]) lt 100/info.binning then begin ;merging on left
          xtmp = min([info.sx[i], info.sx[info.ctr+1]], max=x2tmp)
          info.sx[i] = xtmp
          info.sx[info.ctr+1] = 0 & info.sy[info.ctr+1] = 0
          xtmp = min([info.dx[i], info.dx[info.ctr+1]], max=x2tmp)
          info.dx[i] = x2tmp
          info.dx[info.ctr+1] = 0 &  info.dy[info.ctr+1] = 0
          info.ctr = info.ctr - 1 ;go back one region
          regions_redraw,info
       endif
     endfor  

     if info.ctr mod 2 eq 0 then start=1 else start=0
     for i=start,info.ctr,2 do begin ;max 8 regions
        if abs(info.sx[info.ctr+1] - info.dx[i]) lt 100/info.binning then begin ;merging on right
           xtmp = min([info.sx[i], info.sx[info.ctr+1]], max=x2tmp)
           info.sx[i] = xtmp
           info.sx[info.ctr+1] = 0 & info.sy[info.ctr+1] = 0
           xtmp = min([info.dx[i], info.dx[info.ctr+1]], max=x2tmp)
           info.dx[i] = x2tmp
           info.dx[info.ctr+1] = 0 &  info.dy[info.ctr+1] = 0
           info.ctr = info.ctr - 1 ;go back one region
           regions_redraw,info
         endif
     endfor

     if info.ctr ne currctr then goto,mergecheck  ;redo check for merging if something was merged


      ;--- check that less than 2048 rows -----------
       if abs(info.dx[info.ctr] - info.sx[info.ctr]) gt 2048/info.binning then begin
          print,"After mirror/merge a readout region is too large (>2048 rows). Try again..."
          info.sx[info.ctr] = 0 & info.sy[info.ctr] = 0
          info.dx[info.ctr] = 0 &  info.dy[info.ctr] = 0
          info.sx[info.ctr+1] = 0 & info.sy[info.ctr+1] = 0
          info.dx[info.ctr+1] = 0 &  info.dy[info.ctr+1] = 0
          info.ctr = info.ctr - 2 ;go back one region
          regions_redraw,info
       endif

        ;todo: check for 4096, port E and row summing...
       ;print box coordinates
       print,'ROI coordinates (binned!):'
       print,'x0:',info.sx[0:7]
       print,'x1:',info.dx[0:7]
       print,'y0:',info.sy[0:7]
       print,'y1:',info.dy[0:7]
  
;     timing for skipped region: Tskip = Tob(314 msec) + Trs (100 msec) * Ns (num of skipped rows)
;     readout timing: Tread = (Tcs + Trs)*nr with Tcs = 274 ms for 1x, 178.1 for 2x, 130.15 for 4x
;     Trs = 100 msec for 1x, 200msec for 2x, 400 ms for 4x, 800 ms for 8x, Nr = nr of post-summed rows read

      colvec = fltarr(4144/info.binning)  ;contains 1 if column read, 0 if skipped
      for i=0,info.ctr+1 do colvec[info.sx[i]:info.dx[i]] = 1  ;ctr+1 because of mirrored region

      ;formulas from Mansir's document. /2 because readout simultaneous for 2 cameras
      ;and because ports are read out from each side
      Tskip = 314. + 100. * n_elements(where(colvec eq 0))*info.binning/2.  ;png image is binned!
      Tread = (274. + 100.)*n_elements(where(colvec eq 1))*info.binning/2.  
      print,'read out time [ms]:',(Tskip+tread)/1e3

      if info.ctr ge 8 then begin
         print,'Maximum number of ROI reached. Deleting...'
         goto,maxroi
      endif

      info.ctr = info.ctr+2  ;increase counter
      ENDCASE

;--------------------- cursor moving ---------------------------------------------
   'MOTION': BEGIN

  ; Here is where the actual box is drawn
      WSet, info.wid
      Device, Copy=[0, 0, info.xsize, info.ysize, 0, 0, info.pixID]

  ; Get the coodinates of the new box and draw it.
      sx = info.sx[info.ctr]
      sy = info.sy[0]           ;enforce same box height
      dx = event.x
      if info.ctr eq 0 then dy = event.y else dy=info.dy[0] ;enforce same box height

      PlotS, [sx, sx, dx, dx, sx], [sy, dy, dy, sy, sy], /Device, Color=info.boxColor
      ;plot mirrored box
      PlotS, 4144/info.binning-[sx, sx, dx, dx, sx], [sy, dy, dy, sy, sy], /Device, $
         Color=info.boxColor
 
      ENDCASE

ENDCASE

endelse

Widget_Control, event.top, Set_UValue=info, /No_Copy
END


;**********************************************************************************************
;---------------------main program: set up widget ---------------------------------------------
;**********************************************************************************************

PRO iris_regions, fuv=fuv,nuv=nuv

;-------  these values may need to be changed --------
    binning=2  ;images are of size 2072
    vdoppler = [50,100,200,300] ;km/s
    fuv_cii = 118.              ;location of a CII line in pixel coord (this may change!)
    fuv_siv = 1914              ;location of Si IV line
    nuv_mgh = 1655              ;location of Mg H (or K, I'm not sure)
    nuv_mgk = 1797              ;location of other Mg line
;---------
    simimages=concat_dir('$SSW_IRIS','idl/uio/iris_simulator/Documents/images/')

    fuvimg = concat_dir(simimages,'fuv_2072x548_jun2012.png')
    nuvimg = concat_dir(simimages,'nuv_1036x548.png')
    sjiimg = concat_dir(simimages,'sji_1036x548_slitline.png')

    read_png,fuvimg,fuvx
    read_png,nuvimg,nuvx
    read_png,sjiimg,sji

    nuvx = nuvx[0:2,*,*]
    nuvtmp = nuvx
    for i=0,2 do nuvx[i,*,*] = rotate(reform(nuvtmp[i,*,*]),5) ;nuv was saved in a strange format and also needs to be flipped
    nuvx = scaleimg(nuvx,left=1,right=500)                     ;make image darker, otherwise boxes invisible

    ;small screen? bin images
    if keyword_set(nuv) then image=[[sji],[nuvx]] else image=fuvx
    xsize = (Size(image))[2]
    ysize = (Size(image))[3]
    scrsz = get_screen_size()
    xs=scrsz[0] & ys = scrsz[1]

    while (xsize ge xs || ysize ge ys) do begin
       image = congrid(image,3,xsize/2.,ysize/2.)
       xsize = (Size(image))[2]
       ysize = (Size(image))[3]
       print,'image was binned to fit the screen (each of these messages is a factor of 2 binning)'
       binning = binning*2.
    endwhile

print,'************************** WARNING ****************************'
print,'This widget does not apply the rules for start/end rows, pixel divisibility by 16 etc.'
print,'Use the table creator auto-correction after you input your numbers there'


   tlb = Widget_Base(Title=' FUV spectrum')
   ;Create the draw widget graphics window. Turn button events ON.
   drawID = Widget_Draw(tlb, XSize=xsize, YSize=ysize, Button_Events=1)

   ; Realize widgets and make draw widget the current window.
   Widget_Control, tlb, /Realize
   Widget_Control, drawID, Get_Value=wid
   WSet, wid

  
   ;FUV specific graphics
   if ~keyword_set(nuv) then begin
      boxcolor = 0              ;black
      image[*,fuv_cii,0:*:2] = 0    ;C II line
      dopplerpix1 = dopplershift(1334.5,vdoppler,spec='fuv')
      dopplerpix2 = dopplershift(1402.8,vdoppler,spec='fuv')
 
      image[*,fuv_cii+dopplerpix1,0:*:2] = 0
      image[*,fuv_cii-dopplerpix1,0:*:2] = 0
      image[*,fuv_siv+dopplerpix2,0:*:2] = 0
      image[*,fuv_siv-dopplerpix2,0:*:2] = 0
      spec='fuv'
   endif else begin             ;NUV specific settings
      loadct,1
      boxcolor = 200            ;white
      dopplerpix1 = dopplershift(2803.,vdoppler,spec='nuv')
      dopplerpix2 = dopplershift(2796.,vdoppler,spec='nuv')
      image[*,nuv_mgh+dopplerpix1,0:*:2] = 0
      image[*,nuv_mgh-dopplerpix1,0:*:2] = 0
      image[*,nuv_mgk+dopplerpix2,0:*:2] = 0
      image[*,nuv_mgk-dopplerpix2,0:*:2] = 0
      spec='nuv' 
   endelse

; Create an "info" structure with information to run the program.
   info = { image:image, $      ; The image data.
            wid:wid, $          ; The window index number.
            binning:binning, $  ;factor of png binning
            drawID:drawID, $    ; The draw widget identifier.
            pixID:-1, $         ; The pixmap identifier (undetermined now).
            spec:spec, $        ;spec=nuv or fuv
            xsize:xsize, $      ; The X size of the graphics window.
            ysize:ysize, $      ; The Y size of the graphics window.
            sx:intarr(10), $    ; The X value of the static corner of the box.
            sy:intarr(10), $    ; The Y value of the static corner of the box.
            dx:intarr(10), $    ; The X value of the chosen corner of the box.
            dy:intarr(10), $    ; The Y value of the chosen corner of the box.
                                ;intarr needs to be 2 more than # of
                                ;ROI for temp storage (assuming max 8 ROI)
            nuv_mgk:nuv_mgk, $
            nuv_mgh:nuv_mgh, $
            fuv_cii:fuv_cii, $
            fuv_siv:fuv_siv, $
            ctr:0, $            ;counter for ROI
            vdoppler:vdoppler, $ ;Doppler velocity
            boxColor:boxColor }  ; The rubberband box color.
 
 ;display image and draw doppler lines etc.
   tv_and_draw,info

 ;Store the info structure.
   Widget_Control, tlb, Set_UValue=info, /No_Copy

   ; Start the program going.
   XManager, 'iris_regions', tlb, /No_Block, Event_Handler='iris_regions_Events'


END




