;+
; NAME:
;	SMEI_OPERATOR::COMPUTE
;
;
; PURPOSE:
;	Generate a SMEI_SEQUENCE from an operator.
;
;
; CATEGORY:
;	SMEI_OPERATOR
;
;
; CALLING SEQUENCE:
;	sop -> compute
;
;
; MODIFICATION HISTORY:
;	Original: 22/10/03; SJT
;	Get times etc. from first multi-image sequence if available:
;	4/11/03; SJT
;	Pass filename of "dominant" file down: 1/12/03; SJT
;	Add %median operator: 19/2/04; SJT
;	Add %csum operator: 8/10/09; SJT
;-

pro smei_operator::compute

if obj_valid(self.sequence) then obj_destroy, self.sequence

;	Verify that we have suitable arguments

fsa = -1
for j =  0, self -> get_arg_count()-1 do begin
    if (self -> get_argument(j)) -> get_class() eq 1 then begin
        fsa = j
        break
    endif
endfor
if fsa eq -1 then begin
    for j =  0, self -> get_arg_count()-1 do begin
        if (self -> get_argument(j)) -> get_class() eq 2 then begin
            fsa = j
            fla = j
            break
        endif
    endfor
endif else begin
    fla = fsa
    for j = fsa, self -> get_arg_count()-1 do begin
        if (self -> get_argument(j)) -> get_class() eq 1 and $
          (self -> get_argument(j)) -> get_count() gt 1 then begin
            fla = j
            break
        endif
    endfor
endelse

if fsa eq -1 then begin
    smei_msg, /alert, "No SEQUENCE or IMAGE arguments, cannot compute"
    return
endif

self.sequence = obj_new('SMEI_SEQUENCE')


;	Determine the expression to be evaluated for each image of the
;	output sequence

case self -> get_class() of 
    1: begin                    ; IDL operator
        if self -> get_arg_count() eq 1 then expr = 'ans = ' + self ->  $
          get_operator() + 'p0' $
        else begin
            expr = 'ans = p0'
            for j = 1, self -> get_arg_count()-1 do $
              expr = expr+' '+self -> get_operator()+ $
              ' p'+string(j, format = "(I0)")
        endelse
    end

    2: begin                    ; Specials
        case self -> get_operator() of
            '%mean': self -> compute_average
            '%sum': self -> compute_sum
            '%csum': self -> compute_csum
            '%min': self -> compute_min
            '%max': self -> compute_max
            '%cat': self -> concatenate
            '%median': self -> compute_median
        end
        return                  ; NB don't want to do the end stuff
    end

    3: begin                    ; Function call
        expr = 'ans = '+self -> get_operator()+'('
        for j = 0, self -> get_arg_count()-1 do begin
            expr = expr+'p'+string(j, format = "(I0)")
            if j ne  self -> get_arg_count()-1 then expr = expr+', '
        endfor
        if ptr_valid(self.extras) then expr = expr+', ' + $
          '_extra=*(self.extras))' $
        else expr = expr+')'
    end
    
endcase

if widget_info(/active) then $
  pm = cw_progress(title = 'Calculating', $
                   value = 0., $
                   /column, $
                   xsize = 200, $
                   ysize = 20, $
                   max = self -> get_count()) $
else pm = 0l

for j = 0, self -> get_count()-1 do begin
    flg = 0u
    for k = 0, self -> get_arg_count()-1 do begin
        getexp = 'p'+string(k, format = "(I0)")+ $
          ' = (self->get_argument('+string(k, format = "(I0)")+ $
          '))->eval('+string(j, format = "(I0)")+')'
        ok = execute(getexp)
        if not ok then  smei_msg, /warn, [getexp, "Failed to execute " + $
                                          "properly", !error_state.msg]
        flg or= (self -> get_argument(k)) -> eval(j, /flags)
    endfor
    
    simg = (self -> get_argument(fla)) -> get_image(j)
    ok = execute(expr)
    if not ok then  smei_msg, /warn, [expr, "Failed to execute " + $
                                      "properly", !error_state.msg]
    im = self.sequence -> add_image(image_data = ans, $
                                    start = simg -> get_time(/start), $
                                    stop = simg -> get_time(/stop), $
                                    unit = simg -> get_unit(), $
                                    centre = simg -> get_centre(), $
                                    scale = simg -> get_scale(), $
                                    cvalue = simg -> get_cvalue(), $
                                    fitshead = simg -> $
                                    get_header(/fitshead), $
                                    ancilhead = $
                                    simg -> get_header(/ancil, $
                                                       /fitshead), $ $
                                    flaghead = simg->get_header(/flag, $ $
                                                                /fitshead), $
                                    flags = simg -> get_flags(), $
                                    filename = simg -> get_file(), $
                                    projection = simg ->  $
                                    get_projection(), $
                                    /last, $
                                    flag_data = flg, $
                                    ancil_data = simg -> get_ancil())
    if widget_info(/valid, pm) then widget_control, pm, set_value = j+1
endfor

if widget_info(/valid, pm) then widget_control, pm, /destroy

end
