;+
;NAME: 
;    spd_ui_plugin_manager
;
;PURPOSE:
;    Interface for SPEDAS plugins
;
;
;$LastChangedBy: nikos $
;$LastChangedDate: 2016-10-11 16:59:54 -0700 (Tue, 11 Oct 2016) $
;$LastChangedRevision: 22089 $
;$URL: svn+ssh://thmsvn@ambrosia.ssl.berkeley.edu/repos/spdsoft/tags/spedas_3_1/spedas_gui/objects/spd_ui_plugin_manager__define.pro $
;-

pro spd_ui_plugin_manager::Cleanup
    ptr_free, self.plugin_menus
    ptr_free, self.plugin_file_config_panels
    ptr_free, self.plugin_load_data_panels
    ptr_free, self.plugin_about_pages
    ptr_free, self.data_proc_plugins
end

;+
; NAME: 
;     addAboutPlugin
;     
; PURPOSE: 
;     Add an about page with information on the plugin. For example, the "rules of the road"
;     statement, developer credits, acknowledgements, etc.
;     
; INPUT: 
;     mission name: name of the mission to add to the load data panel
;     procedure name: name of the procedure containing the load data panel widget for this mission
;     panel title: title of the load data panel
;-
pro spd_ui_plugin_manager::addAboutPlugin, mission_name, text_file
    plugin_struct = [{mission_name: mission_name, text_file: text_file}]
    if ptr_valid(self.plugin_about_pages) then begin
        append_array, (*self.plugin_about_pages), plugin_struct
    endif else self.plugin_about_pages = ptr_new(plugin_struct)
end 

;+
; NAME: 
;     getAboutPlugins
;     
; PURPOSE: 
;     returns an array of structures, one struct for each plugin's about page
;     
;
;-
function spd_ui_plugin_manager::getAboutPlugins
    if ptr_valid(self.plugin_about_pages) then begin
        return, *self.plugin_about_pages
    endif else return, 0
end


;+
; NAME: 
;     addLoadDataPanel
;     
; PURPOSE: 
;     Add a panel to the load data window
;     
; INPUT: 
;     mission name: name of the mission to add to the load data panel
;     procedure name: name of the procedure containing the load data panel widget for this mission
;     panel title: title of the load data panel
;-
pro spd_ui_plugin_manager::addLoadDataPanel, mission_name, procedure_name, panel_title
    plugin_struct = [{mission_name: mission_name, procedure_name: procedure_name, panel_title: panel_title}]
    if ptr_valid(self.plugin_load_data_panels) then begin
        append_array, (*self.plugin_load_data_panels), plugin_struct
    endif else self.plugin_load_data_panels = ptr_new(plugin_struct)
end 

;+
; NAME: 
;     getLoadDataPanels
;     
; PURPOSE: 
;     returns an array of structures, one struct for each load data panel
;     
; OUTPUT:
;
;-
function spd_ui_plugin_manager::getLoadDataPanels
    if ptr_valid(self.plugin_load_data_panels) then begin
        return, *self.plugin_load_data_panels
    endif else return, 0
end

;+
; NAME: 
;     addFileConfigPanel
;     
; PURPOSE: 
;     Add a panel to the file configuration window
;     
; INPUT: 
;    mission name: name of the mission
;    procedure name: name of the procedure containing the file config widget
;-   
pro spd_ui_plugin_manager::addFileConfigPanel, mission_name, procedure_name
    plugin_struct = [{mission_name: mission_name, procedure_name: procedure_name}]
    if ptr_valid(self.plugin_file_config_panels) then begin
        append_array, (*self.plugin_file_config_panels), plugin_struct
    endif else self.plugin_file_config_panels = ptr_new(plugin_struct)
end

;+
; NAME: 
;     getFileConfigPanels
;     
; PURPOSE: 
;     returns an array of structures, one struct for each file config panel
;     
; OUTPUT:
; 
;-
function spd_ui_plugin_manager::getFileConfigPanels
    if ptr_valid(self.plugin_file_config_panels) then begin
        return, *self.plugin_file_config_panels
    endif else return, 0
end

;+
; NAME: 
;     addPluginMenu
;     
; PURPOSE: 
;     Add a menu item to the "Plugins" menu in the GUI
;     
; INPUT: 
;    item: menu item text
;    procedure: name of the procedure containing the widget to open when the user selects this menu item
;    location: 
; 
;-   
pro spd_ui_plugin_manager::addPluginMenu, item, procedure, location
    plugin_struct = [{item: item, procedure: procedure, location: location}]
    
    if ptr_valid(self.plugin_menus) eq 1 then begin
        append_array, (*self.plugin_menus), plugin_struct
    endif else self.plugin_menus = ptr_new(plugin_struct)
end

;+
; NAME: 
;     getPluginMenus
;     
; PURPOSE: 
;     returns an array of structures, one for each plugin menu
;
;-   
function spd_ui_plugin_manager::getPluginMenus
    if ptr_valid(self.plugin_menus) then begin
        return, *self.plugin_menus
    endif else return, 0
end

;+
; NAME:
;    addDataProcessingPlugin
; 
; PURPOSE: 
;     add a new plugin to the "More..." menu in the data processing panel
;   
;-
pro spd_ui_plugin_manager::addDataProcessingPlugin, item, procedure, location
    plugin_struct = [{item: item, procedure: procedure, location: location}]
    if ptr_valid(self.data_proc_plugins) eq 1 then begin
        append_array, (*self.data_proc_plugins), plugin_struct
    endif else self.data_proc_plugins = ptr_new(plugin_struct)
end

;+
; NAME: 
;     getDataProcessingPlugins
;     
; PURPOSE: 
;     returns an array of structures, one for each data processing plugin
;
;-    
function spd_ui_plugin_manager::getDataProcessingPlugins
    if ptr_valid(self.data_proc_plugins) then begin
        return, *self.data_proc_plugins
    endif else return, 0
end

;+
; NAME: 
;     parseConfig
;     
; PURPOSE: 
;     parses a SPEDAS configuration file (.txt)
;
;-  
function spd_ui_plugin_manager::parseConfig, filename
    mission_name = ''
    file_template = { VERSION: 1.0, $
                 DATASTART: 0, $
                 DELIMITER: 58b, $
                 MISSINGVALUE: '', $
                 COMMENTSYMBOL: ";", $
                 FIELDCOUNT: 2, $
                 FIELDTYPES: [7, 7], $
                 FIELDNAMES: ['type', 'info'], $
                 FIELDLOCATIONS: [0, 10], $
                 FIELDGROUPS: [0, 1] $
                 }
    
    ; make sure this is a valid ascii file
    test_ascii = query_ascii(filename)
    if test_ascii ne 1 then return, 0

    plugin_data = read_ascii(filename, template=file_template, count=num_items)
    
    for plugin_idx = 0, n_elements(plugin_data.type)-1 do begin
        plugin_type = plugin_data.type[plugin_idx]
        plugin_info = plugin_data.info[plugin_idx]
        info_components = strsplit(plugin_info, ',', /extract)
        case plugin_type of
            'project': begin
                ; project definition
                mission_name = info_components[0]
            end
            'load_data': begin
                ; plugin has a load data panel
                if n_elements(info_components) eq 2 then begin
                    self->addLoadDataPanel, mission_name, info_components[0], info_components[1]
                endif else if n_elements(info_components) eq 1 then begin
                    self->addLoadDataPanel, mission_name, info_components[0], '' ; use mission name for tab/panel title
                endif else begin
                    dprint, dlevel = 0, 'Not enough arguments to add the Load Data panel for ' + filename
                endelse
            end
            'menu': begin
                ; plugin has a menu item
                if n_elements(info_components) eq 3 then begin
                    self->addPluginMenu, info_components[2], info_components[0], info_components[1]
                endif else begin
                    dprint, dlevel = 0, 'Not enough arguments to add plugin item to the "Plugins" menu. '
                endelse
            end
            'config': begin
                ; plugin has a config panel
                self->addFileConfigPanel, mission_name, info_components[0]
            end
            'data_processing': begin
                ; found a data processing plugin
                if n_elements(info_components) eq 3 then begin
                    self->addDataProcessingPlugin, info_components[2], info_components[0], info_components[1]
                endif else begin
                    dprint, dlevel = 0, 'Not enough arguments to add plugin item to the "Data Processing" panel'
                endelse
            end
            'about': begin
                ; found an "about" page for the plugin
                if n_elements(info_components) eq 1 then begin
                    self->addAboutPlugin, mission_name, info_components[0]
                endif else begin
                    dprint, dlevel = 0, 'Not enough arguments to add plugin''s About Page to the GUI'
                endelse
            end
            else: dprint, dlevel = 0, 'Error loading plugin, unknown plugin type: ' + string(plugin_type)
        endcase
    endfor
    return, 1
end

function spd_ui_plugin_manager::loadSaveFile, save_file
    catch, error_status
    if error_status ne 0 then return, 0
    result = file_test(save_file, /read)
    if result then begin
      restore, save_file 
      return, 1
    endif 
    return, 0
end

function spd_ui_plugin_manager::init
    getpluginpath, path
    if ~undefined(path) then begin
        ; find any save files in the plugins directory
        ;    (this is useful for adding new plugins to 
        ;     the VM releases that can't compile routines)
        plugin_sav_files = file_search(path, '*.sav')        
        for sav_idx = 0, n_elements(plugin_sav_files)-1 do begin
            if plugin_sav_files[sav_idx] eq '' then continue 
            if self->loadSaveFile(plugin_sav_files[sav_idx]) ne 1 then begin
                dprint, dlevel = 0, 'Error loading the save file at: ' + plugin_sav_files[sav_idx]
                ; throw an error dialog too, since we're probably in the VM here
                sa_error = error_message('Error loading the save file at: ' + plugin_sav_files[sav_idx], /error)
            endif
        endfor
        
        ; find the plugin files
        plugin_files = file_search(path, '*.txt')
        
        ; load the plugin files
        for plugin_idx = 0, n_elements(plugin_files)-1 do begin
            if self->parseConfig(plugin_files[plugin_idx]) ne 1 then begin
                dprint, dlevel = 0, 'Error parsing the configuration file: ' + plugin_files[plugin_idx]
            endif
        endfor
        
    endif
    return, 1
end

pro spd_ui_plugin_manager__define
    compile_opt idl2
    state = { SPD_UI_PLUGIN_MANAGER, $
        plugin_menus: ptr_new(), $
        plugin_file_config_panels: ptr_new(), $
        plugin_load_data_panels: ptr_new(), $
        plugin_about_pages: ptr_new(), $
        data_proc_plugins: ptr_new() $
    }
end