;  SCCS filename:  SCCS/s.kpfvu.pro
;            SID:  1.23
;    Last update:  06/02/97 09:52:07
; Check out time:  06/02/97 09:52:13

; initialize program parameters --------                     
                     
PRO init_param                       

    COMMON version,version_str
    version_str='v1.4a 6/97'
                       
    COMMON params $                      
           ,win_img_xsize, win_img_ysize $        ; image window size 
           ,win_prf_xsize, win_prf_ysize $        ; profile window size
           ,imx, imy $                            ; normalized image placement
           ,cbdelta,cbwidth,cbheight $            ; color bar size      
           ,color_table_ndx $                     ; default color table      
           ,map_grid_cndx,  map_cont_cndx         ; map colors        

    ; turn off compilation messages
    COMMON quiet_val,oldQuietVal
    oldQuietVal = !QUIET
    !QUIET = 1
                       
    ; window sizes in device coordinates (pixels)                     
    win_img_xsize = 340    ; image window                               
    win_img_ysize = 340                                   
    win_prf_xsize = 340    ; profile window                               
    win_prf_ysize = 75                         
                     
    ; normalized placement of image in image window             
    imx=0.20             
    imy=0.20             
                     
    ; color bar size and placement                                
    cbdelta=7.             ; offset from edge of image             
    cbwidth=10.            ; width of color bar             
    cbheight=228.          ; height of color bar             
                     
    ; default color table             
    color_table_ndx = 5                       
                     
    ; color indices for map grid and contintent outlines             
    map_grid_cndx = 200                             
    map_cont_cndx = 180                                         
                       
END  ; end of parameter initialization                     
                       
                     
; Help screen ---------------                     
                         
PRO show_kpfvu_help,event
   
   COMMON BASES,tlb,menubase             

help_text = [' ' $
   ,'DISCLAIMER:  UVI Key Parameters are presented as summary ' $
   ,'data only and are governed by the ISTP rules for data usage.' $
   ,'(URL http://www-spof.gsfc.nasa.gov/rules.html). In some cases ' $
   ,'parameters such as pointing and calibration may not be adequate' $
   ,'to support quantitative scientific analysis.  For this reason,' $
   ,'they are not to be used for presentation, publication, or analysis.' $
   ,' '  $
   ,'REQUIREMENTS:  This utility was developed using'  $
   ,'               IDL 3.5 on a SUN workstation.  It'  $
   ,'               has also been tested on PC and DEC ' $
   ,'               ALPHA platforms.  It requires a windowed' $
   ,'               operating system capable of displaying' $
   ,'               multiple windows.'  $
   ,' '  $
   ,'USAGE: kpfvu    '  $
   ,'       kpfvu,''help'' ' $
   ,'       kpfvu,''filename'' ' $
   ,' '  $
   ,'The filename must be a string and be enclosed in single' $
   ,'quotes ''like this''.  If the file name is help, then'  $
   ,'this help window is shown.' $
   ,' '  $
   ,'This utility allows inspection of image and nonimage Key' $
   ,'Parameter data, summary inspection of nonimage parameters,' $
   ,'and several output options to save the current' $
   ,'data.' $
   ,' ' $
   ,'The DISPLAY menu provides viewing options. The OUTPUT menu ' $
   ,'provides options to save the current image data.  The ' $
   ,'OPEN menu allows a new key parameter file to be opened.' $
   ,' ' $
   ,'Record buttons...' $
   ,'----------------------------------------------------------' $
   ,'These buttons are used to select the data record to display.' $
   ,' |<      Go to the first record' $
   ,'  <      Go back one record' $
   ,'  >      Advance one record '$
   ,' >|      Go to the last record' $
   ,' >>      Display all records with slight pause between records' $
   ,' <<      Same as >> but in reverse direction' $
   ,' !!      End continuous display of records' $
   ,' GoTo    Go to a specific record or time' $
   ,' slider  Manually select record' $
   ,' ' $
   ,'DISPLAY menu...' $
   ,'----------------------------------------------------------' $
   ,'SUMMARY -- graphic summary of nonimage parameters for the' $
   ,'           entire file.' $
   ,' ' $
   ,'FLAGS -- decodes quality and gap flags for the current record.' $
   ,' ' $
   ,'ZOOM -- displays a region of interest from the image.  Use' $
   ,'        the mouse to specify the center of the roi.' $ 
   ,' ' $
   ,'MOSAIC -- shows a mosaic of images about the current frame.' $
   ,' '$
   ,'REBIN -- the image is rebinned as a regular grid in either' $
   ,'         geodetic or magnetic coordinates and then displayed' $
   ,'         in the appropriate coordinate system.' $
   ,' ' $
   ,'COLOR TABLES -- provides option of using several standard' $
   ,'                color tables.' $
   ,' ' $
   ]  
  
   help_text2= [ $ 
    'OUTPUT menu...' $
   ,'----------------------------------------------------------' $
   ,'All output filenames are of the form DDD_HHMMSS.xxx, where' $
   ,'       DDD = day of year' $
   ,'       HH  = hour of day' $
   ,'       MM  = minute of hour' $
   ,'       SS  = second of minute' $
   ,'       xxx = PS or GIF or XDR' $
   ,' '  $
   ,'PS  -- the current active window is saved to a postscript ' $
   ,'       file.  A TVRD() command is used, so the output is at' $
   ,'       the resolution of the current display device.' $ 
   ,'GIF -- the current active window is saved as a GIF image. ' $
   ,'       A TVRD() command is used, so the output is at the' $
   ,'       resolution of the current display device.' $ 
   ,' '  $
   ,'XDR -- the image array and housekeeping structure for the ' $
   ,'       image data are saved to an output file using the IDL' $
   ,'       SAVE command.  They can be restored in a later IDL ' $
   ,'       session using the RESTORE command.' $
   ,' '  $
   ,'Misc...' $
   ,'----------------------------------------------------------' $
   ,'Mouse button:  Clicking the mouse button in the image display' $
   ,'               will display the row, column, and value of the' $
   ,'               selected pixel.  A row,column profile will be' $
   ,'               displayed in the lower display.  Subsequent' $
   ,'               zoom or line profiles will be centered on the' $
   ,'               point selected by the mouse click.' $
   ,' ' $
   ,'END OF KPFVU HELP'  $
   ,' ']

   IF(tlb NE -1) THEN BEGIN
      helpBase = WIDGET_BASE(TITLE='KPFvu Help',GROUP_LEADER=menubase)
   ENDIF ELSE BEGIN
      helpBase = WIDGET_BASE(TITLE='KPFvu Help')
   ENDELSE

   id = WIDGET_TEXT(helpBase,/SCROLL,YSIZE=30 $
       ,VALUE=[help_text,help_text2])
   WIDGET_CONTROL,id,SET_TEXT_TOP_LINE=0
   WIDGET_CONTROL, id, /REALIZE                                                                                                                   
END  ; end of help screen                                                                                                                                            
                                                                                                                                             
                                                                                                                                                                                                                                           
                                                                                     
; KPF viewer module -------------------                       
                                                             
PRO kpf,infilename
                                     
    ; the values of the params common block are set in init_params                     
    COMMON params $                      
           ,win_img_xsize, win_img_ysize $        ; image window size 
           ,win_prf_xsize, win_prf_ysize $        ; profile window size
           ,imx, imy $                            ; normalized image placement  
           ,cbdelta,cbwidth,cbheight $            ; color bar size       
           ,color_table_ndx $                     ; default color table        
           ,map_grid_cndx,  map_cont_cndx         ; map colors                
              
    COMMON summary,qual_ary,pgf_ary,gain_ary,seq_ary,dsp_ary,system $
           ,door,filter,rsc,filename,time_pb5,jmin,jmax,numframes   
 
    COMMON display,pxflag,puflag,mflag,cflag,psflag
    COMMON BASES, tlb, menubase
    COMMON IDS,  mouseWindow,hskWindow,prof,draw,summDraw,slider,maxSlider
    COMMON BIDS, topButton,backButton,forwButton,bottButton
    COMMON mouse,x,y
    COMMON version,version_str
    COMMON GO, stop_flag,go_flag
 
    filename = infilename   
    pixel_flag=1
    pxflag=pixel_flag
    x = 100
    y = 100
    stop_flag=0
    go_flag=0

    topButton = 0
    backButton = 0
    forwButton = 0
    bottButton = 0
   
    ; set up to use 8-bit color on a true color device

;   device, decompose = 0
    device, pseudo_color = 8
                                                            
    ;set default color table                                      
    loadct,color_table_ndx                                      
                                   
    ;make top level base for menu, hsk, status, etc.
    tlb = WIDGET_BASE(TITLE='KPFvu - UVI Key Parameter Viewer - '+version_str $
                 ,COLUMN=2)

    ;make base for graphics
    graphicsBase = WIDGET_BASE(tlb,TITLE='Display' $
                     ,XOFFSET=100,YOFFSET=100,COLUMN=1)
 
    ;make draw widget to hold image graphics
    draw = WIDGET_DRAW(graphicsBase,XSIZE=win_img_xsize,YSIZE=win_img_ysize $
                     ,RETAIN=2,/BUTTON_EVENTS $
                     ,EVENT_PRO='mouse_event')

    ;make text widget to hold mouse position
    mouseWindow = WIDGET_TEXT(graphicsBase, YSIZE=2, VALUE=' ')

    ;make draw widget to hold row/column profiles
    prof = WIDGET_DRAW(graphicsBase,XSIZE=win_prf_xsize,YSIZE=win_prf_ysize $
                     ,RETAIN=2)
 
    ;make control base to hold status and menu
    controlBase = WIDGET_BASE(tlb,COLUMN=1)
 
    ;make menu base to hold menu buttons
    menubase = WIDGET_BASE(controlBase,COLUMN=5)
 
    ;make buttons for menu bar
    openButton = WIDGET_BUTTON(menubase,VALUE='Open',EVENT_PRO='open_event')
    dispButton = WIDGET_BUTTON(menubase,VALUE='Display',/MENU)
    outButton  = WIDGET_BUTTON(menubase,VALUE='Output',/MENU)
    exitButton = WIDGET_BUTTON(menubase,VALUE='Exit',EVENT_PRO='end_app')
    helpButton = WIDGET_BUTTON(menubase,VALUE='Help',EVENT_PRO='show_kpfvu_help')

    psButton   = WIDGET_BUTTON(outButton,VALUE='PS' $
                 ,EVENT_PRO='ps_event')
    gfButton   = WIDGET_BUTTON(outButton,VALUE='GIF' $
                 ,EVENT_PRO='gf_event')
    xdButton   = WIDGET_BUTTON(outButton,VALUE='XDR' $
                 ,EVENT_PRO='xdr_event')

    summButton = WIDGET_BUTTON(dispButton,VALUE='Summary' $
                 ,EVENT_PRO='summary_event')
    flagButton = WIDGET_BUTTON(dispButton,VALUE='Flags' $
                 ,EVENT_PRO='flag_event')
    zoomButton = WIDGET_BUTTON(dispButton,VALUE='Zoom' $
                 ,EVENT_PRO='zoom_event')
    moscButton = WIDGET_BUTTON(dispButton,VALUE='Image Mosaic' $
                 ,EVENT_PRO='mosc_event')
;    rbinButton = WIDGET_BUTTON(dispButton,VALUE='Rebinned Image',/MENU)
    colrButton = WIDGET_BUTTON(dispButton,VALUE='Color Tables' $
                 ,EVENT_PRO='color_event')

;    grbinButton = WIDGET_BUTTON(rbinButton,VALUE='Geodetic' $
;                 ,EVENT_PRO='grbin_event')
;    mrbinButton = WIDGET_BUTTON(rbinButton,VALUE='Magnetic' $
;                 ,EVENT_PRO='mrbin_event')

    ;make text widget to hold housekeeping
    hskWindow = WIDGET_TEXT(controlBase,/SCROLL,XSIZE=35,YSIZE=16,VALUE=' ')

    ;make base to hold toggle buttons
    toggBase = WIDGET_BASE(controlBase,ROW=5,/EXCLUSIVE,FRAME=1)

    ;make toggle buttons for geodetic options
    pixButton = WIDGET_BUTTON(toggBase,VALUE='Pixel Coordinates', $
               /NO_RELEASE,EVENT_PRO='pixbutton_event')
    geoButton = WIDGET_BUTTON(toggBase,VALUE='Geodetic Coordinates', $
               /NO_RELEASE,EVENT_PRO='geobutton_event')
;    magButton = WIDGET_BUTTON(toggBase,VALUE='Magnetic Coordinates', $
;               /NO_RELEASE,EVENT_PRO='magbutton_event')

    WIDGET_CONTROL,pixButton,/SET_BUTTON
 

    ;make slider to scale image intensity
    maxSlider = WIDGET_SLIDER(controlBase,VALUE=1 $
               ,MINIMUM=0,MAXIMUM=1, $
                TITLE='Maximum Image Value (photon flux)',FRAME=1, $
                EVENT_PRO='max_slide_event', $
                SCROLL=1)

    ;make button base on graphics base
    grButtonBase = WIDGET_BASE(controlBase,COLUMN=10)

    ;make record buttons for graphics
    topButton  = WIDGET_BUTTON(grButtonBase,VALUE='|<' $
                     ,EVENT_PRO='top_record')
    gobckButton   = WIDGET_BUTTON(grButtonBase,VALUE='<<' $
                     ,EVENT_PRO='gobck_event')
    backButton = WIDGET_BUTTON(grButtonBase,VALUE='<' $
                     ,EVENT_PRO='decrement_record')
    forwButton = WIDGET_BUTTON(grButtonBase,VALUE='>' $
                     ,EVENT_PRO='increment_record')
    goButton   = WIDGET_BUTTON(grButtonBase,VALUE='>>' $
                     ,EVENT_PRO='go_event')
    bottButton = WIDGET_BUTTON(grButtonBase,VALUE='>|' $
                     ,EVENT_PRO='bottom_record')
    gotoButton = WIDGET_BUTTON(grButtonBase,VALUE='GoTo' $
                     ,EVENT_PRO='goto_record')
    slider     = WIDGET_SLIDER(grButtonBase,VALUE=0, $
                    MINIMUM=0,MAXIMUM=1,EVENT_PRO='slider_event', $
                    FRAME=1)

    ;disable buttons until file has been opened
    WIDGET_CONTROL,dispButton,SENSITIVE=0
    WIDGET_CONTROL, outButton,SENSITIVE=0
    WIDGET_CONTROL, pixButton,SENSITIVE=0
    WIDGET_CONTROL, geoButton,SENSITIVE=0
;    WIDGET_CONTROL, magButton,SENSITIVE=0
    WIDGET_CONTROL, maxSlider,SENSITIVE=0
    WIDGET_CONTROL, topButton,SENSITIVE=0
    WIDGET_CONTROL,backButton,SENSITIVE=0
    WIDGET_CONTROL,forwButton,SENSITIVE=0
    WIDGET_CONTROL,bottButton,SENSITIVE=0
    WIDGET_CONTROL,gotoButton,SENSITIVE=0
    WIDGET_CONTROL,  goButton,SENSITIVE=0
    WIDGET_CONTROL,gobckButton,SENSITIVE=0
    WIDGET_CONTROL,    slider,SENSITIVE=0

    ;make bases active
    WIDGET_CONTROL,tlb,/REALIZE

    ;initialize hsk structure
    create_hsk_structure,hsk

    bsIDS = {bases,tlb:tlb}
    bIDS = {buttons,topButton:topButton,backButton:backButton $
             ,forwButton:forwButton,goButton:goButton $
             ,pixButton:pixButton,geoButton:geoButton $
;             ,magButton:magButton $
             ,bottButton:bottButton,dispButton:dispButton $
             ,outButton:outButton,exitButton:exitButton $
             ,helpButton:helpButton,goBckButton:goBckButton $
             ,gotoButton:gotoButton,gfButton:gfButton $
             ,xdButton:xdButton,colrButton:colrButton} 
    wIDS = {windows,draw:draw,mouseWindow:mouseWindow}
    sIDS = {sliders, maxSlider:maxSlider,slider:slider}
    info = {infilename:infilename,j:0,jmin:0,jmax:1 $
           ,numframes:1,max:1.,min:0. $
           ,spkOvrRideFlag:0,image_data:FLTARR(200,228),hsk:hsk $
           ,lat_img:FLTARR(20,23),lon_img:FLTARR(20,23) $
           ,f_str:' ',date_str:' ',time_str:' ' $
           ,path_str:'',first_flag:1,rot_val:2 $
           ,bsIDS:bsIDS,sIDS:sIDS,bIDS:bIDS,wIDS:wIDS} 

    ;copy common data into widget user value 
    WIDGET_CONTROL, tlb, SET_UVALUE = info   

    ;make image window active window
    WIDGET_CONTROL,draw,GET_VALUE=drawWID
    WSET,drawWID

    ;open file if name provided
    dummy_event = {id: 0, top: tlb, handler: tlb}
    IF(infilename NE '')THEN open_event,dummy_event

    ;hand off control to the widget manager
    XMANAGER,'kpf',tlb
                                                                                                                                             
endpt:                                                                                                                                                 
                                                                                                                                             
END ; end of kpf viewer module                                                                                     
PRO open_event,event

    WIDGET_CONTROL,event.top,GET_UVALUE=info

    ;get filename of new file
    filename = info.infilename
    new_str=''
    IF(filename EQ '') THEN BEGIN
       IF(info.path_str NE '') THEN BEGIN
          filename=PICKFILE(TITLE='Please Select Key Parameter File To Read' $
                   ,GET_PATH=new_str,PATH=info.path_str)
       ENDIF ELSE BEGIN
          filename=PICKFILE(TITLE='Please Select Key Parameter File To Read' $
                   ,GET_PATH=new_str)
       ENDELSE
       IF(filename EQ '') THEN RETURN
    ENDIF ELSE BEGIN
       IF(info.first_flag NE 1) THEN BEGIN
          filename=PICKFILE(TITLE='Please Select Key Parameter File To Read' $
                   ,GET_PATH=new_str,PATH=info.path_str)
          IF(filename EQ '') THEN RETURN
       ENDIF
    ENDELSE
    newfilename = filename

    WIDGET_CONTROL,event.top,/HOURGLASS

    ;find how many image records are in CDF              
    getcdfrecs,newfilename,numframes                    
                                                        
    ;set up for records to display                    
    jmin=0                                                   
    jmax=numframes-1                                        
    WIDGET_CONTROL,info.sIDS.slider,SET_SLIDER_MAX=jmax 

    ;open CDF and read image
    read_image_kpf,0,image,pimage1,pimage2,newfilename

    ;load info structure
    info.path_str = new_str
    info.first_flag = 0
    info.numframes = numframes 
    info.jmin = jmin
    info.jmax = jmax
    info.j    = 0
    info.image_data = image
    info.infilename = newfilename
    WIDGET_CONTROL,event.top,SET_UVALUE=info

    ;read hsk
    update_hsk,event

    ;display data
    WIDGET_CONTROL,event.top,GET_UVALUE=info
    show_record,event
 

    ;enable controls
    WIDGET_CONTROL,info.bIDS.dispButton,SENSITIVE=1
    WIDGET_CONTROL,info.bIDS.outButton,SENSITIVE=1
    WIDGET_CONTROL,info.bIDS.pixButton,SENSITIVE=1
    WIDGET_CONTROL,info.bIDS.geoButton,SENSITIVE=1
;    WIDGET_CONTROL,info.bIDS.magButton,SENSITIVE=1
    WIDGET_CONTROL,info.bIDS.topButton,SENSITIVE=1
    WIDGET_CONTROL,info.bIDS.backButton,SENSITIVE=1
    WIDGET_CONTROL,info.bIDS.forwButton,SENSITIVE=1
    WIDGET_CONTROL,info.bIDS.bottButton,SENSITIVE=1
    WIDGET_CONTROL,info.bIDS.gotoButton,SENSITIVE=1
    WIDGET_CONTROL,info.bIDS.goButton,SENSITIVE=1
    WIDGET_CONTROL,info.bIDS.gobckButton,SENSITIVE=1
    WIDGET_CONTROL,info.sIDS.maxSlider,SENSITIVE=1
    WIDGET_CONTROL,info.sIDS.slider,SENSITIVE=1

    WIDGET_CONTROL,info.wIDS.mouseWindow $
         ,SET_VALUE='Click mouse button for pixel info.'
END

FUNCTION get_max,img
    std = STDEV(img)
    med = MEDIAN(img)
    max = MAX(img)
    IF((max-med) GT 3*std) THEN max=med+(3*std)
    RETURN,max
END
FUNCTION get_min,img
    min=MAX([MIN(img),0])
    RETURN,min
END

PRO summary_event,event

    COMMON summary,qual_ary,pgf_ary,gain_ary,seq_ary,dsp_ary,system $
           ,door,filter,rsc,infilename,time_pb5,jmin,jmax,numframes    
    COMMON BASES,tlb,menubase             

    WIDGET_CONTROL,event.top,GET_UVALUE=info

    numframes = info.numframes
    IF (numframes LE 1) THEN GOTO, endpt

    oldWID = !d.window

    WIDGET_CONTROL,event.top,GET_UVALUE=info

    ;read non-image data                                                   
    read_nonimage_kpf,qual_ary,pgf_ary,gain_ary,seq_ary,dsp_ary,gci_ary $
              ,system,filter,door,time_pb5,attitude,info.infilename          
                                                                       
    ;get spacecraft distance from center of earth               
    rsc = FLTARR(N_ELEMENTS(gci_ary)/3)                        
    FOR i=0,N_ELEMENTS(system)-1 DO BEGIN                     
        rsc(i) = SQRT(gci_ary(0,i)*gci_ary(0,i) $             
                +gci_ary(1,i)*gci_ary(1,i) $                
                +gci_ary(2,i)*gci_ary(2,i))                
        rsc(i)=rsc(i)/6378.0                              
    ENDFOR                                              

    summBase = WIDGET_BASE(TITLE='UVI KP Summary',GROUP_LEADER=tlb)
    draw = WIDGET_DRAW(summBase,XSIZE=500,YSIZE=480 $
                     ,RETAIN=2)
    WIDGET_CONTROL,draw,/REALIZE

    summary,qual_ary,pgf_ary,gain_ary,seq_ary,dsp_ary,system $              
           ,door,filter,rsc,infilename,time_pb5,jmin,jmax 
             
    wset,oldWID

endpt:

END

PRO top_record,event
 
    COMMON IDS,  mouseWindow,hskWindow,prof,draw,summDraw,slider,maxSlider
    COMMON BIDS, topButton,backButton,forwButton,bottButton
    WIDGET_CONTROL,event.top,GET_UVALUE=info
 
    info.j = info.jmin

    WIDGET_CONTROL,event.top,SET_UVALUE=info
    WIDGET_CONTROL, slider, SET_VALUE=info.j
    WIDGET_CONTROL,topButton,SENSITIVE=0
    WIDGET_CONTROL,backButton,SENSITIVE=0
    WIDGET_CONTROL,bottButton,SENSITIVE=1
    WIDGET_CONTROL,forwButton,SENSITIVE=1

    update_hsk,event
    show_record,event
 
END

PRO decrement_record,event
 
    COMMON IDS,  mouseWindow,hskWindow,prof,draw,summDraw,slider,maxSlider
    COMMON BIDS, topButton,backButton,forwButton,bottButton
    WIDGET_CONTROL,event.top,GET_UVALUE=info
 
    WIDGET_CONTROL,topButton,SENSITIVE=1
    WIDGET_CONTROL,backButton,SENSITIVE=1
    WIDGET_CONTROL,bottButton,SENSITIVE=1
    WIDGET_CONTROL,forwButton,SENSITIVE=1

    info.j = info.j-1
    IF(info.j LE info.jmin) THEN BEGIN
       info.j = info.jmin
       WIDGET_CONTROL,topButton,SENSITIVE=0
       WIDGET_CONTROL,backButton,SENSITIVE=0
    ENDIF

    WIDGET_CONTROL,event.top,SET_UVALUE=info
    WIDGET_CONTROL, slider, SET_VALUE=info.j
   
    update_hsk,event
    show_record,event
 
END

PRO clear_prof

    COMMON IDS,  mouseWindow,hskWindow,prof,draw,summDraw,slider,maxSlider
    WIDGET_CONTROL,prof,GET_VALUE=wid
    WSET,wid
    ERASE
    WIDGET_CONTROL,draw,GET_VALUE=wid
    WSET,wid

END

PRO zoom_event,event

    COMMON BASES,tlb,menubase             
    COMMON IDS,  mouseWindow,hskWindow,prof,draw,summDraw,slider,maxSlider
    COMMON show_record,img,max_val,min_val
    COMMON mouse,x,y

    WIDGET_CONTROL,event.top,GET_UVALUE=info

    ;make base for prompt
    usrBase=WIDGET_BASE(COLUMN=1,TITLE='Enter Region of Interest Size')
    roiID=CW_FIELD(usrBase,TITLE='ROI size (pixels):',VALUE='50',/RETURN_EVENTS)

    WIDGET_CONTROL,usrBase,/REALIZE
    uevent=WIDGET_EVENT(usrBase) 

    WIDGET_CONTROL, roiID, GET_VALUE=roi_ary
    WIDGET_CONTROL, usrBase, /DESTROY

    roi=roi_ary(0)

    rm=y-roi/2
    cm=x-roi/2

    IF(rm LT 0)   THEN rm=0
    IF(cm LT 0)   THEN cm=0
    IF(rm GT 227-roi) THEN rm=227-roi
    IF(cm GT 199-roi) THEN cm=199-roi

    rp=rm+roi
    cp=cm+roi

    zoomBase = WIDGET_BASE(TITLE='KPFvu Zoom',GROUP_LEADER=tlb)
    id = WIDGET_DRAW(zoomBase,XSIZE=300,YSIZE=300,RETAIN=2)
    WIDGET_CONTROL, id, /REALIZE

    ;make zoom window active window
    WIDGET_CONTROL,id,GET_VALUE=zoomWID
    WSET,zoomWID

    image=info.image_data

    ;setup normalized screen coordinates for image display                 
    oldPosition=!P.POSITION 
    imx=0.2
    imy=0.2
    cx1=imx                                                                
    cx2=imx+(200./!d.x_size)                                              
    cy1=imy             
    cy2=imy+(228./!d.y_size)             
    !P.POSITION=[cx1,cy1,cx2,cy2]                            

    ;remove corner fill values from image             
    image = image * (image NE -127)                  
                                                   
    ;remove standard fill values from image             
    image = image * (image NE -32768)                     
                  
    ;the image is rotated to match orbital orientation. 
    image = ROTATE(CONGRID(image(cm:cp,rm:rp),200,228),info.rot_val)
    image = BYTSCL(image,MAX=info.max,MIN=info.min)

    TV,image,imx,imx,/NORMAL

        ;overdraw box with row/col labels  
        xrange=[cp,cm]
        yrange=[rp,rm]
        PLOT,xrange,yrange $
             ,/NORMAL,/NOERASE,YSTYLE=1,XSTYLE=1,PSYM=3 $  
             ,XRANGE=xrange,YRANGE=yrange $             
             ,XTITLE='column',YTITLE='row'

    ;reset draw window to active window
    WIDGET_CONTROL,draw,GET_VALUE=drawWID
    WSET,drawWID
    !P.POSITION=oldPosition

END

FUNCTION chk_leap_year,year

      return_val = 0

     ;divisible by 4 and not centurial year
      IF((year MOD 4) EQ 0)  AND  ((year MOD 100) NE 0) THEN  $
          return_val = 1

     ;divisible by 400
      IF(year MOD 400) EQ 0 THEN return_val = 1

      RETURN,return_val

END

FUNCTION get_doy,day,month,year

    days_per_month = [31,28,31,30,31,30,31,31,30,31,30,31]

    doy=0
    FOR i=0,month-2 DO BEGIN
        doy = doy + days_per_month(i)
    ENDFOR
    doy = doy + day

    is_leap_year = chk_leap_year(year)
    IF(is_leap_year) AND (month GT 2) THEN doy=doy+1

    RETURN,doy

END

FUNCTION get_msec_of_day,day,hour,minute,second,millisecond

    msd = LONG(0)

    msd = millisecond
    msd = msd + second * 1000
    msd = msd + minute * 60 * 1000
    msd = msd + hour * 60 * 60 * 1000

    RETURN,msd
END

PRO get_ptg,row,col,gdlat,gdlon,event

    WIDGET_CONTROL,event.top,GET_UVALUE=info
    hsk = info.hsk

    gdlat=0
    gdlon=0

    cnv_flag = 1
    emis_hgt = 120
    CASE hsk.system OF
     -1: system = 2 
      1: system = 1
      ELSE: GOTO,errPt
    ENDCASE

    ;decode epoch value 
    CDF_EPOCH,hsk.epoch,year,month,day,hour,minute $ 
            ,second,millisecond,/BREAKDOWN_EPOCH     
    doy=get_doy(day,month,year)
    msd=get_msec_of_day(day,hour,minute,second,millisecond)

    time = LONARR(2)
    time(0) = year*1000 + doy
    time(1) = msd

    L0 = hsk.gci_look_dir
    att = hsk.attitude
    orb = hsk.gci_position

    ;check for fill values
    IF(MAX(ABS(L0)) GT 1E10) THEN GOTO,errPt
    IF(MAX(ABS(att)) GT 1E10) THEN GOTO,errPt
    IF(MAX(ABS(orb)) GT 1E10) THEN GOTO,errPt
    uviptg,cnv_flag,system,row,col,time,L0,att,orb,emis_hgt $
             ,versStr,gdlat,gdlon,rotm,ra,dec
errPt:
END

PRO mouse_event,event

    COMMON mouse,xx,yy
    COMMON show_record,image,max,min
    COMMON IDS,  mouseWindow,hskWindow,prof,draw,summDraw,slider,maxSlider
    COMMON params $                      
           ,win_img_xsize, win_img_ysize $        ; image window size 
           ,win_prf_xsize, win_prf_ysize $        ; profile window size
           ,imx, imy $                            ; normalized image placement
           ,cbdelta,cbwidth,cbheight $            ; color bar size      
           ,color_table_ndx $                     ; default color table      
           ,map_grid_cndx,  map_cont_cndx         ; map colors        

    WIDGET_CONTROL,event.top,GET_UVALUE=info
    lat_img=info.lat_img
    lon_img=info.lon_img

    ;initialize text
    txt='                        '

    ;respond to button events (0) and motion events (2)
    IF (event.type EQ 2) OR (event.type EQ 0) THEN BEGIN

       ;get mouse position and normalize to image position
       x=fix(event.x-imx*!d.x_size)
       y=fix(event.y-imy*!d.y_size)
       xx=200-x
       yy=227-y

       ;ad hoc fix to image registration problem
       xx=xx-7

       ;if in image output position to text widget
       IF( (xx GE 0) AND (xx LE 199) AND (yy GE 0) AND (yy LE 227) ) THEN BEGIN 

        txt = '(row:'+STRTRIM(STRING(yy),2)+', col:'+STRTRIM(STRING(xx),2)+')' $
              +' = '+STRTRIM(STRING(image(xx,yy)),2)

         ;get lat/lon info
         ;get_ptg,yy,xx,lat,lon,event
         xxx=FIX(xx/10)
         yyy=FIX(yy/10)
         txt = [txt, 'Geodetic: (lat,lon) =  (' $
             + STRTRIM(STRING(lat_img(xxx,yyy),FORMAT='(F6.2)'),2) + ','  $
             + STRTRIM(STRING(lon_img(xxx,yyy),FORMAT='(F6.2)'),2)]+ ')'

         ;output text to text widget
         WIDGET_CONTROL,mouseWindow,SET_VALUE=txt

         ;if button pressed then draw profiles
         IF(event.type EQ 0) THEN BEGIN

            ;save current plot settings
            oldPosition=!P.POSITION

            ;make profile window current and clear
            WIDGET_CONTROL,prof,GET_VALUE=wid
            WSET,wid
            ERASE

            ;plot profiles
            max1=MAX(image(*,y))
            max2=MAX(image(x,*))
            !P.POSITION=[0.15,0.2,0.95,0.8]
            PLOT,image(*,y),YRANGE=[0,MAX([max1,max2])],YTICKS=1 $
                ,CHARSIZE=0.8

            OPLOT,image(x,*),COLOR=200

            ;reset previous window and plot settings
            WIDGET_CONTROL,draw,GET_VALUE=wid
            WSET,wid
            !P.POSITION=oldPosition
         ENDIF

       ENDIF
    ENDIF

END

PRO max_slide_event,event
 
    COMMON IDS,  mouseWindow,hskWindow,prof,draw,summDraw,slider,maxSlider
    WIDGET_CONTROL,event.top,GET_UVALUE=info
    WIDGET_CONTROL,maxSlider,GET_VALUE=max
    info.max = max
    info.spkOvrRideFlag = 1

    WIDGET_CONTROL,event.top,SET_UVALUE=info
   
    update_hsk,event
    show_record,event
 
END

PRO slider_event,event
 
    COMMON IDS,  mouseWindow,hskWindow,prof,draw,summDraw,slider,maxSlider
    COMMON BIDS, topButton,backButton,forwButton,bottButton
    WIDGET_CONTROL,event.top,GET_UVALUE=info
    WIDGET_CONTROL,slider,GET_VALUE=jval
    info.j = jval      

    WIDGET_CONTROL,topButton,SENSITIVE=1
    WIDGET_CONTROL,backButton,SENSITIVE=1
    WIDGET_CONTROL,bottButton,SENSITIVE=1
    WIDGET_CONTROL,forwButton,SENSITIVE=1

    IF(info.j GE info.jmax) THEN BEGIN
       info.j = info.jmax
       WIDGET_CONTROL,bottButton,SENSITIVE=0
       WIDGET_CONTROL,forwButton,SENSITIVE=0
    ENDIF ELSE BEGIN
       IF(info.j LE info.jmin) THEN BEGIN
          info.j = info.jmin
          WIDGET_CONTROL,topButton,SENSITIVE=0
          WIDGET_CONTROL,backButton,SENSITIVE=0
       ENDIF
    ENDELSE

    WIDGET_CONTROL,event.top,SET_UVALUE=info
   
    update_hsk,event
    show_record,event
 
END

PRO mng_slider,event
    WIDGET_CONTROL,event.top,GET_UVALUE=info
    max_slider=info.sIDS.maxSlider
    image=info.image_data
    info.min = get_min(image)

    IF(info.spkOvrRideFlag EQ 0) THEN BEGIN
       info.max = get_max(image)
    ENDIF
    info.spkOvrRideFlag = 0

    WIDGET_CONTROL,max_slider,SET_SLIDER_MAX=MAX(image)
    WIDGET_CONTROL,max_slider,SET_SLIDER_MIN=MIN(image)
    WIDGET_CONTROL,max_slider,SET_VALUE=info.max
    WIDGET_CONTROL, event.top, SET_UVALUE=info
END

PRO gobck_event,event

    WIDGET_CONTROL,event.top, /HOURGLASS
    WIDGET_CONTROL,event.top,GET_UVALUE=info
    COMMON GO, stop_flag,go_flag

    goButton   = info.bIDS.goButton
    gotoButton = info.bIDS.gotoButton
    gobckButton   = info.bIDS.gobckButton
    topButton  = info.bIDS.topButton
    backButton = info.bIDS.backButton
    forwButton = info.bIDS.forwButton
    bottButton = info.bIDS.bottButton
    dispButton = info.bIDS.dispButton
    outButton  = info.bIDS.outButton
    exitButton = info.bIDS.exitButton
    helpButton = info.bIDS.helpButton

    WIDGET_CONTROL,topButton,SENSITIVE=0
    WIDGET_CONTROL,backButton,SENSITIVE=0
    WIDGET_CONTROL,forwButton,SENSITIVE=0
    WIDGET_CONTROL,bottButton,SENSITIVE=0
    WIDGET_CONTROL,outButton,SENSITIVE=0
    WIDGET_CONTROL,dispButton,SENSITIVE=0
    WIDGET_CONTROL,exitButton,SENSITIVE=0
    WIDGET_CONTROL,helpButton,SENSITIVE=0
    WIDGET_CONTROL,goButton,SENSITIVE=0
    WIDGET_CONTROL,gotoButton,SENSITIVE=0

    WIDGET_CONTROL,gobckButton,SET_VALUE='!!'
    WIDGET_CONTROL,gobckButton,EVENT_PRO='stop_all_event'

    ;stay in loop until info.disp_flag is changed
    go_flag = 1
    WHILE (info.j GT info.jmin) AND (stop_flag NE 1) DO BEGIN
        decrement_record,event
        xevent=WIDGET_EVENT(gobckButton,/NOWAIT) 
    ENDWHILE

    WIDGET_CONTROL,topButton,SENSITIVE=1
    WIDGET_CONTROL,backButton,SENSITIVE=1
    WIDGET_CONTROL,forwButton,SENSITIVE=1
    WIDGET_CONTROL,bottButton,SENSITIVE=1
    WIDGET_CONTROL,outButton,SENSITIVE=1
    WIDGET_CONTROL,dispButton,SENSITIVE=1
    WIDGET_CONTROL,exitButton,SENSITIVE=1
    WIDGET_CONTROL,helpButton,SENSITIVE=1
    WIDGET_CONTROL,goButton,SENSITIVE=1
    WIDGET_CONTROL,gotoButton,SENSITIVE=1

    WIDGET_CONTROL,gobckButton,SET_VALUE='<<'
    WIDGET_CONTROL,gobckButton,EVENT_PRO='gobck_event'
    stop_flag = 0
    go_flag = 0

END

PRO go_event,event

    WIDGET_CONTROL,event.top, /HOURGLASS
    WIDGET_CONTROL,event.top,GET_UVALUE=info
    COMMON GO, stop_flag,go_flag

    gobckButton   = info.bIDS.gobckButton
    goButton   = info.bIDS.goButton
    topButton  = info.bIDS.topButton
    backButton = info.bIDS.backButton
    forwButton = info.bIDS.forwButton
    bottButton = info.bIDS.bottButton
    dispButton = info.bIDS.dispButton
    outButton  = info.bIDS.outButton
    exitButton = info.bIDS.exitButton
    helpButton = info.bIDS.helpButton
    gotoButton = info.bIDS.gotoButton

    WIDGET_CONTROL,topButton,SENSITIVE=0
    WIDGET_CONTROL,backButton,SENSITIVE=0
    WIDGET_CONTROL,forwButton,SENSITIVE=0
    WIDGET_CONTROL,bottButton,SENSITIVE=0
    WIDGET_CONTROL,outButton,SENSITIVE=0
    WIDGET_CONTROL,dispButton,SENSITIVE=0
    WIDGET_CONTROL,exitButton,SENSITIVE=0
    WIDGET_CONTROL,helpButton,SENSITIVE=0
    WIDGET_CONTROL,gobckButton,SENSITIVE=0
    WIDGET_CONTROL,gotoButton,SENSITIVE=0

    WIDGET_CONTROL,goButton,SET_VALUE='!!'
    WIDGET_CONTROL,goButton,EVENT_PRO='stop_all_event'

    ;stay in loop until info.disp_flag is changed
    go_flag = 1
    WHILE (info.j LT info.jmax) AND (stop_flag NE 1) DO BEGIN
        increment_record,event
        xevent=WIDGET_EVENT(goButton,/NOWAIT) 
    ENDWHILE

    WIDGET_CONTROL,topButton,SENSITIVE=1
    WIDGET_CONTROL,backButton,SENSITIVE=1
    WIDGET_CONTROL,forwButton,SENSITIVE=1
    WIDGET_CONTROL,bottButton,SENSITIVE=1
    WIDGET_CONTROL,outButton,SENSITIVE=1
    WIDGET_CONTROL,dispButton,SENSITIVE=1
    WIDGET_CONTROL,exitButton,SENSITIVE=1
    WIDGET_CONTROL,helpButton,SENSITIVE=1
    WIDGET_CONTROL,gobckButton,SENSITIVE=1
    WIDGET_CONTROL,gotoButton,SENSITIVE=1

    WIDGET_CONTROL,goButton,SET_VALUE='>>'
    WIDGET_CONTROL,goButton,EVENT_PRO='go_event'
    stop_flag = 0
    go_flag = 0

END

PRO stop_all_event,event

    WIDGET_CONTROL,event.top, /HOURGLASS
    COMMON GO, stop_flag,go_flag

    stop_flag = 1

END

PRO find_record,flag,file,epoch,record

    record=-1

    id=CDF_OPEN(file)
    cdf_struct = CDF_INQUIRE(id)
    numrecs=cdf_struct.maxrec

    epoch_ary = DBLARR(numrecs)
    CDF_VARGET,id,'Epoch',tmp,REC_COUNT=numrecs,COUNT=[1,1,1,1,1]
    epoch_ary = REFORM(tmp)

    CDF_CLOSE,id

    IF((epoch_ary(0) GT epoch) OR $
       (epoch_ary(numrecs-1) LT epoch)) THEN RETURN

    diff = ABS(epoch_ary - epoch)
    r_ary = WHERE(diff EQ MIN(diff))
    record=r_ary(0)

END
PRO getTime_event,event

    COMMON GETTIME, ParentID
    WIDGET_CONTROL,event.top,/HOURGLASS

    ;neat trick here.  the parent base has tlb
    ;in uvalue.  extract it first, then get info
    ;from tlb
    WIDGET_CONTROL,event.top,GET_UVALUE=ptrToData
    WIDGET_CONTROL,ptrToData,GET_UVALUE=info

    ;decode current epoch for default values of text widget
    CDF_EPOCH,info.hsk.epoch,year,month,day,hour,minute $ 
            ,second,millisecond,/BREAKDOWN_EPOCH     

    ;build compound widget
    usrBase=WIDGET_BASE(COLUMN=1,TITLE='GoTo Time')
    hID=CW_FIELD(usrBase,TITLE='  Hour:',VALUE=hour $
                    ,/INTEGER,/RETURN_EVENTS)
    mID=CW_FIELD(usrBase,TITLE='Minute:',VALUE=minute $
                    ,/INTEGER,/RETURN_EVENTS)
    sID=CW_FIELD(usrBase,TITLE='Second:',VALUE=second $
                    ,/INTEGER,/RETURN_EVENTS)

    ;realize base and start event handler for this base
    WIDGET_CONTROL,usrBase,/REALIZE
    uevent=WIDGET_EVENT(usrBase) 

    ;the return key was hit.  read values and then
    ;get rid of text widget
    WIDGET_CONTROL, hID, GET_VALUE=hary
    WIDGET_CONTROL, mID, GET_VALUE=mary
    WIDGET_CONTROL, sID, GET_VALUE=sary
    WIDGET_CONTROL, usrBase, /DESTROY

    ;reformat values read from text widget
    hour=hary(0)
    minute=mary(0)
    second=sary(0)

    ;limit checks
    IF(hour GT 23) THEN hour=23
    IF(minute GT 59) THEN minute=59
    IF(second GT 59) THEN second=59

    ;build epoch corresponding to requested time
    ;note that we are using year,month,day,& msec
    ;from original epoch
    CDF_EPOCH,epoch,year,month,day,hour,minute $ 
            ,second,millisecond,/COMPUTE_EPOCH    

    ;find record corresponding to time.  
    ;a return value of -1 means time was 
    ;outside of data limits.  set default
    ;of goto record input to appropriate value
    find_record,'',info.infilename,epoch,record
    IF(record NE -1) THEN BEGIN
       WIDGET_CONTROL,ParentID,SET_VALUE=record
    ENDIF ELSE BEGIN
       IF(epoch LT info.hsk.epoch) THEN $
          WIDGET_CONTROL,ParentID,SET_VALUE=0
       IF(epoch GT info.hsk.epoch) THEN $
          WIDGET_CONTROL,ParentID,SET_VALUE=info.jmax
    ENDELSE

END

PRO goto_record,event
    WIDGET_CONTROL,event.top,/HOURGLASS
    WIDGET_CONTROL,event.top,GET_UVALUE=info
    COMMON GETTIME, id
    COMMON IDS,  mouseWindow,hskWindow,prof,draw,summDraw,slider,maxSlider

    usrBase=WIDGET_BASE(COLUMN=1,TITLE='GoTo Record',UVALUE=event.top)
    ID=CW_FIELD(usrBase,TITLE='Select Record Number',VALUE=info.j $
                    ,/INTEGER,/RETURN_EVENTS)
    button=WIDGET_BUTTON(usrBase,VALUE='Select Time' $
                    ,EVENT_PRO='getTime_event')

    WIDGET_CONTROL,usrBase,/REALIZE
    uevent=WIDGET_EVENT(usrBase) 

    WIDGET_CONTROL, ID, GET_VALUE=ary
    WIDGET_CONTROL, usrBase, /DESTROY

    jval = ary(0)
    IF(jval GT info.jmax) THEN jval=info.jmax
    WIDGET_CONTROL,slider,SET_VALUE=jval

    WIDGET_CONTROL,event.top,SET_UVALUE=info
    slider_event,event

END
PRO increment_record,event

    COMMON IDS,  mouseWindow,hskWindow,prof,draw,summDraw,slider,maxSlider
    COMMON BIDS, topButton,backButton,forwButton,bottButton
    WIDGET_CONTROL,event.top,GET_UVALUE=info

    WIDGET_CONTROL,topButton,SENSITIVE=1
    WIDGET_CONTROL,backButton,SENSITIVE=1
    WIDGET_CONTROL,bottButton,SENSITIVE=1
    WIDGET_CONTROL,forwButton,SENSITIVE=1

    info.j = info.j+1
    IF(info.j GE info.jmax) THEN BEGIN
       info.j = info.jmax
       WIDGET_CONTROL,bottButton,SENSITIVE=0
       WIDGET_CONTROL,forwButton,SENSITIVE=0
    ENDIF 

    WIDGET_CONTROL,event.top,SET_UVALUE=info
    WIDGET_CONTROL, slider, SET_VALUE=info.j

    update_hsk,event
    show_record,event

END

PRO bottom_record,event
 
    COMMON IDS,  mouseWindow,hskWindow,prof,draw,summDraw,slider,maxSlider
    COMMON BIDS, topButton,backButton,forwButton,bottButton
    WIDGET_CONTROL,event.top,GET_UVALUE=info
 
    info.j = info.jmax

    WIDGET_CONTROL,event.top,SET_UVALUE=info
    WIDGET_CONTROL, slider, SET_VALUE=info.j
    WIDGET_CONTROL,bottButton,SENSITIVE=0
    WIDGET_CONTROL,forwButton,SENSITIVE=0
    WIDGET_CONTROL,topButton,SENSITIVE=1
    WIDGET_CONTROL,backButton,SENSITIVE=1
   
    update_hsk,event
    show_record,event
 
END

PRO pixbutton_event,event
 
    COMMON display,pixel_flag,max_flag,crs_flag
    WIDGET_CONTROL,event.top,GET_UVALUE=info
 
    pixel_flag = 1
 
    update_hsk,event
    show_record,event
 
END

PRO magbutton_event,event
 
    COMMON display,pixel_flag,max_flag,crs_flag
    WIDGET_CONTROL,event.top,GET_UVALUE=info
 
    pixel_flag = -1
 
    update_hsk,event
    show_record,event
 
END

PRO geobutton_event,event
 
    COMMON display,pixel_flag,max_flag,crs_flag
    WIDGET_CONTROL,event.top,GET_UVALUE=info
 
    pixel_flag = 0 
 
    update_hsk,event
    show_record,event
 
END

PRO gf_event,event
    WIDGET_CONTROL,event.top, /HOURGLASS
    WIDGET_CONTROL,event.top,GET_UVALUE=info
    f    =info.f_str+'.gif'
    captured = TVRD()
    WRITE_GIF,f,captured
END
PRO xdr_event,event
    WIDGET_CONTROL,event.top, /HOURGLASS
    WIDGET_CONTROL,event.top,GET_UVALUE=info
    image=info.image_data
    hsk  =info.hsk
    f    =info.f_str+'.xdr'
    SAVE,image,hsk,/XDR,FILENAME=f
END
PRO ps_event,event
    WIDGET_CONTROL,event.top, /HOURGLASS
    WIDGET_CONTROL,event.top,GET_UVALUE=info
    f    =info.f_str+'.ps'
    wid=!d.window
    psprint,wid,f 
END
PRO color_event,event
    xloadct
END
PRO mosc_event,event

    WIDGET_CONTROL,/HOURGLASS
    WIDGET_CONTROL,event.top,GET_UVALUE=info

    oldWID = !d.window
    oldj=info.j

    ;create display window
    wxsize=600
    wysize=500
    tempBase = WIDGET_BASE(TITLE='Image Mosaic',GROUP_LEADER=info.bsIDS.tlb)
    id = WIDGET_DRAW(tempBase,XSIZE=wxsize,YSIZE=wysize,RETAIN=2)
    WIDGET_CONTROL, id, /REALIZE

    col=200.       ;image horizontal size
    row=228.       ;image vertical size
    num_imgs=7     ;number of mini images per row
    num_imgrows=5  ;number of rows of mini images

    ;conversion factors
    binsize = FLOAT(wxsize)/FLOAT(num_imgs)
    fctr = binsize/col
    total_frames = num_imgs*num_imgrows
    refFrm = info.j - total_frames/2
    IF(refFrm GT info.jmax-total_frames) THEN refFrm=info.jmax-total_frames+1
    IF(refFrm LT 0) THEN refFrm=0
 
    ;create mini images
    FOR j=0,num_imgrows-1 DO BEGIN
        FOR i=0,num_imgs-1 DO BEGIN
 
            imgDelta=i+j*num_imgs
            imgFrm=refFrm+imgDelta
            IF(imgFrm GT info.jmax) THEN GOTO,endpt
 
            read_image_kpf,imgFrm,img,pimage1,pimage2,info.infilename
            img=ROTATE(img,info.rot_val)

            ;remove corner fill values from image             
            img = img * (img NE -127)                  
                                                   
            ;remove standard fill values from image             
            img = img * (img NE -32768)                     

            ;get limits 
            imin = get_min(img)
            imax = get_max(img)
 
            imgscl = BYTSCL(img,MAX=imax,MIN=imin)
            TV,CONGRID(imgscl,fctr*col,fctr*row),imgDelta
 
            ;label with record number
            ;x=FLOAT(i)/FLOAT(num_imgs)
            ;y=0.98-FLOAT(j)/FLOAT(num_imgrows)
            ;XYOUTS,x,y,STRTRIM(STRING(imgFrm),2),/NORMAL,CHARTHICK=2
 
            info.j=imgFrm
            WIDGET_CONTROL,event.top,SET_UVALUE=info
            update_hsk,event,/fast
            WIDGET_CONTROL,event.top,GET_UVALUE=info
            x=FLOAT(i)/FLOAT(num_imgs)
            y=0.98-0.98*FLOAT(j)/FLOAT(num_imgrows)
            y2=y-0.14
            XYOUTS,x,y,STRMID(info.time_str,0,8),/NORMAL
            XYOUTS,x,y2,ufil(info.hsk),/NORMAL

        ENDFOR
    ENDFOR
endpt:
 
    ;wset,oldWID
    info.j=oldj
    WIDGET_CONTROL,event.top,SET_UVALUE=info

END
FUNCTION ufil,hsk
    CASE hsk.filter OF
     2: retval='1304'
     3: retval='1356'
     4: retval='LBHS'
     5: retval='LBHL'
     6: retval='SOLR'
     ELSE: retval='UNKNOWN'
    ENDCASE
    RETURN,retval
END
FUNCTION udoor,hsk
    CASE hsk.door OF
     -1: retval='CLOSED'
      1: retval='OPEN'
      ELSE: retval='UNKNOWN'
     ENDCASE
    RETURN,retval
END
FUNCTION usys,hsk
     CASE hsk.system OF
     -1: retval='System B'
      1: retval='System A'
      ELSE: retval='UNKNOWN'
     ENDCASE
    RETURN,retval
END
FUNCTION umode,hsk
    CASE hsk.mode OF
      1: retval='Normal'
      2: retval='Fast (miniframe)'
      3: retval='Idle'
    ELSE: retval='UNKNOWN'
    ENDCASE
    RETURN,retval
END

PRO annotate_image,info
    ;annotate image             
    annString = 'Not for publication, presentation, or analysis.'
    XYOUTS,0.02,0.96,annString,/NORMAL,CHARSIZE=0.8
    annstring = ufil(info.hsk)+' Gain '+STRTRIM(STRING(info.hsk.gain),2)
    XYOUTS,0.02,0.02,annString,/NORMAL,CHARSIZE=0.8
    annstring = info.date_str+info.time_str
    XYOUTS,0.50,0.02,annString,/NORMAL,CHARSIZE=0.8
END
PRO grbin_event,event

    WIDGET_CONTROL,event.top,GET_UVALUE=info
    hsk = info.hsk
    image = info.image_data
    lat_img=SMOOTH(CONGRID(info.lat_img,200,228),9)
    lon_img=SMOOTH(CONGRID(info.lon_img,200,228),9)
 
    ;remove corner fill values from image             
    image = image * (image NE -127)                  
                                                   
    ;remove standard fill values from image             
    image = image * (image NE -32768)                     

    WIDGET_CONTROL,/HOURGLASS
    latstep=2
    lonstep=4
    latmin=(-90)
    bin_data,image,lat_img,lon_img,latmin,latstep,lonstep $
            ,imgbins,latbins,lonbins

    ;clear screen after      
    ;image has been calculated to prevent having                     
    ;user stare at empty screen while waiting                     
    WIDGET_CONTROL,info.wIDS.draw,GET_VALUE=drawWID
    WSET,drawWID
    ERASE                                                                                                                                         
    ; also clear profile window
    clear_prof

    ;plot remapped image
    p0lat=90.
    p0lon=0.
    rot=0.
    lonmin=-180.
    plot_geo_map,imgbins,info.min,info.max,latmin,lonmin $
                ,p0lat,p0lon,rot,map_cont_cndx

    ;annotate image
    annotate_image,info
END
PRO mrbin_event,event

;under development
;not called from app

    WIDGET_CONTROL,/HOURGLASS
    WIDGET_CONTROL,event.top,GET_UVALUE=info
    hsk = info.hsk
    image = info.image_data
    lat_img=SMOOTH(CONGRID(info.lat_img,200,228),9)
    lon_img=SMOOTH(CONGRID(info.lon_img,200,228),9)
 
 
    ;remove corner fill values from image             
    image = image * (image NE -127)                  
                                                   
    ;remove standard fill values from image             
    image = image * (image NE -32768)                     

    ;convert geodetic data into magnetic data
    geo_to_mag,lat_img,lon_img,lat_mag,lon_mag

    latstep=2
    lonstep=4
    latmin=(-90)
    bin_data,image,lat_mag,lon_mag,latmin,latstep,lonstep $
            ,imgbins,latbins,lonbins

    ;clear screen after      
    ;image has been calculated to prevent having                     
    ;user stare at empty screen while waiting                     
    WIDGET_CONTROL,info.wIDS.draw,GET_VALUE=drawWID
    WSET,drawWID
    ERASE                                                                                                                                         
    ; also clear profile window
    clear_prof

    ;decode epoch value 
    CDF_EPOCH,hsk.epoch,year,month,day,hour,minute $ 
            ,second,millisecond,/BREAKDOWN_EPOCH     
    doy=get_doy(day,month,year)
    msd=get_msec_of_day(day,hour,minute,second,millisecond)

    time = LONARR(2)
    time(0) = year*1000 + doy
    time(1) = msd

    ;get rotation between ut & lt
    rot=360.*time(1)/(24.*60.*60.*1000.)
    IF(rot GT 180) THEN rot=rot-360.

    ;rot=rot+180.
    ;IF(rot GT 180) THEN rot=rot-360.

print,time,rot

    ;plot remapped image
    plot_mag_map,imgbins,latmin,info.min,info.max,rot
    XYOUTS,0.15,0.2,'Magnetic Lat & MLT (Tilted Dipole)',/NORMAL,CHARSIZE=0.8

    ;annotate image
    annotate_image,info
END

PRO flag_event,event

    WIDGET_CONTROL,event.top,/HOURGLASS
    WIDGET_CONTROL,event.top,GET_UVALUE=info

    tlb = info.bsIDS.tlb
    qf = info.hsk.quality_flag
    pf = info.hsk.post_gap_flag

    IF(qf EQ 0) THEN BEGIN
       flag_text=[' ','No quality flag bits are set.',' ']
    ENDIF ELSE BEGIN
       flag_text=[' ','The following quality flag bits are set:',' ']
       IF((qf AND '01'X) NE 0) THEN flag_text=[flag_text $
         ,'Bit  0:  Error writing SFDU comment.']
       IF((qf AND '02'X) NE 0) THEN flag_text=[flag_text $
         ,'Bit  1:  Image time is outside of processing window.']
       IF((qf AND '04'X) NE 0) THEN flag_text=[flag_text $
         ,'Bit  2:  One or more minor frames are zero filled.']
       IF((qf AND '08'X) NE 0) THEN flag_text=[flag_text $
         ,'Bit  3:  One or more minor frames have sync problems.']
       IF((qf AND '10'X) NE 0) THEN flag_text=[flag_text $
         ,'Bit  4:  Unable to determine accurate integration time.']
       IF((qf AND '20'X) NE 0) THEN flag_text=[flag_text $
         ,'Bit  5:  The despun platform is in motion.']
       IF((qf AND '40'X) NE 0) THEN flag_text=[flag_text $
         ,'Bit  6:  Potential errors in pointing information.']
       IF((qf AND '80'X) NE 0) THEN flag_text=[flag_text $
         ,'Bit  7:  Potential errors in image time tags.']
       IF((qf AND '100'X) NE 0) THEN flag_text=[flag_text $
         ,'Bit  8:  An error occurred decoding miniframe data.']
       IF((qf AND '200'X) NE 0) THEN flag_text=[flag_text $
         ,'Bit  9:  There was a gap in the level-zero data.']
       IF((qf AND '400'X) NE 0) THEN flag_text=[flag_text $
         ,'Bit 10:  Potential errors in image calibration.']
       IF((qf AND '800'X) NE 0) THEN flag_text=[flag_text $
         ,'Bit 11:  Unable to find current background image.']
       IF((qf AND '1000'X) NE 0) THEN flag_text=[flag_text $
         ,'Bit 12:  Unable to find default image.']
    ENDELSE

    IF(pf EQ 0) THEN BEGIN
       flag_text=[flag_text,' ','The Post Gap flag is not set.']
    ENDIF ELSE BEGIN
       flag_text=[flag_text,' ','A gap occurred prior to the current record']
       txt0='because '
       CASE pf OF
         1:txt=txt0+'UVI was in wrong mode.'
         2:txt=txt0+'there was missing data.'
         3:txt=txt0+'data was too noisy to process.'
         10:txt=txt0+'UVI HVPS not enabled.'
         11:txt=txt0+'UVI gain set to zero.'
         12:txt=txt0+'desired image was missing frame 1 hsk.'
         13:txt=txt0+'UVI KPGS was unable to find telemetry sync.'
         14:txt=txt0+'no background images were available.'
         15:txt=txt0+'desired image was not present.'
         16:txt=txt0+'spacecraft altitude was too low.'
         17:txt=txt0+'despun platform was pointed away from the earth.'
         18:txt=txt0+'data was outside processing time period.'
         19:txt=txt0+'of unknown cause.'
         DEFAULT:txt=txt0+'undefined gap event.'
       ENDCASE
       flag_text=[flag_text,txt]

    ENDELSE 

    flagBase = WIDGET_BASE(TITLE='Quality Flags',GROUP_LEADER=tlb)
    id = WIDGET_TEXT(flagBase,/SCROLL,YSIZE=10,VALUE=flag_text)
    WIDGET_CONTROL,flagBase,/REALIZE
END

FUNCTION chk_leap_year,year

      return_val = 0

     ;divisible by 4 and not centurial year
      IF((year MOD 4) EQ 0)  AND  ((year MOD 100) NE 0) THEN  $
          return_val = 1

     ;divisible by 400
      IF(year MOD 400) EQ 0 THEN return_val = 1

      RETURN,return_val

END

FUNCTION get_doy,day,month,year

    days_per_month = [31,28,31,30,31,30,31,31,30,31,30,31]

    doy=0
    FOR i=0,month-2 DO BEGIN
        doy = doy + days_per_month(i)
    ENDFOR
    doy = doy + day

    is_leap_year = chk_leap_year(year)
    IF(is_leap_year) AND (month GT 2) THEN doy=doy+1

    RETURN,doy

END

FUNCTION get_rot,hsk
    CASE usys(hsk) OF
      'System A' : rot=2
      'System B' : rot=5
      ELSE : MESSAGE,'ERROR: Unknown system value.'
    ENDCASE
    RETURN,rot
END
PRO update_hsk,event,fast=fast

   COMMON IDS,  mouseWindow,hskWindow,prof,draw,summDraw,slider,maxSlider
   WIDGET_CONTROL,event.top,GET_UVALUE=info

   j = info.j
   infilename = info.infilename

   read_hsk_kpf,j,infilename,hsk

   info.hsk = hsk
   info.rot_val=get_rot(hsk)
   WIDGET_CONTROL,event.top,SET_UVALUE=info

   ;decode epoch value 
   CDF_EPOCH,hsk.epoch,year,month,day,hour,minute $ 
            ,second,millisecond,/BREAKDOWN_EPOCH     

    doy = get_doy(day,month,year)

   date_string = STRTRIM(STRING(month,FORMAT='(I2.2)'),2)+'/'  $ 
                  +STRTRIM(STRING(day,FORMAT='(I2.2)'),2)+'/'    $ 
                  +STRTRIM(STRING(year,FORMAT='(I4.4)'),2)
   date_string1 = STRTRIM(STRING(year),2) +' ' $
               + STRTRIM(STRING(doy,FORMAT='(I3.3)'),2) +'/' 
   time_string = STRTRIM(STRING(hour,FORMAT='(I2.2)'),2)+':'   $ 
                  +STRTRIM(STRING(minute,FORMAT='(I2.2)'),2)+':' $ 
                  +STRTRIM(STRING(second,FORMAT='(I2.2)'),2)+'.' $ 
                  +STRTRIM(STRING(millisecond),2)     

    f_str = STRTRIM(STRING(doy,FORMAT='(I3.3)'),2) +'_' $
           +STRTRIM(STRING(hour,FORMAT='(I2.2)'),2)   $ 
           +STRTRIM(STRING(minute,FORMAT='(I2.2)'),2) $ 
           +STRTRIM(STRING(second,FORMAT='(I2.2)'),2) 
    info.f_str = f_str
    info.date_str = date_string1
    info.time_str = time_string
    WIDGET_CONTROL,event.top,SET_UVALUE=info

    IF(KEYWORD_SET(fast)) THEN RETURN

    sc_re = SQRT( hsk.gci_position(0)*hsk.gci_position(0) $
                + hsk.gci_position(1)*hsk.gci_position(1) $
                + hsk.gci_position(2)*hsk.gci_position(2) )
    sc_re = sc_re / 6378

    ;make hsk text string
    hsk_string = [ $
    ' KPGS Vers: ' + hsk.kpgs_version, $
    '    Record: ' + STRTRIM(STRING(j),2), $
    '     Epoch: ' + date_string+ $
    ' ' + time_string, $
    '  Time_PB5: ' + STRTRIM(STRING(hsk.time_pb5(0)),2)+ $
    ' ' + STRTRIM(STRING(hsk.time_pb5(1)),2)+ $
    ' ' + STRTRIM(STRING(hsk.time_pb5(2)),2), $
    'Image Time: ' + STRTRIM(STRING(hsk.img_minus_msec),2)+ $
    '/' + '+'+STRTRIM(STRING(hsk.img_plus_msec),2)+' msec', $
    '  Gap Flag: ' + STRTRIM(STRING(hsk.post_gap_flag),2), $
    ' Qual Flag: ' + STRTRIM(STRING(hsk.quality_flag),2), $
    'Nom Period: '+ STRTRIM(STRING(hsk.nominal_output_period),2)+' min', $
    '    Filter: ' + ufil(hsk), $
    '      Gain: ' + STRTRIM(STRING(hsk.gain),2), $
    '      Mode: ' + umode(hsk), $
    ' DSP Angle: ' + STRTRIM(STRING(hsk.dsp_angle,FORMAT='(F8.4)'),2) $
          + ' deg', $
    '   Obs Seq: ' + STRTRIM(STRING(hsk.seq),2), $
    '      Door: ' + udoor(hsk), $
    '  Distance: ' + STRTRIM(STRING(sc_re,FORMAT='(F6.2)'),2) $
          + ' Re', $
    '    System: ' + usys(hsk), $
    ' ', $
    '  Position: ' + STRTRIM(STRING(hsk.gci_position(0),FORMAT='(E10.2)'),0)+ $
               ' ' + STRTRIM(STRING(hsk.gci_position(1),FORMAT='(E10.2)'),0)+ $
               ' ' + STRTRIM(STRING(hsk.gci_position(2),FORMAT='(E10.2)'),0), $
    '  Attitude: ' + STRTRIM(STRING(hsk.attitude(0),FORMAT='(E10.2)'),0)+ $
               ' ' + STRTRIM(STRING(hsk.attitude(1),FORMAT='(E10.2)'),0)+ $
               ' ' + STRTRIM(STRING(hsk.attitude(2),FORMAT='(E10.2)'),0), $
    '  Look Dir: ' + STRTRIM(STRING(hsk.gci_look_dir(0),FORMAT='(E10.2)'),0)+ $
               ' ' + STRTRIM(STRING(hsk.gci_look_dir(1),FORMAT='(E10.2)'),0)+ $
               ' ' + STRTRIM(STRING(hsk.gci_look_dir(2),FORMAT='(E10.2)'),0), $
    '   Sun Dir: ' + STRTRIM(STRING(hsk.gci_sun(0),FORMAT='(E10.2)'),0)+ $
               ' ' + STRTRIM(STRING(hsk.gci_sun(1),FORMAT='(E10.2)'),0)+ $
               ' ' + STRTRIM(STRING(hsk.gci_sun(2),FORMAT='(E10.2)'),0) $
    ]
    
    WIDGET_CONTROL,hskWindow,SET_VALUE=hsk_string

END

                         
PRO show_record,event
                                                
    ; the values of the params common block are set in init_params                     
    COMMON params $                      
           ,win_img_xsize, win_img_ysize $        ; image window size 
           ,win_prf_xsize, win_prf_ysize $        ; profile window size
           ,imx, imy $                            ; normalized image placement
           ,cbdelta,cbwidth,cbheight $            ; color bar size           
           ,color_table_ndx $                     ; default color table     
           ,map_grid_cndx,  map_cont_cndx         ; map colors             
              
    COMMON display,pixel_flag,max_flag,crs_flag
    COMMON show_record,img,max_common,min
    COMMON IDS,  mouseWindow,hskWindow,prof,draw,summDraw,slider,maxSlider

    WIDGET_CONTROL,event.top,GET_UVALUE=info
    hsk = info.hsk
    j   = info.j
    infilename = info.infilename
    numframes = info.numframes

    ;open CDF and read image              
    read_image_kpf,j,image,pimage1,pimage2,infilename             
    img=image

    ;remove corner fill values from image             
    image = image * (image NE -127)                  
                                                   
    ;remove standard fill values from image             
    image = image * (image NE -32768)                     

    info.image_data =image
    info.lat_img = pimage1
    info.lon_img = pimage2

    ;the image is rotated to match orbital orientation. 
    image = ROTATE(image,info.rot_val) 
    lat_img = ROTATE(pimage1,info.rot_val)
    lon_img = ROTATE(pimage2,info.rot_val)

    ;update max slider
    WIDGET_CONTROL,event.top,SET_UVALUE=info
    mng_slider,event
    WIDGET_CONTROL,event.top,GET_UVALUE=info

    ;clear screen after      
    ;image has been read to prevent having                     
    ;user stare at empty screen while waiting                     
    WIDGET_CONTROL,draw,GET_VALUE=drawWID
    WSET,drawWID
    ERASE                                                                                                                                         
    ; also clear profile window
    clear_prof

    ; setup normalized screen coordinates for image display                 
    cx1=imx                                                                
    cx2=imx+(200./!d.x_size)                                              
    cx3=cx2+(cbdelta/!d.x_size)                                          
    cx4=cx3+(cbwidth/!d.x_size)                                                                                                              
    cy1=imy             
    cy2=imy+(228./!d.y_size)             
    cy3=cy1                                                                  
    cy4=cy2                             
                                                                                   
    ;find minimum value
    max = info.max
    min = info.min
    max_common = max

    ;display image using normalized screen coords              
    image = BYTSCL(image,MAX=max,MIN=min)
    TV,image,imx,imx,/NORMAL
    !P.POSITION=[cx1,cy1,cx2,cy2]                            

    CASE pixel_flag OF
      0: BEGIN
           plot_lat_grid,lat_img,map_grid_cndx
           plot_lon_grid,lat_img,lon_img,map_grid_cndx
         END
     -1: BEGIN
           geo_to_mag,lat_img,lon_img,lat_mag,lon_mag
           plot_lat_grid,lat_mag,map_grid_cndx
           plot_lon_grid,lat_mag,lon_mag,map_grid_cndx
         END
      ELSE:
    ENDCASE
                                      
    ;overdraw box with row/col labels  
    xrange=[199,0]
    yrange=[227,0]
    PLOT,xrange,yrange $
         ,/NORMAL,/NOERASE,YSTYLE=1,XSTYLE=1,PSYM=3 $  
         ,XRANGE=xrange,YRANGE=yrange $             
         ,XTITLE='column',YTITLE='row'  
                                                                  
    ;draw color bar   
    color_bar,min,max

    ;annotate image             
    annotate_image,info
  
endpt:                                                                                                                                                                            
END                                                                                                                                                                   
PRO color_bar,min,max

    COMMON params $                      
           ,win_img_xsize, win_img_ysize $        ; image window size 
           ,win_prf_xsize, win_prf_ysize $        ; profile window size
           ,imx, imy $                            ; normalized image placement
           ,cbdelta,cbwidth,cbheight $            ; color bar size           
           ,color_table_ndx $                     ; default color table     
           ,map_grid_cndx,  map_cont_cndx         ; map colors             
              

    ;cx3=0.8
    ;cx4=cx3+(cbwidth/!d.x_size)
    ;cy3=0.25
    ;cy4=cy3+(cbheight/!d.y_size)

        cx1=imx                                                                
        cx2=imx+(200./!d.x_size)                                              
        cx3=cx2+(cbdelta/!d.x_size)                                          
        cx4=cx3+(cbwidth/!d.x_size)                                                                                                              
        cy1=imy             
        cy2=imy+(228./!d.y_size)             
        cy3=cy1                                                                  
        cy4=cy2                             
                                                                                   
    ;draw color bar                           
    cdepth=!d.n_colors                                     
    tmp=INDGEN(cdepth)                                   
    bar=CONGRID(ROTATE(tmp,1),cbwidth,cbheight) 
    TVSCL,bar,cx3,cy3,/NORMAL                 
                           
    ;frame color bar                       
    !P.POSITION=[cx3,cy3,cx4,cy4]                           
    PLOT,[0,1],[min,max] $                           
          ,/NORMAL,/NOERASE,/NODATA $                          
          ,XTICKS=1,XSTYLE=1,XTICKNAME=[' ',' '] $                          
          ,YTICKS=1,YTICKNAME=[' ',' ']                         
    !P.POSITION=0                                    
    AXIS,YAXIS=1,YRANGE=[min,max],CHARSIZE=0.8 $
                   ,YTITLE='photon cm^-2 s^-1'

END
  
PRO plot_mag_map,img,latmin,min,max,rot

    oldPosition=!P.POSITION
    !P.POSITION=0
    !P.REGION=[0.1,0.2,0.75,0.95]
    MAP_SET,90,0,rot,/AZIMUTHAL,LIMIT=[50,-180,90,180]
    mpimg=MAP_IMAGE(img,x,y,LATMIN=latmin,COMPRESS=1,/WHOLE_MAP)
    TVSCL,mpimg,x,y

    MAP_SET,90,0,0,/AZIMUTHAL,LIMIT=[50,-180,90,180],/NOERASE
    MAP_GRID,/LABEL,LONLAB=0,LONDEL=90.,LATDEL=10.0,LATLAB=45
    !P.REGION=0

    color_bar,min,max

    !P.POSITION=oldPosition

END  

PRO geo_to_mag,lat,lon,lat_mag,lon_mag

    ;from code supplied by Dirk Lummerzheim

    lat_p=11*!dtor    ; geographic co-latitude of north pole
    lon_p=-70*!dtor   ; geographic longitude (east positive) of north pole

    ;convert input values from degrees to radians
    lat_g=(90-lat)*!dtor  ; convert to co-latitude
    lon_g=lon*!dtor

    ;convert to magnetic coords
    lat_mag=acos( cos(lat_p)*cos(lat_g) + $
                  sin(lat_p)*sin(lat_g)*cos(lon_g-lon_p) )
    lon_mag=asin( sin(lat_g)*sin(lon_g-lon_p)/ $
                       sin(lat_mag) )

    ;check for bad values of lon
    i=where(finite(lon_mag) lt 1, ii)
    if ii gt 0 then lon_mag(i)=0

    ;convert back from radians to degrees
    lon_mag=lon_mag/!dtor
    lat_mag=90-lat_mag/!dtor  ; convert from co-latitude

    ;??
    lm=atan( tan(lat_p), cos(lon_g-lon_p) )
    i=where(lat_g gt lm, ii)
    if ii gt 0 then lon_mag(i)=180-lon_mag(i)

    ;??
    lon_mag=360-((lon_mag + 180) mod 360)

    ;shift into range -180 to +180
    ;ndx=WHERE(lon_mag GT 180)
    ;lon_mag(ndx) = lon_mag(ndx)-360.
end

PRO plot_geo_map,img,min,max,latmin,lonmin,p0lat,p0lon,rot,cndx

    oldPosition=!P.POSITION
    !P.POSITION=0
    !P.REGION=[0.1,0.2,0.75,0.95]
    MAP_SET,p0lat,p0lon,rot,/SATELLITE,SAT_P=[9,0,0],LIMIT=[40,0,90,360]
    mpimg=MAP_IMAGE(img,x,y,xs,ys,LATMIN=latmin,LONMIN=lonmin $
                       ,COMPRESS=1,/WHOLE_MAP)
    image=BYTSCL(mpimg,MIN=min,MAX=max)
    TVSCL,image,x,y
    MAP_CONTINENTS,COLOR=cndx
    MAP_GRID,/LABEL,LONLAB=latmin,COLOR=cndx,LATDEL=20
    !P.REGION=0

    color_bar,min,max

    !P.POSITION=oldPosition
END   
PRO plot_lon_grid,lat_img,lon_img,cndx
   !P.REGION=!P.POSITION
   CONTOUR,lon_img,/NOERASE $
      ,XSTYLE=5,YSTYLE=5 $
      ,LEVELS=[0,90,180,270] $
      ,C_LABELS=[1,1,1,1,1,1,1,1,0] $
      ,COLOR=cndx
   !P.REGION=0

    ;label north pole
    IF(MAX(lat_img) GT 85) THEN BEGIN
      FOR i=90,85,-1 DO BEGIN
         ndx=WHERE(ABS(lat_img-i) LT 1,count)
         IF(count GT 0) THEN BEGIN
            x=ndx(0) MOD 200
            y=FIX(ndx(0)/200)
            XYOUTS,x,y,'N',ALIGNMENT=0.5,COLOR=cndx
            GOTO,jmpta
         ENDIF
      ENDFOR
    ENDIF
jmpta:

    ;label prime meridian
    ndx=WHERE((ABS(lat_img)-80) LT 1,count)
    IF(count GT 0) THEN BEGIN
       ndx1=WHERE(ABS(lon_img(ndx)) LT 10,count)
       IF(count GT 0) THEN BEGIN
         x=ndx1(0) MOD 200
         y=FIX(ndx1(0)/200)
         XYOUTS,x,y,'+',ALIGNMENT=0.5,COLOR=cndx
       ENDIF
    ENDIF

END

PRO plot_lat_grid,lat_img,cndx
    !P.REGION=!P.POSITION
    CONTOUR,lat_img,/NOERASE $
       ,XSTYLE=5,YSTYLE=5 $
       ,LEVELS=[-85,-80,-75,-70,-60,-50,-30,-10,10,30,50,70,80] $
       ,C_LABELS=[1,1,1,1,1,1,1,1,1,1,1,1,1] $
       ,COLOR=cndx
    !P.REGION=0
END

PRO bin_data,image,lat,lon,latmin,latstep,lonstep,imgbins,latbins,lonbins

   ;calculate size of rebinned image
   nlat=FIX(0.99+((90.-latmin)/latstep))
   nlon=FIX(0.99+(360./lonstep))
   imgbins=FLTARR(nlon,nlat)
   latbins=FLTARR(nlon,nlat)
   lonbins=FLTARR(nlon,nlat)
   cntbins=FLTARR(nlon,nlat)

   ;rebin data
   FOR i=0,227 DO BEGIN
       FOR j=0,199 DO BEGIN

           row = FIX((lat(j,i)-latmin)/latstep)
           col = FIX((lon(j,i))/lonstep)

           IF((col GE 0) AND (row GE 0)) AND  $
             ((col LT nlon) AND (row LT nlat)) THEN BEGIN
              imgbins(col,row) = imgbins(col,row) + image(j,i)
              latbins(col,row) = latbins(col,row) + lat(j,i)
              lonbins(col,row) = lonbins(col,row) + lon(j,i)
              cntbins(col,row) = cntbins(col,row) + 1
           ENDIF

       ENDFOR
   ENDFOR

   ndx = WHERE(cntbins EQ 0,count)
   IF (count GT 0) THEN cntbins(ndx)=1

   imgbins = imgbins/cntbins
   latbins = latbins/cntbins
   lonbins = lonbins/cntbins

   ;shift images to change lon to -180 to +180 range for map_image call
   imgbins=SHIFT(imgbins,nlon/2,0)
   latbins=SHIFT(latbins,nlon/2,0)
   lonbins=SHIFT(lonbins,nlon/2,0)

   tmp=lonbins
   ndx=WHERE(tmp GT 180,count)
   IF(count GT 0) THEN BEGIN
      tmp(ndx)=lonbins(ndx)-360.
      lonbins=tmp
   ENDIF

END

; driver ---------------------------------------                                                                                     
                                                                                                                                 
PRO kpfvu,infilename

   COMMON BASES,tlb,menubase             

   IF(KEYWORD_SET(infilename)) THEN BEGIN
      IF(STRUPCASE(infilename) EQ 'HELP') THEN BEGIN
         tlb=-1
         show_kpfvu_help
         GOTO,endpt
      ENDIF
   ENDIF ELSE infilename=''

   ;check operating environment
   IF(!D.FLAGS AND 8) EQ 0 THEN BEGIN
     PRINT,' '
     PRINT,'ERROR: This application requires image support.'
     PRINT,'       Not present on current display device.'
     PRINT,' '
     GOTO,endpt
   END
   IF(!D.FLAGS AND 16) EQ 0 THEN BEGIN
     PRINT,' '
     PRINT,'ERROR: This application requires color display.'
     PRINT,'       Not present on current display device.'
     PRINT,' '
     GOTO,endpt
   END
   IF(!D.FLAGS AND 256) EQ 0 THEN BEGIN
     PRINT,' '
     PRINT,'ERROR: This application requires windows support.'
     PRINT,'       Not present on current display device.'
     PRINT,' '
     GOTO,endpt
   END
   IF(!D.FLAGS AND 65536) EQ 0 THEN BEGIN
     PRINT,' '
     PRINT,'ERROR: This application requires widget support.'
     PRINT,'       Not present on current display device.'
     PRINT,' '
     GOTO,endpt
   END

   ; set up 8-bit color on a 24-bit machine

;  device, decomposed=0

   ;initialize parameter block                       
   init_param         
    
   ;display kpf 
   kpf,infilename

endpt:                     
                                                                                                                                    
   CLOSE,/ALL                 
                             
                            
END   ;---- end of driver         
     

pro end_app,event 
   COMMON quiet_val,oldQuietVal
   widget_control, event.top ,/destroy   
   !QUIET=oldQuietVal
end                                     
    

 
PRO PSprint,WindowNumber,fname
     
    COMMON params $                      
           ,win_img_xsize, win_img_ysize $        ; image window size 
           ,win_prf_xsize, win_prf_ysize $        ; profile window size
           ,imx, imy $                            ; normalized image placement
           ,cbdelta,cbwidth,cbheight $            ; color bar size      
           ,color_table_ndx $                     ; default color table      
           ,map_grid_cndx,  map_cont_cndx         ; map colors        
                       
; save current device     
oldDevice=!D.Name     
   
; get contents of graphics window(WindowNumber)     
;x=tvrd(WindowNumber)     
;x=tvrd(0,0,win_img_xsize,win_img_ysize)
x=tvrd(0,0,!d.x_size,!d.y_size)

   
; change device to PostScript with same color table     
Set_Plot,'ps',/copy     
   
; set filename   
device,Filename=fname
    
; read in color table     
;tvlct,r,g,b     
  
; set output to be 8 bit color     
device,bits_per_pixel=8,/color     
  
; set background from black to white     
;tvlct,255,255,255,0     
 
; send graphics window to PostScript file     
tv,x     
  
; close file     
device,/close  
 
; restore device       
Set_Plot,oldDevice     
     
END     

PRO create_hsk_structure,hsk

; examine KPF cdf for descriptions
; of each variable

hsk = {hskstruct, $
       epoch:          0D, $
       time_pb5:       LONARR(3), $
       img_minus_msec: 0L, $
       img_plus_msec:  0L, $
       post_gap_flag:  0L, $
       quality_flag:   0L, $
       kpgs_version:   'old ', $
       nominal_output_period:  0L, $
       system:         0L, $
       seq:            0L, $
       mode:           0L, $
       gain:           0L, $
       door:           0L, $
       gci_position:   FLTARR(3), $
       attitude:       FLTARR(3), $
       gci_sun:        FLTARR(3), $
       gci_look_dir:   DBLARR(3), $
       dsp_angle:      0.0, $
       filter:         0L }

END

PRO read_hsk_kpf,record,datafilename,hsk

   ;define housekeeping array
   create_hsk_structure,hsk

   ;open cdf 
   id=CDF_OPEN(datafilename)                                                                                                                                      
   ;read housekeeping.  The CDF_VARGET1 statement 
   ;will not read directly into a structure.  
   ;Therefore a temporary variable 'tmp' is used. 

   cdfstruct = CDF_INQUIRE(id)
   IF(cdfstruct.nvars EQ 31) THEN BEGIN
      CDF_VARGET1,id,'KPGS_VERSION',tmp
      hsk.kpgs_version=STRING(tmp)
   ENDIF

   CDF_VARGET1,id,'Epoch',tmp,REC_START=record 
   hsk.epoch=tmp 

   CDF_VARGET1,id,'IMG_MINUS_MSEC',tmp,REC_START=record 
   hsk.img_minus_msec=tmp 

   CDF_VARGET1,id,'IMG_PLUS_MSEC',tmp,REC_START=record 
   hsk.img_plus_msec=tmp 

   CDF_VARGET1,id,'POST_GAP_FLAG',tmp,REC_START=record 
   hsk.post_gap_flag=tmp 

   CDF_VARGET1,id,'QUALITY_FLAG',tmp,REC_START=record 
   hsk.quality_flag=tmp 

   CDF_VARGET1,id,'NOMINAL_OUTPUT_PERIOD',tmp,REC_START=record 
   hsk.nominal_output_period=tmp 

   CDF_VARGET1,id,'SYSTEM',tmp,REC_START=record 
   hsk.system=tmp 

   CDF_VARGET1,id,'SEQ',tmp,REC_START=record 
   hsk.seq=tmp 

   CDF_VARGET1,id,'MODE',tmp,REC_START=record 
   hsk.mode=tmp 

   CDF_VARGET1,id,'GAIN',tmp,REC_START=record 
   hsk.gain=tmp 

   CDF_VARGET1,id,'DOOR',tmp,REC_START=record 
   hsk.door=tmp 

   CDF_VARGET1,id,'DSP_ANGLE',tmp,REC_START=record 
   hsk.dsp_angle=tmp 

   CDF_VARGET1,id,'FILTER',tmp,REC_START=record 
   hsk.filter=tmp 

   ;read multidimensional data with the CDF_VARGET statement
   CDF_VARGET,id,'Time_PB5',tmp,COUNT=[3,1,1,1,1],REC_START=record   
   hsk.time_pb5=tmp

   CDF_VARGET,id,'GCI_POSITION',tmp,COUNT=[3,1,1,1,1],REC_START=record
   hsk.gci_position=tmp

   CDF_VARGET,id,'ATTITUDE',tmp,COUNT=[3,1,1,1,1],REC_START=record   
   hsk.attitude=tmp

   CDF_VARGET,id,'GCI_SUN',tmp,COUNT=[3,1,1,1,1],REC_START=record   
   hsk.gci_sun=tmp

   CDF_VARGET,id,'GCI_LOOK_DIR',tmp,COUNT=[3,1,1,1,1],REC_START=record 
   hsk.gci_look_dir=tmp

   ;close cdf 
   CDF_CLOSE,id 

END                                                                

 

PRO summary,qual_ary,pgf_ary,gain_ary,seq_ary,dsp_ary,sysnum,doornum,imgnum $ 
           ,rsc,infilename,time_pb5,jmin,jmax                                  
        
       old_char_size=!p.charsize                                              
       !p.charsize=0.85                                                      
                                                                   
      ;quality flag.  plot log base 2 of flag to show                
      ;which bit is set         
      qtemp=FLTARR(N_ELEMENTS(qual_ary))                           
      qndx = WHERE(qual_ary GT 0,count)                          
      IF count NE 0 THEN BEGIN                          
       qtemp=qual_ary(qndx)    
       qtemp=ALOG(qtemp)/ALOG(2)                           
      ENDIF                          
                                                     
                                                                   
      ; set up reference points in normalized coordinates                   
      xref1a=0.1                                                           
      xref2a=0.45                                                         
      yref1a=0.92                                                                              
      
      xref1b=0.6 
      xref2b=0.95 
      yref1b=0.92 
                                                                      
      ydel=-0.17 
      yspc=-0.03 
                                                                                                     
      ;spacecraft height
      mlt=1                   
      ytop=yref1a+((ydel+yspc)*(mlt-1))   
      ybot=ytop+ydel                                                         
      plot,rsc,psym=10,/norm,/noerase,position=[xref1a,ybot,xref2a,ytop] $
                   ,yrange=[0,10],thick=3,ystyle=1,yticks=5,xstyle=4 $    
                   ,ytitle='Rsc'                                         

      ;dsp angle
      mlt=2 
      ytop=yref1a+((ydel+yspc)*(mlt-1))
      ybot=ytop+ydel                  
      plot,dsp_ary,psym=10,/norm,/noerase,position=[xref1a,ybot,xref2a,ytop] $
                   ,yrange=[-40,40],thick=3,ystyle=1,yticks=4,xstyle=4 $    
                   ,ytitle='DSP'                                           

      ;filter
      mlt=3
      ytop=yref1a+((ydel+yspc)*(mlt-1)) 
      ybot=ytop+ydel
      plot,imgnum,psym=10,/norm,/noerase,position=[xref1a,ybot,xref2a,ytop]  $
                   ,yrange=[1,6],thick=3,ystyle=1,yticks=5,xstyle=4 $       
                   ,ytickname=['?','1304','1356','LBHS','LBHL','SOLR'] $   
                   ,ytitle='filter'

       ;gain setting   
       mlt=4   
       ytop=yref1a+((ydel+yspc)*(mlt-1))  
       ybot=ytop+ydel 
       plot,gain_ary,psym=10,/norm,/noerase,position=[xref1a,ybot,xref2a,ytop] $
                   ,yrange=[0,16],ystyle=1,xstyle=4,yticks=4,thick=3 $         
                   ,ytitle='Gain'                                             

       ;draw axis at bottom
       axis,xaxis=0,xtitle='Record' 

       ;quality 
       mlt=1 
       ytop=yref1b+((ydel+yspc)*(mlt-1))   
       ybot=ytop+ydel    
       plot,qtemp,psym=10,/norm,/noerase,position=[xref1b,ybot,xref2b,ytop] $  
                   ,yrange=[0,25],ystyle=1,xstyle=4,yticks=5,thick=3 $          
                   ,ytitle='QF High Bit'
                                                                      
       ;post gap flag 
       mlt=2 
       ytop=yref1b+((ydel+yspc)*(mlt-1)) 
       ybot=ytop+ydel                   
       plot,pgf_ary,psym=10,/norm,/noerase,position=[xref1b,ybot,xref2b,ytop] $
                   ,yrange=[0,25],ystyle=1,xstyle=4,yticks=5,thick=3 $       
                   ,ytitle='Gap Flag'                                       
                                                                      
                                                                      
       ;observing sequence
       mlt=3             
       ytop=yref1b+((ydel+yspc)*(mlt-1))
       ybot=ytop+ydel                  
       plot,seq_ary,psym=10,/norm,/noerase,position=[xref1b,ybot,xref2b,ytop] $
                   ,yrange=[0,50],thick=3,ystyle=1,yticks=5,xstyle=4 $  
                   ,ytitle='Seq'                                       
                                                                      
       ;door
       mlt=4             
       ytop=yref1b+((ydel+yspc)*(mlt-1))
       ybot=ytop+ydel                  
       plot,doornum,psym=10,/norm,/noerase,position=[xref1b,ybot,xref2b,ytop] $
                   ,yrange=[-2,2],thick=3,ystyle=1,yticks=4,xstyle=4 $       
                   ,ytickname=[' ','CLS','?','OPN',' '] $
                   ,ytitle='Door'
                                                      
                                                                               
       ;draw axis at bottom 
       axis,xaxis=0,xtitle='Record' 
                                                                               
       !p.charsize = old_char_size 
                                                                   
END                                                                      
                                                         
                                                         
                                                     
                                                     
; routine to find number of records in cdf -------------------                                                         
                                                         
PRO getcdfrecs,datafilename,numrecs                                                            
                                                            
   ;initialize output                                                         
   numrecs=0                                                            
                                                         
   IF datafilename NE '' THEN BEGIN                                                          
       id=CDF_OPEN(datafilename)                                                                                   
       result=CDF_INQUIRE(id)                                                            
       numrecs=result.maxrec+1                                                            
       CDF_CLOSE,id                                                         
   ENDIF                                                            
                                                            
END  ; end of getcdfrecs                                                           
                                                                                                                   
                                                         
; routine to read nonimage parameters from cdf ----------------                                                         
                                                         
PRO read_nonimage_kpf,qual_ary,pgf_ary,gain_ary,seq_ary,dsp_ary,gci_ary $                                                               
       ,system,filter,door,time_pb5,attitude,datafilename                                                                                                                                                                                  
                                                                                                                                                       
   IF datafilename NE '' THEN BEGIN                                                                                                           
       id=CDF_OPEN(datafilename)                                                                                                                                                                                         
       result=CDF_INQUIRE(id)                                                                            
                                                                     
       data = INTARR(result.maxrec+1)                                                                     
       CDF_VARGET,id,'QUALITY_FLAG',data,count=[1,1,1,1,1] $                                                                     
           ,rec_count=result.maxrec+1                                                                      
       IF(result.maxrec GT 0) THEN $                                                                     
           qual_ary=REFORM(TRANSPOSE(REFORM(data))) $                                                                     
           ELSE qual_ary = data                                                                     
                                                                     
       data = INTARR(result.maxrec+1)                                                                     
       CDF_VARGET,id,'POST_GAP_FLAG',data,count=[1,1,1,1,1] $                                                                     
           ,rec_count=result.maxrec+1                                                                      
        IF(result.maxrec GT 0) THEN $                                                                     
           pgf_ary=REFORM(TRANSPOSE(REFORM(data))) $                                                                     
           ELSE pgf_ary = data                                                                     
                                                                     
       data = INTARR(result.maxrec+1)                                                                     
       CDF_VARGET,id,'GAIN',data,count=[1,1,1,1,1] $                                                                     
           ,rec_count=result.maxrec+1                                                                      
        IF(result.maxrec GT 0) THEN $                                                                     
           gain_ary=REFORM(TRANSPOSE(REFORM(data))) $                                                                     
           ELSE gain_ary = data                                                                     
                                                                     
       data = INTARR(result.maxrec+1)                                                                     
       CDF_VARGET,id,'SEQ',data,count=[1,1,1,1,1] $                                                                     
           ,rec_count=result.maxrec+1                                                                      
        IF(result.maxrec GT 0) THEN $                                                                     
           seq_ary=REFORM(TRANSPOSE(REFORM(data))) $                                                                     
           ELSE seq_ary = data                                                                     
                                                                     
       data = INTARR(result.maxrec+1)                                                                     
       CDF_VARGET,id,'DSP_ANGLE',data,count=[1,1,1,1,1] $                                                                     
           ,rec_count=result.maxrec+1                                                                      
        IF(result.maxrec GT 0) THEN $                                                                     
           dsp_ary=REFORM(TRANSPOSE(REFORM(data))) $                                                                     
           ELSE dsp_ary = data                                                                     
                                                                     
       data = FLTARR(result.maxrec+1)                                                                     
       CDF_VARGET,id,'GCI_POSITION',data,count=[3,1,1,1,1] $                                                                     
           ,rec_count=result.maxrec+1                                                                      
        IF(result.maxrec GT 0) THEN $                                                                     
           gci_ary=REFORM(data) $                                                                     
           ELSE gci_ary = data                                                                     
                                                               
       data = INTARR(result.maxrec+1)                                                                     
       CDF_VARGET,id,'Time_PB5',data,count=[3,1,1,1,1] $                                                                     
           ,rec_count=result.maxrec+1                                                                      
        IF(result.maxrec GT 0) THEN $                                                                     
           Time_PB5=REFORM(data) $                                                                     
           ELSE Time_PB5 = data                                                                     
                                                        
       data = INTARR(result.maxrec+1)                                                                     
       CDF_VARGET,id,'ATTITUDE',data,count=[3,1,1,1,1] $                                                                     
           ,rec_count=result.maxrec+1                                                                      
        IF(result.maxrec GT 0) THEN $                                                                     
           attitude=REFORM(data) $                                                                     
           ELSE attitude = data                                                                     
                                                        
       data=INTARR(result.maxrec+1)                                                                     
       CDF_VARGET,id,'SYSTEM',data,count=[1,1,1,1,1] $                                                                     
           ,rec_count=result.maxrec+1                                                                      
        IF(result.maxrec GT 0) THEN $                                                                     
           system = REFORM(data)   $                                                                  
           ELSE system  = data                                                                     
                                                                     
       data=INTARR(result.maxrec+1)                                                                     
       CDF_VARGET,id,'FILTER',data,count=[1,1,1,1,1] $                                                                     
           ,rec_count=result.maxrec+1                                                                      
        IF(result.maxrec GT 0) THEN $                                                                     
           filter = REFORM(data)   $                                                                  
           ELSE filter  = data                                                                     
                                                                     
       data=INTARR(result.maxrec+1)                                                                     
       CDF_VARGET,id,'DOOR',data,count=[1,1,1,1,1] $                                                                     
           ,rec_count=result.maxrec+1                                                                      
        IF(result.maxrec GT 0) THEN $                                                                     
           door = REFORM(data)   $                                                                  
           ELSE door = data                                                                     
                                                         
       CDF_CLOSE,id                                                                         
                                                                     
   ENDIF                                                                
                                                                        
END ; end of read_nonimage_kpf                                                          
                                                         
                                                         
; routine to read image from cdf ---------------------------                                                         
                                                         
PRO read_image_kpf,rec,image,pimage1,pimage2,datafilename                                                                                                                                                                                  
                                                                                                                                                       
   image=FLTARR(200,228)                                                                            
   pimage1=FLTARR(20,23)                                                                      
   pimage2=FLTARR(20,23)                                                                      
   sub_image=FLTARR(50,228)                                  
   data=FLTARR(228,200)                                                                           
   pdata=FLTARR(23,20)                                                                                   
   IF datafilename NE '' THEN BEGIN                                                                                                           
       id=CDF_OPEN(datafilename)                                                                                                                                                                                         
       result=CDF_INQUIRE(id)                                                                            
                                                                      
       IF !VERSION.OS EQ 'Win32' THEN BEGIN                                  
        ;The CDF interface under the 32-bit Windows versions of IDL cannot handle                                  
        ;transfers of >64K.  We have to read the image in 4 passes.                                  
                                   
        CDF_VARGET,id,'IMAGE_DATA',sub_image,REC_START=rec,OFFSET=[0,0,0,0,0],COUNT=[1,228,50,1,1]                                  
        image(0:49,*) = TRANSPOSE(REFORM(sub_image))                     
            
        CDF_VARGET,id,'IMAGE_DATA',sub_image,REC_START=rec,OFFSET=[0,0,50,0,0],COUNT=[1,228,50,1,1]                                  
        image(50:99,*) = TRANSPOSE(REFORM(sub_image))                                  
                                                                                                        
        CDF_VARGET,id,'IMAGE_DATA',sub_image,REC_START=rec,OFFSET=[0,0,100,0,0],COUNT=[1,228,50,1,1]                                  
        image(100:149,*) = TRANSPOSE(REFORM(sub_image))                                  
                                                                                                        
        CDF_VARGET,id,'IMAGE_DATA',sub_image,REC_START=rec,OFFSET=[0,0,150,0,0],COUNT=[1,228,50,1,1]                                  
        image(150:199,*) = TRANSPOSE(REFORM(sub_image))                                  
            
       ENDIF ELSE BEGIN                                  
          CDF_VARGET,id,'IMAGE_DATA',data,REC_START=rec,count=[1,228,200,1,1]             
          image=TRANSPOSE(REFORM(data))                   
       ENDELSE                                  
            
       CDF_VARGET,id,'GEODETIC_LAT',pdata,REC_START=rec,count=[1,1,1,23,20]                                                                         
       pimage1=TRANSPOSE(REFORM(pdata))                                                                 
       ndx=WHERE(pimage1 LT 0)                                                                              
       ;if ndx NE -1 THEN pimage1(ndx) = 0                                                                      
                                                                      
       CDF_VARGET,id,'GEODETIC_LONG',pdata,REC_START=rec,count=[1,1,1,23,20]                                                                         
       pimage2=TRANSPOSE(REFORM(pdata))                                                                       
       ndx=WHERE(pimage2 LT 0)                                                                              
       ;if ndx NE -1 THEN pimage2(ndx) = 0                                                                      
                                                                      
       CDF_CLOSE,id                                                                         
   ENDIF                                                                            
END  ;end of read_image_kpf