;+
; NAME:
;         p3d_extract_tophat
;
;         $Id: p3d_extract_tophat.pro 181 2010-04-21 08:44:03Z christersandin $
;
; PURPOSE:
;         This routine provides a simple spectrum extraction algorithm. Using
;         the input image an extracted spectrum image is calculated, where each
;         spectrum is placed in an individual row.
;
;         The spectra are extracted from the input image by summing up the flux
;         in each wavelength bin over an interval of the width 2*PROFWIDTH+1
;         in the cross-dispersion direction. The input trace mask is used to
;         find the spectra.
;
; AUTHOR:
;         Christer Sandin
;         Astrophysikalisches Institut Potsdam (AIP)
;         An der Sternwarte 16
;         D-14482 Potsdam, GERMANY
;
; COPYRIGHT:
;         p3d: a general data-reduction tool for fiber-fed IFSs
;
;         Copyright 2009,2010 Astrophysikalisches Institut Potsdam (AIP)
;
;         This program is free software; you can redistribute it and/or modify
;         it under the terms of the GNU General Public License as published by
;         the Free Software Foundation; either version 3 of the License, or
;         (at your option) any later version.
;
;         This program is distributed in the hope that it will be useful, but
;         WITHOUT ANY WARRANTY; without even the implied warranty of
;         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;         General Public License for more details.
;
;         You should have received a copy of the GNU General Public License
;         along with this program; if not, see <http://www.gnu.org/licenses>.
;
;         Additional permission under GNU GPL version 3 section 7
;
;         If you modify this Program, or any covered work, by linking or
;         combining it with IDL (or a modified version of that library),
;         containing parts covered by the terms of the IDL license, the
;         licensors of this Program grant you additional permission to convey
;         the resulting work.
;
; CATEGORY:
;         p3d :: spectrum extraction
;
; CALLING SEQUENCE:
;         p3d_extract_tophat,image,traces,out,dout,dimage=,profwidth=,match=, $
;             stawid=,topwid=,logunit=,verbose=,error=,/debug,/help
;
; INPUTS:
;         image           - A two-dimensional array.
;         traces          - A two-dimensional array, which for every spectrum
;                           bin provides the y-position of every spectrum line
;                           on the raw data CCD image.
;
; KEYWORD PARAMETERS:
;         dimage          - A two-dimensional array of the same dimensions as
;                           IMAGE, with the errors of IMAGE. If this keyword is
;                           present then an output error image, DOUT, is
;                           calculated.
;         profwidth       - 2*PROFWIDTH+1 is the total width of the interval
;                           where the flux is integrated; only used when
;                           MATCH==0.
;         match [0]       - When this keyword is set the spectrum width, for
;                           every spectrum bin, in the cross-dispersion
;                           direction is estimated to be half the separation
;                           between any two separated spectra.
;         stawid          - If set, then various messages are written to the
;                           p3d GUI status line (this must be the widget id of
;                           that label widget).
;         topwid          - If set, then error messages are displayed using
;                           DIALOG_MESSAGE, using this widget id as
;                           DIALOG_PARENT, instead of MESSAGE.
;         logunit         - Messages are saved to the file pointed to by this
;                           logical file unit, if it is defined.
;         verbose         - Show more information on what is being done.
;         error           - Returns an error code if set.
;         debug           - The error handler is not setup if debug is set.
;         help            - Show this routine documentation, and exit.
;
; OUTPUTS:
;         out             - A two-dimensional array of the extracted spectra
;                           with the same dimensions as TRACES.
;
; OPTIONAL OUTPUTS:
;         dout            - A two-dimensional array of the extracted spectra
;                           with the same dimensions as TRACES. This is the
;                           error of OUT. DOUT is only calculated if DIMAGE is
;                           present.
;
; COMMON BLOCKS:
;         none
;
; SIDE EFFECTS:
;         none
;
; RESTRICTIONS:
;         IDL version 6.2 or higher is required.
;
; MODIFICATION HISTORY:
;         10.10.2008 - Converted from the original routine standard_extract of
;                      Thomas Becker. /CS
;-
PRO p3d_extract_tophat,image,traces,out,dout,dimage=dimage, $
        profwidth=profwidth,match=match,stawid=stawid,topwid=topwid, $
        logunit=logunit,verbose=verbose,error=error,debug=debug,help=help
  compile_opt hidden,IDL2

  if !version.release lt 6.2 then message,'IDL Version <6.2. Cannot continue.'
  error=0 & rname='p3d_extract_tophat: '
  if ~n_elements(verbose) then verbose=0
  debug=keyword_set(debug)

  if keyword_set(help) or ~n_params() then begin
    doc_library,'p3d_extract_tophat'
    return
  endif

  ;;========================================------------------------------
  ;; Setting up an error handler:

  if ~debug then begin
    catch,error_status
    if error_status ne 0L then begin
      p3d_misc_errors,error_status,rname=rname,topwid=topwid
      catch,/cancel
      error=-1
      return
    endif
  endif ;; ~debug

  ;;========================================------------------------------
  ;; Checking the input arguments:

  if ~n_elements(stawid) then stawid=0L
  usestawid=widget_info(stawid,/valid_id)

  si=size(image)
  if ~si[si[0L]+2L] or si[0L] ne 2L or $
     (si[si[0L]+1L] ge 6L and si[si[0L]+1L] le 11L) then begin
    errmsg='IMAGE must be set; to a two-dimensional array of floating poin' + $
           't type.'
    goto,error_handler
  endif

  se=size(dimage) & ecalc=0L
  if se[se[0L]+2L] ne 0L then begin
    if se[0L] ne si[0L] or se[se[0L]+1L] eq 7L or $
       se[se[0L]+2L] ne si[si[0L]+2L] then begin
      errmsg='DIMAGE {'+strtrim(se[se[0L]+1L],2L)+',['+strtrim(se[1L],2L)+ $
             ','+strtrim(se[2L],2L)+']}, if set, must be of the same ' + $
             'dimensions as IMAGE {'+strtrim(si[si[0L]+1L],2L)+',['+ $
             strtrim(si[1L],2L)+','+strtrim(si[2L],2L)+']}.'
      goto,error_handler
    endif
    ecalc=1L
  endif ;; se[se[0L]+2L] ne 0L

  st=size(traces)
  if ~st[st[0L]+2L] or st[0L] ne 2L or $
     (st[st[0L]+1L] ge 6L and st[st[0L]+1L] le 11L) then begin
    errmsg='TRACES must be set; to a two-dimensional array of floating poi' + $
           'nt type.'
    goto,error_handler
  endif

  if ~keyword_set(match) then begin
    sp=size(profwidth)
    if sp[sp[0L]+2L] ne 1L or $
      (sp[sp[0L]+1L] ge 6L and sp[sp[0L]+1L] le 11L) then begin
      errmsg='PROFWIDTH must be set; to a scalar floating point value.'
      goto,error_handler
    endif

    if profwidth lt 0.0 then begin
      errmsg='PROFWIDTH [='+strtrim(profwidth,2L)+'] must be >0.0.'
      goto,error_handler
    endif
  endif ;; ~keyword_set(match)

  ;; Logging the used parameters:
  msg=['Used the following extraction parameters:', $
       '  profwidth='+string(profwidth,format='(f9.3)')+' :: spectrum extr' + $
       'action half width.', $
       '      match='+strtrim(keyword_set(match),2L)+'.']
  error=p3d_misc_logger(msg,logunit,rname=rname,verbose=verbose ge 1)

  ;;========================================------------------------------
  ;; Finding the (pixel) range of every spectrum on the CCD on the cross-
  ;; dispersion axis:

  if keyword_set(match) then begin

    lower=fltarr(st[1L],st[2L])
    upper=fltarr(st[1L],st[2L])

    cuts =0.5*    (traces[*,1L:st[2L]-1L] + traces[*,0L:st[2L]-2L])
    width=0.5*median(cuts[*,1L:st[2L]-2L] -   cuts[*,0L:st[2L]-3L]) ;; scalar

    lower[*,0L          ]=traces[*,0L       ]-width
    lower[*,1L:st[2L]-1L]=cuts
    upper[*,0L:st[2L]-2L]=cuts
    upper[*,   st[2L]-1L]=traces[*,st[2L]-1L]+width

  endif else begin ;; keyword_set(match)

    lower=traces-profwidth
    upper=traces+profwidth+1.0
;   lower=traces-profwidth-0.5
;   upper=traces+profwidth+0.5

  endelse ;; keyword_set(match)


  uppborder=ceil(( max(upper)-si[2L]+1L)>0.0)
  lowborder=ceil((-min(lower))>0.0)

  tmpim=fltarr(si[1L],si[2L]+lowborder+uppborder)
  if ecalc then begin
    dtmpim=tmpim
    dtmpim[*,lowborder:lowborder+si[2L]-1L]=dimage
  endif
  tmpim[*,lowborder:lowborder+si[2L]-1L]=image

  upper+=lowborder & upplong=long(upper) & upprest=1.0-(upper-upplong)
  lower+=lowborder & lowlong=long(lower) & lowrest=     lower-lowlong

  ;;========================================------------------------------
  ;; Summing up (integrating) the contribution of each spectrum bin and
  ;; spectrum:

  out=fltarr(st[1L],st[2L])
  if ecalc then dout=fltarr(st[1L],st[2L])

  for j=0L,st[2L]-1L do begin
    for i=0L,st[1L]-1L do begin
      out[i,j]=total(tmpim[i,lowlong[i,j]:upplong[i,j]]) - $
                     tmpim[i,lowlong[i,j]]*lowrest[i,j] - $
                     tmpim[i,upplong[i,j]]*upprest[i,j]

      if ecalc then dout[i,j]= $ ;; Calculating the cumulative error
        sqrt(total(dtmpim[i,lowlong[i,j]:upplong[i,j]]^2) + $
                  (dtmpim[i,lowlong[i,j]]*lowrest[i,j])^2 + $
                  (dtmpim[i,upplong[i,j]]*upprest[i,j])^2)
    endfor ;; i=0L,st[1L]-1L
  endfor ;; j=0L,st[2L]-1L

  return

error_handler:
  error=p3d_misc_logger(errmsg,logunit,rname=rname,topwid=topwid, $
      verbose=verbose,/error)
  return
END ;;; procedure: p3d_extract_tophat
