;+
;WIDGET Procedure:
;  spp_ptp_recorder
;PURPOSE:
; Widget tool that opens a socket and records streaming data from a server (host) and can save it to a file
; or send to a user specified routine. This tool runs in the background.
; Keywords:
;   SET_FILE_TIMERES : defines how often the current output file will be closed and a new one will be opened
;   DIRECTORY:  string prepended to fileformat when opening an output file.
; Author:
;    Davin Larson - April 2011
;
; $LastChangedBy: davin-mac $
; $LastChangedDate: 2018-07-27 16:40:55 -0700 (Fri, 27 Jul 2018) $
; $LastChangedRevision: 25525 $
; $URL: svn+ssh://thmsvn@ambrosia.ssl.berkeley.edu/repos/spdsoft/tags/spedas_3_1/projects/SPP/COMMON/spp_ptp_recorder.pro $
;
;-

PRO spp_ptp_recorder_event, ev   ; recorder
 ;   on_error,1

    widget_control, ev.top, get_uvalue= info   ; get all widget ID's
    wids = *info.wids
    localtime=1
    dlevel=info.dlevel

    CASE ev.id OF                         ;  Timed events
    wids.base:  begin
   ;   printdat,info
       on_ioerror, stream_error
       eofile =0
       info.time_received = systime(1)
       widget_control,wids.base,set_uvalue=info
        
       if info.hfp gt 0 then begin
         ;;   Switch file name if needed
         if info.file_timeres ne 0 then begin
           if info.time_received ge info.next_filechange then begin
             dprint,dlevel=dlevel,time_string(info.time_received,prec=3)+ ' Time to change files.'
             if info.dfp then begin
               spp_ptp_recorder_event,{top: ev.top, id:wids.dest_button}   ; close old file  - possible error that dfp might change!
               spp_ptp_recorder_event,{top: ev.top, id:wids.dest_button}   ; open  new file
             endif
           endif
           widget_control, ev.top, get_uvalue= info   ; get all widget ID's
           info.next_filechange = info.file_timeres * ceil(info.time_received / info.file_timeres)
           widget_control,wids.base,set_uvalue=info
         endif
         if 1 then begin
           spp_ptp_lun_read,info.hfp,info.dfp,info=info
           widget_control,wids.base,set_uvalue=info
           msg = info.msg
         endif else begin 
            on_ioerror, stream_error
            eofile =0
            info.time_received = systime(1)
            widget_control,wids.base,set_uvalue=info
            buffer= bytarr(info.maxsize) 
            b=buffer[0]
            i = 0L
            cnt =0L
            nhdr = 5
            nb = nhdr
            while file_poll_input(info.hfp,timeout=0) && i lt info.maxsize  do begin      ; Read from stream one byte (or value) at a time 
                b = bytarr(nb)
                readu,info.hfp,b
                buffer[i] = b
                i += nb
                if (nb eq nhdr) && (b[2] eq 3) && (b[3] eq 0) && b[4] eq 'bb'x then begin  ; look at first few bytes to determine how large the packet is
                  nb = swap_endian(uint(b,0) ,/swap_if_little_endian ) - nhdr
;                  dprint,dlevel=3,nb,i
                endif else  if nb gt 10 then begin   ; reset to read first few bytes on the next read
                    nb = nhdr
;                    dprint,dlevel=3,nb
                endif else nb =1
                cnt++
            endwhile
            dt = systime(1) -info.time_received
;            store_data,/append,'xrate',systime(1),dt/i*1e6
            if debug(5) then begin
              dprint,dlevel=4,nb,cnt,i,dt, dt/i*1e6
            endif

            if eofile eq 1 then begin
              stream_error:
              widget_control,wids.host_text,get_value=hostname
              widget_control,wids.host_port,get_value=hostport
              dprint,dlevel=dlevel+1,info.title_num+!error_state.msg
            endif            
            if i gt 0 then begin                      ;; process data
              buffer = buffer[0:i-1]
              if keyword_set(info.dfp) then writeu,info.dfp, buffer  ;swap_endian(buffer,/swap_if_little_endian)
              flush,info.dfp
              msg = string(/print,i,buffer[0:(i < 64)-1],format='(i6 ," bytes: ", 128(" ",Z02))')
              msg = time_string(info.time_received,tformat='hh:mm:ss - ',local=localtime) + msg
            endif else begin
              dummy = temporary(buffer)    ;           buffer=0
              msg =time_string(info.time_received,tformat='hh:mm:ss - No data available',local=localtime)
            endelse
            if widget_info(/button_set,wids.proc_button) then begin
              widget_control,wids.proc_name,get_value = proc_name
              if keyword_set(proc_name) then call_procedure,proc_name[0],buffer ,info=info  ;,time=info.time_received   ; Execute exec_proc here
            endif
         endelse
          widget_control,wids.output_text,set_value=msg
          dprint,dlevel=dlevel+5,info.title_num+msg,/no_check
          widget_control,wids.poll_int,get_value = poll_int
          poll_int = float(poll_int)
          if poll_int le 0 then poll_int = 1
          if 1 then begin
            poll_int = poll_int - (systime(1) mod poll_int)  ; sample on regular boundaries
          endif

          if not keyword_set(eofile) then WIDGET_CONTROL, wids.base, TIMER=poll_int else begin
            widget_control,wids.host_button,timer=2
          endelse
       endif
       return
    end
    wids.host_button : begin
        widget_control,wids.host_button,get_value=status
        widget_control,wids.host_text, get_value=server_name
        widget_control,wids.host_port, get_value=server_port
        server_n_port = server_name+':'+server_port
        case status of
        'Connect to': begin
            *info.buffer_ptr = !null                                  ; Get rid of previous buffer contents cache
            WIDGET_CONTROL, wids.host_button, set_value = 'Connecting',sensitive=0
            WIDGET_CONTROL, wids.host_text, sensitive=0
            WIDGET_CONTROL, wids.host_port, sensitive=0
            socket,hfp,/get_lun,server_name,fix(server_port),error=error ,/swap_if_little_endian,connect_timeout=10
            if keyword_set(error) then begin
              dprint,dlevel=dlevel-1,info.title_num+!error_state.msg+strtrim(error)   ;strmessage(error)
              widget_control, wids.output_text, set_value=!error_state.msg
              WIDGET_CONTROL, wids.host_button, set_value = 'Failed:',sensitive=1
              WIDGET_CONTROL, wids.host_text, sensitive=1
              WIDGET_CONTROL, wids.host_port, sensitive=1
            endif else begin
              dprint,dlevel=dlevel,info.title_num+'Connected to server: "'+server_n_port+'"  Unit:'+strtrim(hfp)
              info.hfp = hfp
              WIDGET_CONTROL, wids.base, TIMER=1    ; , set_uvalue=hfp
              WIDGET_CONTROL, wids.host_button, set_value = 'Disconnect',sensitive=1
            endelse
        end
        'Disconnect': begin
            WIDGET_CONTROL, wids.host_button, set_value = 'Closing'  ,sensitive=0
            WIDGET_CONTROL, wids.host_text, sensitive=1
            WIDGET_CONTROL, wids.host_port, sensitive=1
            msg = 'Disconnected from server: "'+server_n_port+'"'
            widget_control, wids.output_text, set_value=msg
            dprint,dlevel=dlevel,info.title_num+msg
            free_lun,info.hfp
            info.hfp =0
            wait,1
            WIDGET_CONTROL, wids.host_button, set_value = 'Connect to',sensitive=1
        end
        else: begin
            WIDGET_CONTROL, wids.host_text, sensitive=1
            WIDGET_CONTROL, wids.host_port, sensitive=1
            WIDGET_CONTROL, wids.host_button, set_value = 'Connect to',sensitive=1
            dprint,info.title_num+'Error Recovery'
        end
        endcase
    end
    wids.dest_button: begin
        widget_control,ev.id,get_value=status

        widget_control,wids.dest_text, get_value=filename
        case status of
        'Write to': begin
            if keyword_set(info.dfp) then begin
                free_lun,info.dfp
                info.dfp = 0
            endif
            WIDGET_CONTROL,   ev.id       , set_value = 'Opening' ,sensitive=0
            widget_control, wids.dest_text, get_value = fileformat,sensitive=0
            filename = time_string(systime(1),tformat = fileformat[0])                     ; Substitute time string
            widget_control,wids.host_text, get_value=hostname
            filename = str_sub(filename,'{HOST}',strtrim(hostname,2) )
            widget_control,wids.host_port, get_value=hostport
            filename = str_sub(filename,'{PORT}',strtrim(hostport,2) )               ; Substitute port number
            widget_control, wids.dest_text, set_uvalue = fileformat,set_value=filename
            if keyword_set(filename) then begin
                file_open,'u',info.directory+filename, unit=dfp,dlevel=4,compress=-1,file_mode='666'o,dir_mode='777'o
                dprint,dlevel=dlevel,info.title_num+' Opened output file: '+info.directory+filename+'   Unit:'+strtrim(dfp)
                info.dfp = dfp
                info.filename= info.directory+filename
                widget_control, wids.dest_flush, sensitive=1
            endif
;              wait,1
            WIDGET_CONTROL, ev.id, set_value = 'Close   ',sensitive =1
        end
        'Close   ': begin
            WIDGET_CONTROL, ev.id,          set_value = 'Closing',sensitive=0
            widget_control, wids.dest_flush, sensitive=0
            widget_control, wids.dest_text ,get_uvalue= fileformat,get_value=filename
            if info.dfp gt 0 then begin
                free_lun,info.dfp
                info.dfp =0
            endif
;            wait,1
            widget_control, wids.dest_text ,set_value= fileformat,sensitive=1
            WIDGET_CONTROL, ev.id, set_value = 'Write to',sensitive=1
            dprint,dlevel=dlevel,info.title_num+'Closed output file: '+filename,no_check_events=1
        end
        else: begin
            dprint,info.title_num+'Invalid State'
        end
        endcase
    end
    wids.dest_flush: begin
      spp_ptp_recorder_event,{top: ev.top, id:wids.dest_button}   ; close old file
      spp_ptp_recorder_event,{top: ev.top, id:wids.dest_button}   ; open  new file      
    end
;    wids.host_text:  begin
;        widget_control,ev.id,get_value=value
;        dprint,'"'+value+'"'
;    end
    wids.proc_button: begin
      widget_control,wids.proc_name,get_value=proc_name
      widget_control,wids.proc_name,sensitive = (ev.select eq 0)
      info.run_proc = ev.select
      dprint,dlevel=2,info.title_num+'"'+proc_name+ '" is '+ (info.run_proc ? 'ON' : 'OFF') 
    end
    wids.done: begin   ;    'DONE' ;  close files here!
        if info.hfp gt 0 then begin
            fs = fstat(info.hfp)
            dprint,dlevel=dlevel-1,info.title_num+'Closing '+fs.name
            free_lun,info.hfp
        endif
        if info.dfp gt 0 then begin
            fs = fstat(info.dfp)
            dprint,dlevel=dlevel-1,info.title_num+'Closing '+fs.name
            free_lun,info.dfp
        endif
        ptr_free,ptr_extract(info)
        WIDGET_CONTROL, ev.TOP, /DESTROY
        dprint,dlevel=dlevel-1,info.title_num+'Widget Closed'
        return
    end
    else: begin
        msg = string('Base ID is: ',wids.base)
        widget_control, wids.output_text, set_value=msg
        dprint,info.title_num+msg
        printdat,ev
        printdat,info
    end
    ENDCASE
    widget_control,wids.base,set_uvalue=info
END


;PRO exec_proc_template,buffer,info=info
;;    savetomain,buffer
;;    savetomain,time
;
;    n = n_elements(buffer)
;    if n ne 0 then  begin
;    if debug(2) then begin
;      dprint,time_string(info.time_received,prec=3) +''+ strtrim(n_elements(buffer))
;      n = n_elements(buffer) < 512
;      hexprint,buffer[0:n-1]    ;,swap_endian(uint(buffer,0,n_elements(buffer)/2))
;    endif
;    endif else print,format='(".",$)'
;
;    return
;end





PRO spp_ptp_recorder,base,title=title,ids=ids,host=host,port=port,destination=destination,exec_proc=exec_proc, $
          set_connect=set_connect, set_output=set_output, pollinterval=pollinterval, set_file_timeres=set_file_timeres ,$
          get_procbutton = get_procbutton,set_procbutton=set_procbutton,directory=directory, $
          get_filename=get_filename,info=info
if ~(keyword_set(base) && widget_info(base,/managed) ) then begin
    if not keyword_set(host) then host = 'localhost'
    if not keyword_set(port) then port = '2022'
    if not keyword_set(title) then title = 'SPP PTP Recorder'
    port=strtrim(port,2)
    if not keyword_set(destination) then destination = 'socket_{HOST}.{PORT}_YYYYMMDD_hhmmss.dat'
    ids = create_struct('base', WIDGET_BASE(/COLUMN, title=title ) )
    ids = create_struct(ids,'host_base',   widget_base(ids.base,/row, uname='HOST_BASE') )
    ids = create_struct(ids,'host_button', widget_button(ids.host_base, uname='HOST_BUTTON',value='Connect to') )
    ids = create_struct(ids,'host_text',   widget_text(ids.host_base,  uname='HOST_TEXT' ,VALUE=host ,/EDITABLE ,/NO_NEWLINE ) )
    ids = create_struct(ids,'host_port',   widget_text(ids.host_base,  uname='HOST_PORT',xsize=6, value=port   , /editable, /no_newline))
    ids = create_struct(ids,'poll_int' ,   widget_text(ids.host_base,  uname='POLL_INT',xsize=6,value='1',/editable,/no_newline))
;    if n_elements(directory) ne 0 then $
;      ids = create_struct(ids,'destdir_text',   widget_text(ids.base,  uname='DEST_DIRECTORY',xsize=40 ,/EDITABLE ,/NO_NEWLINE  ,VALUE=directory))
    ids = create_struct(ids,'dest_base',   widget_base(ids.base,/row, uname='DEST_BASE'))
    ids = create_struct(ids,'dest_button', widget_button(ids.dest_base, uname='DEST_BUTTON',value='Write to'))
    ids = create_struct(ids,'dest_text',   widget_text(ids.dest_base,  uname='DEST_TEXT',xsize=40 ,/EDITABLE ,/NO_NEWLINE  ,VALUE=destination))
    ids = create_struct(ids,'dest_flush',  widget_button(ids.dest_base,uname='DEST_FLUSH', value='New' ,sensitive=0))
    ids = create_struct(ids,'output_text', WIDGET_TEXT(ids.base, uname='OUTPUT_TEXT'))
    ids = create_struct(ids,'proc_base',   widget_base(ids.base,/row, uname='PROC_BASE'))
    ids = create_struct(ids,'proc_base2',  widget_base(ids.proc_base ,/nonexclusive))
    ids = create_struct(ids,'proc_button', widget_button(ids.proc_base2,uname='PROC_BUTTON',value='Procedure:'))
    ids = create_struct(ids,'proc_name',   widget_text(ids.proc_base,xsize=35, uname='PROC_NAME', value = keyword_set(exec_proc) ? exec_proc :'exec_proc_template',/editable, /no_newline))
    ids = create_struct(ids,'done',        WIDGET_BUTTON(ids.proc_base, VALUE='Done', UNAME='DONE'))
    title_num = title+' ('+strtrim(ids.base,2)+'): '

    if 1 then info = { socket_recorder } else begin
      info = {wids: ptr_new(), $
        ;      hostname:host, hostport:port, $
        title: title, $
        title_num: title_num, $
        time_received: 0d,  $
        file_timeres: 0d,   $
        next_filechange: 1d20, $
        hfp:0,  $
        directory:'' ,  $
        fileformat:destination,  $
        filename:'', $
        dfp:0 , $
        maxsize:2L^23, $
        buffer_ptr: ptr_new(),   $
        ;        pollinterval:1., $
        verbose:2, $
        dlevel: 2, $
        msg: '', $
        exec_proc_ptr: ptr_new(), $
        last_time: 0d, $
        total_bytes: 0uL, $
        process_rate : 0d, $
        run_proc:keyword_set(set_procbutton) }      
    endelse
        
    info.wids = ptr_new(ids)
    info.next_filechange = 1d20
    info.title=title
    info.title_num = title_num
    info.fileformat = destination
    info.maxsize = 2L^23
    info.buffer_ptr = ptr_new(!null)
    info.verbose =2
    info.exec_proc_ptr = ptr_new(!null)
    info.run_proc = keyword_set(set_procbutton) 
        
;    info.buffer_ptr = ptr_new( bytarr( info.maxsize ) )
    WIDGET_CONTROL, ids.base, SET_UVALUE=info
    WIDGET_CONTROL, ids.base, /REALIZE
    widget_control, ids.base, base_set_title=title_num
    XMANAGER, 'spp_ptp_recorder', ids.base,/no_block
    dprint,dlevel=dlevel,info.title_num+'Widget started'
    base = ids.base
endif else begin
    widget_control, base, get_uvalue= info   ; get all widget ID's
    ids = *info.wids
endelse
if size(/type,exec_proc) eq 7 then    widget_control,ids.proc_name,set_value=exec_proc
if size(/type,destination) eq 7 then  widget_control,ids.dest_text,set_value=destination
if size(/type,host) eq 7 then  widget_control,ids.host_text,set_value=host
if n_elements(port) eq 1 then  widget_control,ids.host_port,set_value=strtrim(port,2)
if n_elements(pollinterval) ne 0 then widget_control,ids.poll_int,set_value=strtrim(pollinterval,2)
if n_elements(set_output)  eq 1 && (keyword_set(info.dfp) ne keyword_set(set_output )) then spp_ptp_recorder_event, { id:ids.dest_button, top:ids.base }
if n_elements(set_connect) eq 1 && (keyword_set(info.hfp) ne keyword_set(set_connect)) then spp_ptp_recorder_event, { id:ids.host_button, top:ids.base }
if n_elements(set_procbutton) eq 1 then begin
  widget_control,ids.proc_button,set_button=set_procbutton
  spp_ptp_recorder_event, { top:ids.base, id:ids.proc_button, select: keyword_set(set_procbutton) }
endif
if n_elements(set_file_timeres) then begin
  info.file_timeres = set_file_timeres
  widget_control, base, set_uvalue= info   
endif
if n_elements(directory) then begin
  info.directory = directory
  widget_control, base, set_uvalue= info
endif
get_procbutton = widget_info(ids.proc_button,/button_set)
;widget_control,ids.dest_text,get_value=get_filename
get_filename = keyword_set(info.dfp) ? info.filename : ''


END