;+
; NAME: sotobs__define
;
;
;
; PURPOSE: Definition of the sotobs (SOT observation) class, a subclass of
;          hinobs, which again is a subclass of anyobs. The class definition
;          contains methods that differs from those of hinobs and anyobs.
;
;
;
;
; METHODS: See hinobs__define and anyobs__define
;
;
;
; COMMON BLOCKS: none
;
;
;
; WRITTEN: Terje Fredvik, UiO, December 2007
;
;
;
;
; MODIFICATION HISTORY:
;          2. Sep 2010 Terje Fredvik: Removed old modification history.  
;          2. Sep 2010 Terje Fredvik: Call fg_prep if keyword NOPREP isn't set
;         31. jan 2011 Terje Fredvik:  # Do not set version (SVN revision is
;                                      set in hinobs__define)
;         14. Dec 2011 Terje Fredvik:  Added method _mk_jpg2000_specific -
;                                      a Helioviewer compatible jpg2000 image
;         25. Jul 2012 Terje Fredvik: Deleted method ::_plot_helio, code is in 
;                                     hinobs::plot_helio
;         11. Apr 2013 Terje Fredvik: added info about new superclass anyobs
;         16. Dec 2014 Terje Fredvik: if fg_prep crashes try once again with
;                                     no_flatfield=1
;         30. Jul 2014 Terje Fredvik: gt_FOVcorner_radius no longer private. 
;                                     Added dirty hack in order to return text
;                                     if image is radially filtered:
;                                     _gt_extra_title.
;-

FUNCTION sotobs::init, file, _ref_extra=extra
  IF self->hinobs::init(file, _extra=extra) EQ 0 $
  THEN return,0
  
  self.thumbsmoothsz = 15
  
  return,1  
END


PRO sotobs::cleanup
  self->hinobs::cleanup
 
  print,"Cleaning up (sotobs)"
END


FUNCTION sotobs::_color_table_txt,i, _extra=extra
  self->private
  instrume = self->get(/instrume)
  
  wanted_ct_txt = 'INTENSITY'
  
  IF instrume EQ 'SOT/WB' THEN wanted_ct_txt = 'INTENSITY'
  
  IF instrume EQ 'SOT/NB' THEN BEGIN
     IF i EQ 0 THEN wanted_ct_txt = 'INTENSITY' ELSE $
        wanted_ct_txt = 'STOKESQUV' ; SOT/NB: 1 Stokes I, the rest are QUV imgs
  ENDIF
  
  IF instrume EQ 'SOT/SP' THEN BEGIN
     IF i LE 1 THEN wanted_ct_txt = 'INTENSITY' ELSE $
        wanted_ct_txt = 'STOKESQUV' ; SOT/SP lev 0 has 2 Stokes I, the rest QUV
  ENDIF
  
  ; If the radialfiltering keyword has been set when calling plot_image
  IF size(extra,/tname) NE 'UNDEFINED' THEN IF $
     strmid(tag_names(extra),0,3) EQ 'RAD' THEN wanted_ct_txt = 'RADFILT'
  
  return, wanted_ct_txt

END


PRO sotobs::_instrument_specific_read_method, data, header 
  self->private
  file = self.file
  shortfile = strmid(file, strpos(file,'/',/reverse_search)+1, 100) 
  instcode = strupcase(strmid(shortfile,0,1))
  
  IF instcode EQ 'F' THEN BEGIN  
     read_sot, file, header0, data0, /quiet   
     IF ~self->get(/prep) THEN BEGIN 
        data = data0
        header = header0
     ENDIF ELSE BEGIN 
        ;; Some FG instrument configurations currently lack flat field files in
        ;; SolarSoft. If fg_prep fails we therefore try to run it once more
        ;; with no_flatfield = 1. If it still fails the program will
        ;; ungracefully crash, as it is supposed to do.
        no_flatfield = 0
        catch, error_status
        IF error_status NE 0 then BEGIN 
           ;; An error is caught!
           print,!error_state.msg
           catch,/cancel ; Cancel catching errors
           print,'Trying to run fg_prep with no_flatfield set to 1'
           no_flatfield = 1
        ENDIF
        
        fg_prep, header0, data0, header, data,/despike, no_flatfield=no_flatfield
        
     ENDELSE
     
  ENDIF ELSE data = readfits(file,header,/silent) ;; i.e. SOT/SP single file

  IF (size(header,/tname)) EQ 'STRUCT' and (size(header))[1] NE 1 THEN $
     header = header[0]
END



;; ++++++++++++++++++++++++++++++++++++++++++++++++++++++
;;      <overridden _ensure_properties help methods
;; ++++++++++++++++++++++++++++++++++++++++++++++++++++++

PRO sotobs::_ensure_title
  o = self
  o->private
  o.title = ptr_new(strarr(o->get(/nicons)))
  header = *(o->get(/header))
  instrume = o->get(/instrume)
  obs_type = gt_fkw(header,'OBS_TYPE')
  
  IF INSTRUME EQ 'SOT/SP' THEN BEGIN
     title = ['Stokes I/polarization 1', 'Stokes I/polarization 2', $
              'Stokes Q/polarization 1', 'Stokes Q/polarization 2', $
              'Stokes U/polarization 1', 'Stokes U/polarization 2', $
              'Stokes V/polarization 1', 'Stokes V/polarization 2']
     IF gt_fkw(header,'NAXIS3') EQ 1 THEN title = title[0:n_elements(title)-1:2]
     (*o.title) = title
  END
  
  IF INSTRUME EQ 'SOT/WB' THEN $
     (*o.title)[*] = OBS_TYPE + ': ' +gt_fkw(header,'wave')

  IF INSTRUME EQ 'SOT/NB' THEN BEGIN
     CASE strmid(OBS_TYPE,0,22) OF
        'FG shuttered Stokes':  (*o.title)  = $
           ['Stokes I', 'Stokes Q', 'Stokes U', 'Stokes V']
        'FG shutterless Stokes':  (*o.title)  = $
           ['Stokes I', 'Stokes Q', 'Stokes U', 'Stokes V']  
        'FG shuttered I and V': (*o.title)  = ['Stokes I', 'Stokes V']
        'FG shutterless I and V': (*o.title)  = ['Stokes I', 'Stokes V']
        ELSE: (*o.title)[*]  = OBS_TYPE + ': ' +gt_fkw(header,'wave') 
     ENDCASE
  ENDIF
END

PRO sotobs::_ensure_xtitle
  o = self
  o->private
  
  IF ~o->is_set(/xtitle) THEN BEGIN 
     instrume = o->get(/instrume)
     IF instrume EQ 'SOT/SP' THEN o.xtitle = 'Wavelength (Å)' ELSE $
        o.xtitle = 'Solar X (arc sec)'
  ENDIF
END

PRO sotobs::_ensure_image_scale 
  o = self
  o->private
  
  IF ~o->is_set(/image_scale) THEN BEGIN
     instrume = o->get(/instrume)
     IF instrume EQ 'SOT/SP' THEN $
        o.image_scale = ptr_new(o->_image_scale_wavelength_y()) ELSE $
           o.image_scale = ptr_new(o->_image_scale_x_y())
  ENDIF
  
END

FUNCTION sotobs::_image_scale_wavelength_y
  self->private
  ;; For SOT/SP the scale in the wavelength direction is actually -cdelt1... 
  scale = self->_image_scale_x_y()
  return, [-scale[0], scale[1]]
END


PRO sotobs::_ensure_image_origin
  o = self
  o->private
  IF ~o->is_set(/image_origin) THEN BEGIN 
     instrume = o->get(/instrume)
     IF instrume EQ 'SOT/SP' THEN $
        o.image_origin = ptr_new(o->_image_origin_wavelength_y()) ELSE $
           o.image_origin = ptr_new(o->_image_origin_x_y()) ; in hinobs__define
  END
END

FUNCTION sotobs::_image_origin_wavelength_y
  self->private
  ;; Hardcoding of wavelength origin: http://solar-b.nao.ac.jp/sot_e/sp_e.shtml
  return, [6300.8, self->_image_origin_y()]
END

;; -----------------------------------------------------
;;      </overridden _ensure_properties help methods
;; -----------------------------------------------------

  
FUNCTION sotobs::_gt_extra_title, radialfiltering=radialfiltering
  self->private
  IF keyword_set(radialfiltering) THEN extra_title = ' * RADIAL FILTER *' ELSE extra_title = ''
  return, extra_title
END


FUNCTION sotobs::_image_final_touch, im, radialfiltering=radialfiltering
  self->private
  
  ;; Find SOT/WB observations with missing data (PERCENTD lt 100). Set the
  ;; missing strips to the median of the image to preserve dynamic range of
  ;; image, then set missing to 0 after sigranging and bytscaling 
  ;percentd = gt_fkw(*(self->get(/header)),'PERCENTD')
  ;IF size(percentd,/tname) EQ 'FLOAT' && percentd LT 100 THEN BEGIN
  
 
  IF keyword_set(radialfiltering) THEN im = self->_radial_filter(im)
  
  nbadix = 0 
  mx = max(im,dim=2,min=mn)
  badix = where(mx EQ mn, nbadix, complement=goodix, ncomplement=ngoodix)
  IF nbadix GT 0 AND ngoodix GT 0 THEN im[badix,*] = median(im[goodix,*])
  ;ENDIF
  
  ;; Fix 15 bit wrap around effect
  IF min(im) LT -31000 THEN im += 2^15
  
  
  im = bytscl(sigrange(im),/nan)
  
  IF nbadix GT 0 THEN im[badix,*] = 1
  
  return, im
END

FUNCTION sotobs::_radial_filter, im
  self->private
;  IF self->hget(/wave) EQ 'Ca II H line' THEN BEGIN 
;  IF self->_gt_FOVcorner_radius() GT 955 THEN $
     im = self->_do_radial_filtering(im); ELSE $
;  print,'Skipping radial filtering due to too little off limb in FOV' 
;  ENDIF
  
  return,im
  
END


FUNCTION sotobs::gt_FOVcorner_radius
  o = self
 ; o->private
  o->_cenAndfov, xcen, ycen, fovx, fovy
  
  IF xcen GT 0 THEN cornerradius = (ycen GT 0) ? $
                                   sqrt((xcen+(fovx/2))^2 + (ycen+(fovy/2))^2) :$
                                   sqrt((xcen+(fovx/2))^2 + (ycen-(fovy/2))^2) $
  ELSE $
     cornerradius = (ycen GT 0) ? $
                    sqrt((xcen-(fovx/2))^2 + (ycen+(fovy/2))^2) :$
                    sqrt((xcen-(fovx/2))^2 + (ycen-(fovy/2))^2)
  
  return, cornerradius
  
END

  
FUNCTION sotobs::_do_radial_filtering, im
  self->private
  mfg_limb_norm_image, im, self->hget(/date_obs),n,pix=self->hget(/xscale)
  return,im/n
END


PRO sotobs::_mk_jpg2000_specific, im, header, dir, fitsname, outdir=outdir
  self->private
  hv_hin_fg2jp2_specific, im, header, dir, fitsname, outdir=outdir, err=err
  IF err NE '' THEN message, err,/info
END


PRO sotobs__define
  
  d = {sotobs, $
       inherits hinobs}
END
