; $Id: browser.pro 7 2008-02-08 12:11:50Z Harald $
; Copyright (c) 2006, IWF/OAW. All rights reserved.
;       Unauthorized reproduction prohibited.
;+
; NAME:
;       MID_BROWSE
;
; PURPOSE:
;       This software is used to browse and verify the ROSETTA/MIDAS
;       archive data products.
;
; CATEGORY:
;       Data Processing.
;
; CALLING SEQUENCE:
;       Mid_Browse [, data_set_path]
;
; INPUT/OUTPUT:
;       Settings are taken from and written to the [MIDAS DATA SET BROWSER]
;       section in the idl_user.ini file which is located in the user's
;       home directory.
;
; PROCEDURE:
;       TBW
;
; REFERENCE:
;       TBW
;
; MODIFICATION HISTORY:
;       Written by:     Harald Jeszenszky, IWF/OAW, Nov 2006.
;-

;-----------------------------------------------------------------------
;   ROUTINE
;       browser_data, name, data [, label, PATH=path]
;
;   PURPOSE
;       Extract data from the given PDS data file.
;-----------------------------------------------------------------------
PRO browser_data, name, data, label, PATH=path

    ; data = readpds(name, PATH=path, LABEL=label, /SILENT, /NOVERIFY)

    mnem = STRMID(FILE_BASENAME(name), 0, 3)
    
    ; copy format files (if required)
    CASE (mnem) OF
    'CAH' : format = 'CAH_STRUCTURE.FMT'
    'EVN' : format = 'EVN_STRUCTURE.FMT'
    'FSC' : format = 'FSC_PREFIX.FMT'
    'HK1' : format = 'HK1_STRUCTURE.FMT'
    'HK2' : format = 'HK2_STRUCTURE.FMT'
    'LIN' : format = 'LIN_STRUCTURE.FMT'
    'SPA' : format = 'SPA_STRUCTURE.FMT'
    'SPS' : format = 'SPS_PREFIX.FMT'
    'TGH' : format = 'TGH_STRUCTURE.FMT'
;    '???' : format = 'ROI_STRUCTURE.FMT'
    ELSE  : format = ''
    ENDCASE
    
;    IF (format NE '') THEN BEGIN
;       src = FILEPATH(format, ROOT=path, SUB='LABEL')
;       tgt = FILEPATH(format, ROOT=FILE_DIRNAME(name))
;       IF (~FILE_TEST(tgt)) THEN $
;           FILE_COPY, src, tgt $
;       ELSE $
;           format = ''
;    ENDIF
    
    data = readpds(name, HEADPDS=label, /SILENT)
    ; HELP, /FILES
;    CLOSE, /ALL                        ; readpds does not free units !!!
;    IF (format NE '') THEN $
;       FILE_DELETE, tgt

    ; delete format files (if required)

    ; remove cr-lf and compress multiple empty lines
    pos = STREGEX(label, '['+STRING(BYTE([10,13]))+']+$')
    idx = WHERE(pos GE 0, cnt)
    IF (cnt GT 0) THEN label[idx] = STRMID(label[idx], 0, TRANSPOSE(pos[idx]))

    idx = WHERE(STRTRIM(label) NE '', cnt)
    IF (cnt GT 0) THEN BEGIN
        skip = (idx[cnt-1] EQ N_ELEMENTS(label)-1)      ; skip last line?
        next = idx[0:cnt-1-skip] + 1
        idx2 = WHERE(STRTRIM(label[next]) EQ '', cnt2)
        IF (cnt2 GT 0) THEN idx = [TEMPORARY(idx), next[idx2]]
        label = label[idx[SORT(idx)]]
    ENDIF ELSE $
        label = ''

    ; get object name
    CASE (mnem) OF
    'CAH' : struct = { object:'CANTILEVER_HISTORY', label:label }
    'EVN' : struct = { object:'MIDAS_EVENT_HISTORY', label:label }
    'FSC' : struct = { object:'FREQUENCY_SCAN_DATA', label:label }
    'HK1' : struct = { object:'HOUSEKEEPING_DATA', label:label }
    'HK2' : struct = { object:'HOUSEKEEPING_DATA', label:label }
    'LIN' : struct = { object:'LINE_SCAN_DATA', label:label }
    'IMG' : struct = { object:'IMAGE_SCAN_DATA', label:label }
    'TGH' : struct = { object:'TARGET_HISTORY', label:label }
    'SPA' : struct = { object:'SPA_SCAN_DATA', label:label }
    'SPS' : struct = { object:'SPS_SCAN_DATA', label:label }
    ELSE  : struct = { object:'UNKNOWN (' + mnem + ')', label:label }
    ENDCASE

    ; prepare data
    SWITCH (mnem) OF
    'CAH' :
    'EVN' :
    'TGH' : BEGIN
        n_recs = N_ELEMENTS(data.(1).(1))
        text = STRARR(n_recs+1)
        FOR i = 0, N_ELEMENTS(data.(1).names)-1 DO BEGIN
            tname = SIZE(data.(1).(i+1), /TNAME)
            CASE (tname) OF
            'LONG'   : value = ToStr(data.(1).(i+1), 'I0')
            'STRING' : value = STRTRIM(data.(1).(i+1), 2)
            'DOUBLE' : value = ToStr(data.(1).(i+1), 'F0.3')
            ELSE : BEGIN
                value = STRARR(n_recs)
                MESSAGE, 'Data type not handled: ' + tname, /CONTINUE
            END
            ENDCASE
            value = [data.(1).names[i], TEMPORARY(value)]
            fcode = 'A' + (tname EQ 'STRING' ? '-' : '') + $
                    STRTRIM(MAX(STRLEN(value)), 1)
            text += (i EQ 0 ? '' : ' ') + ToStr(value, fcode)
        ENDFOR
        struct = CREATE_STRUCT(struct, 'TEXT', text)
        BREAK
    END
    'FSC' :
    'HK1' :
    'HK2' :
    'LIN' :
    'SPA' :  BEGIN
        FOR i = 0, N_ELEMENTS(data.(1).names)-1 DO BEGIN
            IF (SIZE(data.(1).(i+1), /TNAME) EQ 'STRUCT') THEN BEGIN
                FOR j = 1, N_TAGS(data.(1).(i+1)) DO BEGIN
                    struct = CREATE_STRUCT(TEMPORARY(struct), data.(1).names[i+j], data.(1).(i+1).(j-1))
                ENDFOR
                i = i + j
            ENDIF ELSE $
                struct = CREATE_STRUCT(TEMPORARY(struct), data.(1).names[i], data.(1).(i+1))
        ENDFOR
        IF (mnem EQ 'FSC') THEN $
            struct = CREATE_STRUCT(TEMPORARY(struct), data.(2).(0), data.(2).(1))
        BREAK
    END
    'IMG' : BEGIN
        struct = CREATE_STRUCT(struct, 'BCR_IMAGE', data.(1))
        BREAK
    END
    'SPS' : BEGIN
        struct = CREATE_STRUCT(struct, 'TEXT', 'Data display not yet supported.')
    END
    ELSE  : ; do nothing
    ENDSWITCH

    data = TEMPORARY(struct)

END ; browser_data

;-----------------------------------------------------------------------
;   ROUTINE
;       info = browser_info(data [, index])
;
;   PURPOSE
;       Extract textual information from the given data object.
;-----------------------------------------------------------------------
FUNCTION browser_info, data, index

    IF (N_ELEMENTS(index) EQ 0) THEN index = 0
    info = ''

    CASE (data.object) OF
    'FREQUENCY_SCAN_DATA' : BEGIN
        info = ToStr(TAG_NAMES(data), 'A', MAX(STRLEN(TAG_NAMES(data))))
        FOR i = 2, N_TAGS(data)-1 DO BEGIN
            IF (i EQ 24 || i EQ 25) THEN CONTINUE
            info[i] += ' = ' + STRTRIM(LONG(data.(i)[index]), 2)
        ENDFOR
        info[1] = ''
    END
    'LINE_SCAN_DATA' : BEGIN
        info = ToStr(TAG_NAMES(data), 'A', MAX(STRLEN(TAG_NAMES(data))))
        FOR i = 2, N_TAGS(data)-1 DO BEGIN
            IF (i EQ 22 || i EQ 23) THEN CONTINUE
            info[i] += ' = ' + STRTRIM(LONG(data.(i)[index]), 2)
        ENDFOR
        info[1] = ''
    END
    'SPA_SCAN_DATA' : BEGIN
        info = ToStr(TAG_NAMES(data), 'A', MAX(STRLEN(TAG_NAMES(data))))
        FOR i = 2, N_TAGS(data)-1 DO BEGIN
            IF (i GE 23 && i LE 27) THEN CONTINUE
            info[i] += ' = ' + STRTRIM(LONG(data.(i)[index]), 2)
        ENDFOR
        info[1] = ''
    END
    ELSE : ; do nothing
    ENDCASE

    info[0] = 'PRODUCT = ' + data.object

    RETURN, info

END ; browser_info

;-----------------------------------------------------------------------
;   ROUTINE
;       browser_cleanup, id
;
;   PURPOSE
;       Save current settings, free data strutures and exit.
;-----------------------------------------------------------------------
PRO browser_cleanup, id

    WIDGET_CONTROL, id, GET_UVALUE=ptr

    ini_file, (*ptr).state, 'MIDAS DATA SET BROWSER', /SAVE

    PTR_FREE, ptr

END ; browser_cleanup

;-----------------------------------------------------------------------
;   ROUTINE
;       browser_tree_event, ev
;
;   PURPOSE
;       Process tree widget event messages.
;-----------------------------------------------------------------------
PRO browser_tree_event, ev

    CATCH, error
    IF (error NE 0) THEN BEGIN
        CATCH, /CANCEL
        error_msg, /TRACEBACK, /ERROR
        RETURN
    ENDIF
    WIDGET_CONTROL, ev.top, GET_UVALUE=ptr

    WIDGET_CONTROL, ev.id, GET_UVALUE=file
    name = FILE_BASENAME(file)
    path = FILE_DIRNAME(file)
    (*ptr).nodeVal = name

    WIDGET_CONTROL, /HOURGLASS

    CASE (1) OF
    STREGEX(name, '(EVN|CAH|TGH|SPS)_.+\.$', /BOOL) : BEGIN
        name = FILEPATH(name + 'LBL', ROOT_DIR=path)
        browser_data, name, data, text, PATH=(*ptr).state.data_set_path
        WIDGET_CONTROL, (*ptr).idInfo, SET_VALUE=browser_info(data)
        WIDGET_CONTROL, (*ptr).idDraw, MAP=0
        WIDGET_CONTROL, (*ptr).idTabl, MAP=1
        WIDGET_CONTROL, (*ptr).idTabl, SET_VALUE=data.text
    END
    STRMATCH(name, 'HK?_*.', /FOLD_CASE) : BEGIN
        name = FILEPATH(name + 'LBL', ROOT_DIR=path)
        browser_data, name, data, text, PATH=(*ptr).state.data_set_path
        WIDGET_CONTROL, (*ptr).idInfo, SET_VALUE=browser_info(data)
        index = WIDGET_INFO((*ptr).idList, /DROPLIST_SELECT)
        names = TAG_NAMES(data)
        names = ['Select Plot Parameter...', names[2:*]]
        IF (index LE 0) || (index GE N_ELEMENTS(names)) THEN index = 0
        WIDGET_CONTROL, (*ptr).idList, SET_VALUE=names, $
                        SET_UVALUE=data, /NO_COPY, $
                        SET_DROPLIST_SELECT=index, $
                        SEND_EVENT={ID:0L, TOP:0L, HANDLER:0L, INDEX:index}
        WIDGET_CONTROL, (*ptr).idTabl, MAP=0
        WIDGET_CONTROL, (*ptr).idDraw, MAP=1
    END
    STRMATCH(name, 'FSC_*.') || STRMATCH(name, 'LIN_*.') : BEGIN
        name = FILEPATH(name + 'LBL', ROOT_DIR=path)
        browser_data, name, data, text, PATH=(*ptr).state.data_set_path
        WIDGET_CONTROL, (*ptr).idInfo, SET_VALUE=browser_info(data)
        index = WIDGET_INFO((*ptr).idList, /DROPLIST_SELECT)
        count = N_ELEMENTS(data.(2))
        names = 'DATA_RECORD_' + STRTRIM(INDGEN(count)+1, 2) + $
                '_OF_' + STRTRIM(count, 2)
        names = ['Select Plot Parameter...', TEMPORARY(names)]
        IF (index LE 0) || (index GE N_ELEMENTS(names)) THEN index = 0
        WIDGET_CONTROL, (*ptr).idList, SET_VALUE=names, $
                        SET_UVALUE=data, /NO_COPY, $
                        SET_DROPLIST_SELECT=index, $
                        SEND_EVENT={ID:0L, TOP:0L, HANDLER:0L, INDEX:index}
        WIDGET_CONTROL, (*ptr).idTabl, MAP=0
        WIDGET_CONTROL, (*ptr).idDraw, MAP=1
    END
    STRMATCH(name, 'IMG_*.') : BEGIN
        name = FILEPATH(name + 'LBL', ROOT_DIR=path)
        browser_data, name, data, text, PATH=(*ptr).state.data_set_path
        WIDGET_CONTROL, (*ptr).idInfo, SET_VALUE=browser_info(data)
        draw = WIDGET_INFO((*ptr).idDraw, /GEOMETRY)
        dims = SIZE(data.(2), /DIMENSIONS)
        fact = MAX(dims / [draw.xsize, draw.ysize])
        dims = dims/fact
        image = CONGRID(data.(2), dims[0], dims[1], /CENTER, /INTERP)
        WSET, (*ptr).winNum
        ERASE, 255
        TV, BYTSCL(image), (draw.xsize-dims[0])/2, $
                           (draw.ysize-dims[1])/2, /DEVICE
        WIDGET_CONTROL, (*ptr).idTabl, MAP=0
        WIDGET_CONTROL, (*ptr).idDraw, MAP=1
    END
    STRMATCH(name, 'SPA_*.') : BEGIN
        name = FILEPATH(name + 'LBL', ROOT_DIR=path)
        browser_data, name, data, text, PATH=(*ptr).state.data_set_path
        WIDGET_CONTROL, (*ptr).idInfo, SET_VALUE=browser_info(data)
        index = WIDGET_INFO((*ptr).idList, /DROPLIST_SELECT)
        count = N_ELEMENTS(data.(2))
        names = 'DATA_RECORD_' + STRTRIM(INDGEN(count)+1, 2) + $
                '_OF_' + STRTRIM(count, 2)
        names = ['Select Plot Parameter...', TEMPORARY(names)]
        IF (index LE 0) || (index GE N_ELEMENTS(names)) THEN index = 0
        WIDGET_CONTROL, (*ptr).idList, SET_VALUE=names, $
                        SET_UVALUE=data, /NO_COPY, $
                        SET_DROPLIST_SELECT=index, $
                        SEND_EVENT={ID:0L, TOP:0L, HANDLER:0L, INDEX:index}
        WIDGET_CONTROL, (*ptr).idTabl, MAP=0
        WIDGET_CONTROL, (*ptr).idDraw, MAP=1
    END
    ELSE : BEGIN                        ; any other tree selection
        WIDGET_CONTROL, (*ptr).idInfo, SET_VALUE=''
        WIDGET_CONTROL, (*ptr).idList, SET_VALUE='No Plot Parameter Available'
        WIDGET_CONTROL, (*ptr).idTabl, SET_VALUE=''
        WSET, (*ptr).winNum
        ERASE, 255

        IF STRMATCH(name, '*.PDF') THEN BEGIN
            ONLINE_HELP, BOOK=file, /FULL_PATH
            text = 'File displayed in external browser.'
        ENDIF ELSE IF STRMATCH(name, '*.PNG', /FOLD_CASE) THEN BEGIN
            WIDGET_CONTROL, (*ptr).idTabl, MAP=0
            WIDGET_CONTROL, (*ptr).idDraw, MAP=1
            name = FILEPATH(name, ROOT_DIR=path)
            ok = QUERY_PNG(name, info)
            READ_PNG, name, image, r, g, b
            draw = WIDGET_INFO((*ptr).idDraw, /GEOMETRY)
            fact = MAX(info.dimensions / [draw.xsize, draw.ysize])
            IF (fact GT 1.0) THEN BEGIN
                info.dimensions = ROUND(info.dimensions/fact)
            ENDIF
            IF (~info.has_palette) THEN BEGIN
                image = COLOR_QUAN(image, 1, r, g, b, COLORS=254)
            ENDIF
            image = CONGRID(image, info.dimensions[0], info.dimensions[1])
            TVLCT, r, g, b, 1
            TV, image + 1B, (draw.xsize-info.dimensions[0])/2, $
                            (draw.ysize-info.dimensions[1])/2, /DEVICE
            text = ''
        ENDIF ELSE IF FILE_TEST(file, /REGULAR) THEN BEGIN
            blck = STRARR(1024)
            ON_IOERROR, END_OF_DATA
            OPENR, unit, file, /GET_LUN
            WHILE NOT EOF(unit) DO BEGIN
                READF, unit, blck
            END_OF_DATA:
                count = (FSTAT(unit)).TRANSFER_COUNT
                IF (N_ELEMENTS(text) EQ 0) THEN $
                    text = blck[0:count-1] $
                ELSE $
                    text = [TEMPORARY(text), blck[0:count-1]]
            ENDWHILE
            ON_IOERROR, NULL
            FREE_LUN, unit
        ENDIF ELSE BEGIN
            text = ''
            file = ''
        ENDELSE
    ENDELSE
    ENDCASE

    top = WIDGET_INFO((*ptr).idText, /TEXT_TOP_LINE)
    WIDGET_CONTROL, (*ptr).idText, SET_VALUE=text, SET_TEXT_TOP=top
    WIDGET_CONTROL, (*ptr).idFile, SET_VALUE=file

END ; browser_tree_event

;-----------------------------------------------------------------------
;   ROUTINE
;       browser_event, ev
;
;   PURPOSE
;       Process widget event messages.
;-----------------------------------------------------------------------
PRO browser_event, ev

    ON_ERROR, 2
    WIDGET_CONTROL, ev.top, GET_UVALUE=ptr

    CASE (ev.id) OF
    (*ptr).idExit : BEGIN
        WIDGET_CONTROL, ev.top, /DESTROY
    END
    (*ptr).idList : BEGIN
        WSET, (*ptr).winNum
        LOADCT, 3, /SILENT
        IF (ev.index EQ 0) THEN BEGIN
            ERASE, 255
            RETURN
        ENDIF
        ev.index = ev.index - 1
        WIDGET_CONTROL, (*ptr).idList, GET_UVALUE=data, /NO_COPY
        CASE (data.object) OF
        'HOUSEKEEPING_DATA' : BEGIN
            xdat = JULDAY(1, 1, 1958, 0) + (data.packet_obt_seconds+(data.packet_obt_fraction+32768D)/65536D)/86400D
            sidx = (OBJPDS(data.label, 'COLUMN')).index[ev.index]
            eidx = GET_INDEX(data.label, sidx)
            offs = PDSPAR(data.label[sidx:eidx], 'OFFSET', COUNT=npar)
            offs = (npar EQ 0) ? 0.0 : FLOAT(offs[0])
            fact = PDSPAR(data.label[sidx:eidx], 'SCALING_FACTOR', COUNT=npar)
            fact = (npar EQ 0) ? 1.0 : FLOAT(fact[0])
            unit = PDSPAR(data.label[sidx:eidx], 'UNIT', COUNT=npar)
            unit = (npar EQ 0 ? '' : ' [' + unit[0] + ']')
            ydat = data.(ev.index+2)*fact + offs
            ymin = MIN(ydat, MAX=ymax)
            yrange = (ymin EQ ymax) ? [ymin-0.1,ymax+0.1] : [ymin,ymax]
            PLOT, xdat, ydat, /YNOZERO, YRANGE=yrange, /NODATA, $
                  XTICKFORMAT='(C(CMOI02.2,"/",CDI02.2))', $
                  COLOR=0, BACKGROUND=255, YTICKFORMAT='(F0.1)', $
                  TITLE=(*ptr).nodeVal+'DAT', XTITLE='UTC', $
                  YTITLE=(TAG_NAMES(data))[ev.index+2]+unit
            OPLOT, xdat, ydat, COLOR=192
        END
        'FREQUENCY_SCAN_DATA' : BEGIN
            WIDGET_CONTROL, (*ptr).idInfo, $
                            SET_VALUE=browser_info(data, ev.index)
            xdata = (FINDGEN(256)*data.frequency_step[ev.index] + $
                    data.start_frequency[ev.index])*6.984E-4
            IF (SIZE(data.data_samples, /N_DIM) GT 1) THEN $
                ydata = data.data_samples[*,ev.index]*3.0518E-4 $
            ELSE $
                ydata = data.data_samples*3.0518E-4
            PLOT, xdata, ydata, XSTYLE=1, /YNOZERO, YRANGE=[0,10], /NODATA, $
                  TITLE=(*ptr).nodeVal+'DAT', XTICKFORMAT='(F0.1)', $
                  XTITLE='Frequency [Hz]', YTITLE='Amplitude [V]', $
                  COLOR=0, BACKGROUND=255
            OPLOT, xdata, ydata, COLOR=192
            PLOTS, data.frequency_at_max[ev.index]*6.984E-4, $
                   data.ac_maximum[ev.index]*3.0518E-4, $
                   PSYM=6, COLOR=128
        END
        'LINE_SCAN_DATA' : BEGIN
            WIDGET_CONTROL, (*ptr).idInfo, $
                            SET_VALUE=browser_info(data, ev.index)
            count = data.num_steps[ev.index]
            xdata = LINDGEN(count)*data.step_size[ev.index] + $
                    data.x_origin[ev.index]
            IF (SIZE(data.z_set_value, /N_DIM) GT 1) THEN $
                ydata = data.z_set_value[0:count-1, ev.index] $
            ELSE $
                ydata = data.z_set_value[0:count-1]
            yrange = FLOAT([MIN(ydata, MAX=max), max])
            IF (yrange[0] EQ yrange[1]) THEN yrange += [-1,1]
            PLOT, xdata, ydata, XSTYLE=1, /YNOZERO, /NODATA, $
                  COLOR=0, BACKGROUND=255, YTICKFORMAT='(I0)', $
                  XTICKFORMAT='(I0)', YRANGE=yrange, $
                  XTITLE='Position', YTITLE='Z SetValue', $
                  TITLE=(*ptr).nodeVal+'DAT'
            OPLOT, xdata, ydata, COLOR=192
        END
        'SPA_SCAN_DATA' : BEGIN
            WIDGET_CONTROL, (*ptr).idInfo, $
                            SET_VALUE=browser_info(data, ev.index)
            plotwin = !P
            ypltwin = !Y
            !P.MULTI = [0,1,4]
            !P.CHARSIZE = 2.0
            !Y.MARGIN = [0,0]
            !Y.OMARGIN=[4,2]
;            xdata = data.z_pos_sample[*,ev.index]*1.0+32768
            fact = [3.0518E-4, 3.0518E-4, 5.4932E-3, 1.0]
            offs = [0.0, 0.0, 0.0, 32768.0]
            yname = ['AC [V]', 'DC [V]', 'Phase [deg]', 'Z']
            names = TAG_NAMES(data)
            FOR i = 0, 3 DO BEGIN
                ydata = data.(24+i)[*,ev.index]*fact[i] + offs[i]
                PLOT, ydata, XSTYLE=1, /YNOZERO, $ ; YRANGE=[0,10], $
                      TITLE=(i eq 0 ? (*ptr).nodeVal+'DAT' : ''), $
                      XTICKFORMAT=(i EQ 3 ? '(F0.1)' : '(A1)'), $
                      YTITLE=yname[i], COLOR=0, BACKGROUND=255, /NODATA
                OPLOT, ydata, COLOR=128
            ENDFOR
            !Y = ypltwin
            !P = plotwin
        END
        ELSE : ; do nothing
        ENDCASE
        WIDGET_CONTROL, (*ptr).idList, SET_UVALUE=data, /NO_COPY
    END
    ELSE : BEGIN
        HELP, /STRUC, ev
    END
    ENDCASE

END ; browser_event

;-----------------------------------------------------------------------
;   ROUTINE
;       mid_browse
;
;   PURPOSE
;       Main program of the MIDAS Data Set Browser software. Loads the
;       default parameters, creates the GUI and starts the XMANAGER.
;-----------------------------------------------------------------------
PRO mid_browse, path, GROUP=group

    CATCH, error
    IF (error NE 0) THEN BEGIN
        CATCH, /CANCEL
        error_msg, /ERROR, /TRACEBACK
        RETURN
    ENDIF

    ;-------------------------------------------------------------------
    ; load state structure and default data set path
    ;-------------------------------------------------------------------

    state = { $
        data_set_path : '' $
    }
    ini_file, state, 'MIDAS DATA SET BROWSER', /LOAD

    IF (N_ELEMENTS(path) EQ 0) THEN BEGIN
        path = DIALOG_PICKFILE(PATH=state.data_set_path, /DIRECTORY, $
                               /MUST_EXIST)
        IF (path EQ '') THEN $
            MESSAGE, 'Data set path not specified.'
    ENDIF ELSE BEGIN
        IF (NOT FILE_TEST(path, /DIRECTORY)) THEN $
            MESSAGE, 'Given data set path not found.'
    ENDELSE
    state.data_set_path = path
    IF (N_ELEMENTS(group) EQ 0) THEN group = 0L

    lsize = 150
    ffont = 'Courier New*14'

    LOADCT, 3, /SILENT
    DEVICE, DECOMPOSED=0

    tree = path
    root = -1
    index = 0
    count = 1
    regex = PATH_SEP() + '*DATA.*'
    IF (!VERSION.OS_FAMILY EQ 'Windows') THEN regex = PATH_SEP() + regex

    WHILE (index LT count) DO BEGIN
        IF (FILE_TEST(tree[index], /DIRECTORY)) THEN BEGIN
            isData = STREGEX(STRMID(tree[index], STRLEN(path)), regex, /BOOL)
            search = FILEPATH('*', ROOT_DIR=tree[index])
            lst = FILE_SEARCH(search, /TEST_DIRECTORY, COUNT=cnt)
            IF (cnt GT 0) THEN BEGIN
                tree = [TEMPORARY(tree), lst]
                root = [TEMPORARY(root), REPLICATE(index, cnt)]
                count += cnt
            ENDIF
            IF (isData) THEN BEGIN
                lst = FILE_SEARCH(search+'.LBL', /TEST_REGULAR, COUNT=cnt)
                IF (cnt GT 0) THEN $
                    lst = STRMID(lst, 0, TRANSPOSE(STRLEN(lst)-3))
            ENDIF ELSE $
                lst = FILE_SEARCH(search, /TEST_REGULAR, COUNT=cnt)
            IF (cnt GT 0) THEN BEGIN
                tree = [TEMPORARY(tree), lst]
                root = [TEMPORARY(root), REPLICATE(index, cnt)]
                count += cnt
            ENDIF
        ENDIF
        ++index
    ENDWHILE

    ;-------------------------------------------------------------------
    ; get S/W revision and show information in main window title
    ;-------------------------------------------------------------------

    @RELEASE
    txt = program + ' - Revision '
    ids = STRSPLIT(revision, /EXTRACT, COUNT=cnt)
    IF (cnt NE 5) THEN $
        txt = txt + '???' $
    ELSE $
        txt = txt + ids[1] + ' ' + ids[3]

    ;-------------------------------------------------------------------
    ; create widget hierarchy
    ;-------------------------------------------------------------------

    idMain = WIDGET_BASE(TITLE=txt, /COLUMN, GROUP=group, TLB_FRAME=1)
    idRow  = WIDGET_BASE(idMain, /ROW)

    idBase = WIDGET_BASE(idRow, /COLUMN, /FRAME)
    idTree = WIDGET_TREE(idBase, XSIZE=280, YSIZE=280)
    idJunk = WIDGET_LABEL(idBase, VALUE='Data File Attributes')
    idInfo = WIDGET_TEXT(idBase, YSIZE=25, FONT=ffont)
    idJunk = WIDGET_LABEL(idBase, VALUE='Plot Parameter Selection')
    idList = WIDGET_DROPLIST(idBase, VALUE='No Plot Parameter Available', $
                             XSIZE=280)

    idNode = LONARR(N_ELEMENTS(tree))
    idNode[0] = WIDGET_TREE(idTree, VALUE=FILE_BASENAME(path), /FOLDER, $
                            /EXPANDED, UVALUE=tree[0], $
                            EVENT_PRO='browser_tree_event')
    FOR i = 1, N_ELEMENTS(tree) - 1 DO BEGIN
        dir = FILE_TEST(tree[i], /DIRECTORY)
        idNode[i] = WIDGET_TREE(idNode[root[i]], VALUE=FILE_BASENAME(tree[i]), $
                                FOLDER=dir, UVALUE=tree[i], $
                                EVENT_PRO='browser_tree_event')
    ENDFOR

    idBase = WIDGET_BASE(idRow, /COLUMN, /FRAME)
    idFile = WIDGET_LABEL(idBase, VALUE=' ', /DYNAMIC, /SUNKEN_FRAME)
    idText = WIDGET_TEXT(idBase, XSIZE=80, YSIZE=25, FONT=ffont, /SCROLL)

    idBase = WIDGET_BASE(idBase) ; , XPAD=0, YPAD=0, SPACE=0)
    idBmap = WIDGET_BASE(idBase, MAP=1)
    idDraw = WIDGET_DRAW(idBmap, YSIZE=300, /FRAME)
    idBmap = WIDGET_BASE(idBase, MAP=0)
    idTabl = WIDGET_TEXT(idBmap, XSIZE=80, YSIZE=20, FONT=ffont, /SCROLL)

    idBase = WIDGET_BASE(idMain, /ROW)

    idExit = WIDGET_BUTTON(idMain, VALUE='Exit Data Set Browser')

    ;-------------------------------------------------------------------
    ; create state structure and realize widgets
    ;-------------------------------------------------------------------

    ptr = PTR_NEW({ $
        idMain  : idMain, $
        idTree  : idTree, $
        idFile  : idFile, $
        idText  : idText, $
        idList  : idList, $
        idDraw  : idDraw, $
        idTabl  : idTabl, $
        idInfo  : idInfo, $
        idExit  : idExit, $
        fldFont : ffont, $
        winNum  : 0L, $
        nodeVal : '', $
        state   : state $
    })

    WIDGET_CONTROL, idMain, /REALIZE, SET_UVALUE=ptr

    geometry = WIDGET_INFO(idText, /GEOMETRY)
    xsize = geometry.scr_xsize - geometry.xoffset
    WIDGET_CONTROL, idFile, XSIZE=xsize
    WIDGET_CONTROL, idDraw, XSIZE=xsize, GET_VALUE=wnum
    (*ptr).winNum = wnum
    ERASE, 255

    ;-------------------------------------------------------------------
    ; update widgets and start XMANAGER
    ;-------------------------------------------------------------------

    XMANAGER, 'browser', idMain, CLEANUP='browser_cleanup', /NO_BLOCK

END ; mid_browse

; $MAIN$

    mid_browse, 'D:\Daten\Midas\Archiving\RO-C-MIDAS-3-ESC3-SAMPLES-V1.0'

END ; $MAIN$