;+
;NAME:
; spd_ui_dproc_panel
; 
;PURPOSE:
; A widget interface that can be used to set the active data variables
; and perform various data analysis tasks.
; 
;CALLING SEQURNCE:
; spd_ui_dproc_panel, gui_id
; 
;INPUT:
; gui_id = the id of the calling widget
; 
;OUTPUT:
; No explicit output, processes are done
; 
;HISTORY:
; 21-nov-2008, jmm, jimm@ssl.berkeley.edu
; 24-apr-2015, af, event handler uses uname instead of uvalue
; 
;$LastChangedBy: aaflores $
;$LastChangedDate: 2015-04-24 18:45:02 -0700 (Fri, 24 Apr 2015) $
;$LastChangedRevision: 17429 $
;$URL: svn+ssh://thmsvn@ambrosia.ssl.berkeley.edu/repos/spdsoft/tags/spedas_3_1/spedas_gui/panels/spd_ui_dproc_panel.pro $
;-

;helper function for setting active data/determining tree selection
pro spd_ui_dproc_panel_get_tree_select, state, sobj

    compile_opt idl2, hidden

  widget_control,state.loadedlist,get_value=treeobj
  treeptrarr=treeobj->GetValue()
  if ~is_num(treeptrarr[0]) then begin
      If(ptr_valid(state.data_choice)) Then ptr_free, state.data_choice
      treelist=(*(treeptrarr[0])).groupname               ;Concatenate data names.
      n_treeptrarr=n_elements(treeptrarr)
      if n_treeptrarr gt 1 then begin
        for i=1,n_treeptrarr-1 do treelist=[treelist,(*(treeptrarr[i])).groupname]
      endif
      state.data_choice=ptr_new(treelist)
      sobj -> update, 'Variables chosen: '+strjoin(*state.data_choice, ',', /single)
      state.info.historywin-> update, 'Data Processing: Variables chosen: '+strjoin(*state.data_choice, ',', /single)
  Endif Else begin
    ptr_free, state.data_choice
    sobj -> update, 'Bad Selection, Please try again'
    state.info.historywin-> update, 'Data Processing: Bad Selection, Please try again'
  endelse

end

; helper function for determining the selected active data
pro spd_ui_dproc_panel_get_active_select, state, sobj

    compile_opt idl2, hidden

  pindex = widget_info(state.activelist, /list_select)
  If(pindex[0] Ne -1) Then Begin
      If(ptr_valid(state.act_data)) Then Begin
          If(ptr_valid(state.data_choice)) Then ptr_free, state.data_choice
          state.data_choice = ptr_new((*state.act_data)[pindex])
          sobj -> update, 'Variables chosen: '+strjoin(*state.data_choice, ',', /single)
          state.info.historywin-> update, 'Data Processing: Variables chosen: '+strjoin(*state.data_choice, ',', /single)
      Endif Else begin
        sobj -> update, 'No Active Data Available'
        state.info.historywin-> update, 'Data Processing: No Active Data Available'
      endelse
  Endif Else begin
    sobj -> update, 'Bad Selection, Please try again'
    state.info.historywin-> update, 'Data Processing: Bad Selection, Please try again'
  Endelse
end


Pro spd_ui_dproc_panel_event, event

 ; print, ''
;Catch here to insure that the state remains defined
  err_xxx = 0
  Catch, err_xxx
  IF (err_xxx NE 0) THEN BEGIN
    Catch, /Cancel
    Help, /Last_Message, Output = err_msg
    if is_struct(state) then begin
      FOR j = 0, N_Elements(err_msg)-1 DO state.info.historywin->update,err_msg[j]
      x=state.gui_id
      histobj=state.info.historywin
      if obj_valid(state.treeObj) then begin
        *state.treeCopyPtr = state.treeObj->getCopy() 
      endif  
    endif
    Print, 'Error--See history'
    ok=error_message('An unknown error occured and the window must be restarted. See console for details.',$
       /noname, /center, title='Error in Data Processing')
    If(is_struct(state)) Then Widget_Control, event.TOP, Set_UValue=state, /No_Copy
    widget_control, event.top,/destroy
    if widget_valid(x) && obj_valid(histobj) then begin
      spd_gui_error,x,histobj
    endif
    RETURN
  ENDIF

widget_control, /hourglass

;Get info from state, and data object from gui_id
widget_control, event.top, get_uvalue = state, /no_copy
dproc_id = state.master
dobj = state.info.loadeddata
sobj_main = state.info.statusbar
sobj = state.statusbar
historywin = state.info.historywin

;kill request block
If(TAG_NAMES(event, /STRUCTURE_NAME) EQ 'WIDGET_KILL_REQUEST') Then Begin
    historywin-> update, 'Kill request on Data Processing Panel'
    if obj_valid(state.treeObj) then begin
      *state.treeCopyPtr = state.treeObj->getCopy() 
    endif  
    widget_control, event.top, set_uvalue = state, /no_copy
    widget_control, event.top, /destroy
    sobj_main -> update, 'Data Processing Panel killed'
    Return
Endif
If(obj_valid(dobj) Eq 0) Then message, 'No valid data object'

;now deal with the event
uname = widget_info(event.id, /uname)
SPL = strsplit(uname, ':', /extract)

;uvalues only used for plugins atm, coule be expanded if needed
widget_control, event.id, get_uvalue=uvalue

;Handle most data processing options
If(spl[0] Eq 'PROC') Then Begin
    ptree = ptr_new(state.treeobj->getcopy())
    otp = spd_ui_dproc(state.info, spl[1], ext_statusbar = sobj, plugin_structure=uvalue, $ 
                           group_leader = state.master, ptree = ptree)
    
    ;synchronize tree expansion state.(Since Interpol popup uses data tree)
    if spl[1] eq 'INTERPOL' then begin
      state.treeobj->update,from_copy=*ptree
    endif
    
    ptr_free, ptree
    widget_control, event.top, set_uvalue = state, /no_copy
    spd_ui_dproc_reset_act_data, dproc_id, /update_tree

;Handle coordinate transformations
Endif Else If(spl[0] Eq 'COTRANS') Then Begin

    active = state.info.loadedData->getActive(/parent)
    state.info.windowStorage->getProperty,callSequence=callSequence
    spd_ui_cotrans, event.top,spl[1],active,state.info.loadedData, sobj,historywin,callSequence
    widget_control, event.top, set_uvalue = state, /no_copy
    spd_ui_dproc_reset_act_data, dproc_id, /update_tree

;Handle window events
Endif Else Begin
    state.info.historywin->update,'SPD_UI_DPROC_PANEL: User Value: '+uname,/dontshow
;    sobj->update,string('SPD_UI_DPROC_PANEL: User Value: '+uval)
    Case uname of
        'CANC': Begin
            state.info.historywin-> update, 'Closing Data Processing Panel'
            if obj_valid(state.treeObj) then begin
              *state.treeCopyPtr = state.treeObj->getCopy() 
            endif 
            widget_control, event.top, set_uvalue = state, /no_copy
            widget_control, event.top, /destroy
            sobj_main -> update, 'Data Processing Panel Closed'
            Return
        End
        'DATALOADLIST': Begin
          spd_ui_dproc_panel_get_tree_select, state, sobj
        End
        'ACTIVELIST': Begin
          spd_ui_dproc_panel_get_active_select, state, sobj
        End
        'CLEAR':Begin
            dobj -> clearallactive
            sobj -> update, 'All Active variables cleared'
            state.info.historywin-> update, 'All Active variables cleared'
            spd_ui_dproc_reset_act_data, state
        End
        'SETACTIVE':Begin
            spd_ui_dproc_panel_get_tree_select, state, sobj
            If(ptr_valid(state.data_choice)) Then Begin
                dc = *state.data_choice
                For j = 0, n_elements(dc)-1 Do dobj -> setactive, dc[j]
                ptr_free, state.data_choice
                spd_ui_dproc_reset_act_data, state
                sobj -> update, 'Variables set to active: '+strjoin(dc, ',', /single)
                state.info.historywin-> update, 'Variables set to active: '+strjoin(dc, ',', /single)
            Endif Else sobj -> update, 'No Data has been selected'
        End
        'UNSETACTIVE':Begin
            spd_ui_dproc_panel_get_active_select, state, sobj
            If(ptr_valid(state.data_choice)) Then Begin
                dc = *state.data_choice
                For j = 0, n_elements(dc)-1 Do dobj -> clearactive, dc[j]
                ptr_free, state.data_choice
                spd_ui_dproc_reset_act_data, state
                sobj -> update, 'Variables set to inactive: '+strjoin(dc, ',', /single)
                state.info.historywin-> update, 'Variables set to inactive: '+strjoin(dc, ',', /single)
            Endif Else begin
              sobj -> update, 'No Data has been selected'
              state.info.historywin-> update, 'No Data has been selected'
            endelse
        End
        'TRASH':Begin
            ; delete data directly from the data processing window - egrimes 1/4/13
            spd_ui_dproc_panel_get_tree_select, state, sobj
            If(ptr_valid(state.data_choice)) Then Begin
                select = *state.data_choice
                result=dialog_message('Are you sure you want to delete the selected data from the GUI?', $
                    /question,/center, title='Data Processing: Delete GUI data?')
                if result eq 'Yes' then begin
                    for i = 0,n_elements(select)-1 do begin
                      if ~state.info.loadedData->remove(select[i]) then begin
                        state.statusBar->update,'Error deleting: ' + select[i]
                        state.info.historyWin->update,'Error deleting: ' + select[i]
                        return
                      endif else begin
                        state.info.windowStorage->getProperty,callSequence=callSeq
                          ; store deletion in the call sequence object
                          if obj_valid(callSeq) then begin
                              callSeq->adddeletecall,select[i]
                          endif else begin
                              dprint, dlevel = 0, 'Error getting the call sequence object from the window in spd_ui_dproc_panel'
                          endelse
                      endelse 
                    endfor
                    if double(!version.release) lt 8.0d then heap_gc
                    state.treeobj->update
                    state.statusBar->update,'Deleted Selection'
                    state.info.historyWin->update,'Deleted Selection'
                    spd_ui_dproc_reset_act_data, state
                    state.treeobj->clearSelected
                endif
            Endif Else begin
              sobj -> update, 'No Data has been selected'
              state.info.historywin-> update, 'No Data has been selected'
            endelse
        End
        else:begin
          ;nothing to do
        end
    Endcase
    widget_control, event.top, set_uvalue = state, /no_copy
Endelse
Return
End

Pro spd_ui_dproc_panel, info

err_xxx = 0
catch, err_xxx
If(err_xxx Ne 0) Then Begin
    catch, /cancel
    Help, /Last_Message, Output=err_msg
    FOR j = 0, N_Elements(err_msg)-1 DO begin
      Print, err_msg[j]
      info.historywin->update,err_msg[j]
    endfor
    Print, 'Error--See history'

    ok = error_message('An unknown error occured starting Data Processing. See console for details.', $
                       traceback=0, /noname, /center, title='Error in Data Processing')
    widget_control,master,/destroy
    spd_gui_error, info.master, info.historywin
    Return
Endif

gui_id = info.master
master = widget_base(/col, title = 'Data Processing', $
                     group_leader = gui_id, /floating, /tlb_kill_request_events, /modal)

;This base widget will hold the lists of loaded and active data:
listsbase = widget_base(master, /row)
loadedbase = widget_base(listsbase, /column)
addbase = widget_base(listsbase, /column, ypad=140)
activebase = widget_base(listsbase, /column, ypad=5)
analysismenu = widget_base(listsbase, /column)

;This base will hold the buttons on the bottom:
buttonbase = widget_base(master, /row, /align_center)

; Create Status Bar Object
statusBar = Obj_New('SPD_UI_MESSAGE_BAR', Value = 'Status information is displayed here.', master, Xsize = 100, YSize = 1)

loadedLabel = WIDGET_LABEL(loadedBase, value='Loaded Data')

;get the loaded data and active data:
state = {master:master, gui_id:gui_id, info:info, $
         val_data:ptr_new(), data_choice:ptr_new(), $
         act_data:ptr_new(), val_data_t:ptr_new(), $
         act_data_t:ptr_new(), treeobj:obj_new(), $
         activelist:-1L,loadedlist:-1L,$
         statusbar:statusbar,treeCopyPtr:info.guiTree}

spd_ui_dproc_reset_act_data, state, /update_tree ;this sets up the data lists

screen_size = get_screen_size()
xtree_size = min([300,floor((screen_size[0]/4.5))])
ytree_size = min([300,floor((screen_size[1]/3.5))])
xtree_size = 270
ytree_size = 370
state.treeobj = obj_new('spd_ui_widget_tree', loadedbase, 'DATALOADLIST', $
                        info.loadeddata, xsize = xtree_size, ysize = ytree_size, mode = 0, $
                        /multi, uname = 'dataloadlist', /showdatetime)
                        
state.treeObj->update,from_copy=*state.treeCopyPtr
state.loadedlist=widget_info(master,find_by_uname='dataloadlist')

;set up the buttons to add, subtract active data as in the load data widget
getresourcepath,rpath
leftArrow = read_bmp(rpath + 'arrow_180_medium.bmp', /rgb)
rightArrow = read_bmp(rpath + 'arrow_000_medium.bmp', /rgb)
trashcan = read_bmp(rpath + 'trashcan.bmp',/rgb)

spd_ui_match_background, master, leftArrow
spd_ui_match_background, master, rightArrow
spd_ui_match_background, master, trashcan

;plusbmp = filepath('shift_right.bmp', SubDir = ['resource', 'bitmaps'])
;minusbmp = filepath('shift_left.bmp', SubDir = ['resource', 'bitmaps'])
addButton = Widget_Button(addBase, Value = rightArrow, /Bitmap,  uname = 'SETACTIVE', $
                          ToolTip = 'Set Selected Data to Active')
minusButton = Widget_Button(addBase, Value = leftArrow, /Bitmap, $
                            uname = 'UNSETACTIVE', $
                            ToolTip = 'Unset selected data from Active')
trashbutton = Widget_Button(addBase, Value=trashcan, /Bitmap,  uname='TRASH', $
              ToolTip='Delete data selected in the list of loaded data', xsize=27, ysize=27) 
activeLabel = Widget_Label(activeBase, value='Active Data')

state.activelist = widget_list(activebase, value = *state.act_data_t, $
                               uname = 'ACTIVELIST', $
                               XSize = 55, YSize = 22, scr_ysize=ytree_size, /multiple)

;buttons along the bottom
clear_button = Widget_Button(buttonBase, Value = ' Clear Active ', XSize = 85, $
                             uname = 'CLEAR')
; Analysis Pull Down Menu, hacked from spd_gui.pro
;analysisMenu = Widget_Button(buttonbase, Value='Analysis ',/menu
;xsize = 85)
subAvgMenu = Widget_Button(analysisMenu, Value='Subtract Average ', $
                           uname='PROC:SUBAVG', tooltip = 'Subtracts average of each trace')
subMedMenu = Widget_Button(analysisMenu, Value='Subtract Median ', $
                           uname='PROC:SUBMED', tooltip = 'Subtracts median of each trace from each trace')
smoothMenu = Widget_Button(analysisMenu, Value='Smooth Data... ', uname='PROC:SMOOTH', $
                          tooltip = 'Smooths data in time, using input resolution')
hpfiltMenu = Widget_Button(analysisMenu, Value='High Pass filter... ', uname='PROC:HPFILT', $
                          tooltip = 'Subtracts smoothed values from each trace')
blkAvgMenu = Widget_Button(analysisMenu, Value='Block Average... ', uname='PROC:BLKAVG',$
                          tooltip = 'Block time average of each trace')
clipMenu = Widget_Button(analysisMenu, Value='Clip... ', uname='PROC:CLIP', $
                         tooltip = 'Clips traces at input max and min values')
deflagMenu = Widget_Button(analysisMenu, Value='Deflag... ', uname='PROC:DEFLAG', $
                           tooltip = 'Replaces NaN values with interpolated or repeated values')
degapMenu = Widget_Button(analysisMenu, Value='Degap... ', uname='PROC:DEGAP',$
                          tooltip = 'Fills data gaps with NaN values')
interpMenu = Widget_Button(analysisMenu, value='Interpolate...', uname='PROC:INTERPOL', $
                           tooltip = 'Performs interpolation on active data')
spikeMenu = Widget_Button(analysisMenu, Value='Clean Spikes...', uname='PROC:SPIKE', $
                          tooltip = 'Replaces single-point spikes with NaN values')
derivMenu = Widget_Button(analysisMenu, Value='Time Derivative...', uname='PROC:DERIV', $
                          tooltip = 'Time derivatives of each trace')
waveMenu = Widget_Button(analysisMenu, Value='Wavelet Transform...', uname='PROC:WAVE', $
                         tooltip = 'Performs wavelet transform for each trace')
pwrspecMenu = Widget_Button(analysisMenu, Value='Power Spectrum...', uname='PROC:PWRSPC', $
                         tooltip = 'Performs Dynamic power spectrum for each trace')
cotranMenu = Widget_Button(analysisMenu, Value='Coordinate Transform...', uname='PROC:COTRAN', $
                         tooltip = 'Performs a coordinate transform on active data', /menu)
;validCoords = ['DSL', 'SSL', 'GSE', 'GEI', 'SPG', 'GSM', 'GEO', 'SM', 'SSE', 'SEL', 'MAG']

; make a list of valid coordinate systems 
coord_sys_obj = obj_new('spd_ui_coordinate_systems')
validCoords = coord_sys_obj->makeCoordSysList(/uppercase)
obj_destroy, coord_sys_obj

coordMenus = LonArr(N_Elements(validCoords))
FOR i = 0, N_Elements(validCoords)-1 DO $
  coordMenus[i] = Widget_Button(cotranMenu, Value=string(validCoords[i]+'  '),uname='COTRANS:'+validCoords[i])
splitMenu = Widget_Button(analysisMenu, Value='Split Variable', uname='PROC:SPLIT', $
                         tooltip = 'Splits a variable into its different componenets (e.g. _x,_y,_z)')
joinMenu = Widget_Button(analysisMenu, Value='Join Variables...', uname='PROC:JOIN', $
                         tooltip = 'Joins similar variables into one. To be used after splitting.')

valid_plugins = info.pluginManager->getDataProcessingPlugins()

pluginsMenu = Widget_Button(analysisMenu, value='More...', $ uname='PROC:PLUGIN', $
                            tooltip='More data processing options...', /menu)

spd_ui_plugin_menu, pluginsMenu, valid_plugins, uname='PROC:PLUGIN'

;plugin_menus = lonarr(n_elements(valid_plugins))
;for i = 0, n_elements(plugin_menus)-1 do $
;    plugin_menus[i] = Widget_Button(pluginsMenu, value=valid_plugins[i].item, uname='PROC:PLUGIN;'+valid_plugins[i].procedure)    

;Dude...
cancel_button = Widget_Button(buttonBase, Value = '  Done   ', XSize = 85, $
                              uname = 'CANC')
CenterTlb, master
Widget_Control, master, Set_UValue = state, /No_Copy
Widget_Control, master, /Realize

  ;keep windows in X11 from snaping back to 
  ;center during tree widget events 
  if !d.NAME eq 'X' then begin
    widget_control, master, xoffset=0, yoffset=0
  endif

XManager, 'spd_ui_dproc_panel', master, /No_Block

End