!******************************************************************************!
! Tests the detection of bad TimeLine Entries NXM-3040
!
! Arguments: None
!
! @bug      NXM-3040 TimeLine Issue #1 Bad TimeLineIssues
! @since    3.7.2
! @author:  Jeanette McCall
!******************************************************************************!
startmacro
  switch INTERACTIVE interAct GET DEF=TRUE  SDEF=TRUE  ! for normal interactive test(s)
  switch BASELINE    baseline GET DEF=FALSE SDEF=TRUE  ! for defects or more obscure test case(s)

  ! Only allow interAct if PANEL command Exists - may be running in LIBNXM mode
  invoke panelExists reg.shell.M.dictionary.isDictionaryEntry(PANEL)

  ! Specs from this file used for timeline creation
  res referenceFile nxm.sys.test.test_fftout_timeline.prm
  
  ! Spacing for timeline entries in elements
  ! (i.e. will have entries for elements 0,2,4,...)
  res spacing 2
  
  !
  ! TimeLine creator that will help in testing the other TimeLine issues
  ! (NXM-3041, NXM-3042)
  ! Note: These have been used to manually test TestTimelineCreator methods
  !
  ! create timeline with evenly spaced entries
  ! call testWithEvenlySpacedEntries referenceFile spacing

  ! Save off IOOptions as this test changes IOOptions.SuppressInvalidTimeLineEntryErrors
  env get IOOptions origIOOptions
  res errorsEnabled true

  res btnOptSuppress "CoreIO.IOOptions +SuppressInvalidTimeLineEntryErrors"
  res btnOptEnable   "CoreIO.IOOptions -SuppressInvalidTimeLineEntryErrors"

  if interAct and panelExists then
    res inst "Click on each test file to STATUS and verify that the &
              warning is the one specified in the SHELLGUI.\n\n&
              Then click the button '^{btnOptSuppress} to suppress &
              errors and status all the files again. No errors or &
              warnings should be present.\n\n&
              If all the tests give the correct warning, &
              click PASS."

    pipe on
      panel/msgid=MAIN/setup/controls=gc
      gcontrol label macro "MACRO"
      gcontrol menu MAIN "Exit with Status = " "PASS,FAIL" /tleft
      set gc.MAIN.itemColors {PASS=GREEN,FAIL=RED}
      gcontrol text idtext "INSTRUCTIONS" "^inst" 24 12 /title

      gcontrol menu statusfile "Test files to STATUS" &
                               "1.Status Bad BLUE microsecond TIMELINE,&
                                2.Status Bad BLUE high precision TC timeline,&
                                3.Status Bad PLATINUM high precision timeline,&
                                4.Create Bad timelime,&
                                5.Create Suspect timeline,&
                                6.Timeline insertion with timeline insertions disabled,&
                                7.Add Bad Entry Using User API&
                                "
      gcontrol button suppressbtn "Error Reporting Currently Enabled" ^btnOptSuppress
      shellgui/id=idshellgui/attach

    pipe off

  endif  ! end if interAct

  ! restore the original environment
  env set IOOptions origIOOptions


endmacro

!******************************************************************************!
! Main process message for this macro. Should be right after the ENDMACRO.
!******************************************************************************!
procedure processMessage m:msg
  if msg.name eqs "MAIN" then
    assert/text="^reg.main.name: Interactive tests for STATUS" msg.data eqss "PASS"
    pipe stop
  elseif msg.name eqs "SUPPRESSBTN" then
    invoke areSuppressed msg.data.contains("-")
    if areSuppressed then
      ! re-enable errors
      say "enabling errors"
      env set IOOptions -SuppressInvalidTimeLineEntryErrors
      set gc.suppressbtn.items ^btnOptSuppress
      set gc.suppressbtn.title "Error Reporting Currently Enabled" 
      res errorsEnabled true
    else 
      ! suppress errors
      say "disabling errors"
      env set IOOptions +SuppressInvalidTimeLineEntryErrors
      set gc.suppressbtn.items ^btnOptEnable
      set gc.suppressbtn.title "Error Reporting Currently Disabled"
      res errorsEnabled false
    endif
      
  elseif msg.name eqs "STATUSFILE" then
    ! clear text in SHELLGUI before next test case
    message func=sendx id=idshellgui name="CLEAR"
    ! res msg.data
    res badTimelineWarning &
      "'WARN: ERROR: Invalid TimeLine entry that occurs later in the timeline, but is back in time...'
    res badTimelineWarningOffset &
      "'WARN: ERROR: Invalid TimeLine entry that is at later offset, but is back in time...'
    res suspectTimelineWarning &
      "'WARN: Skipping probably invalid timeline entry,...'"
    res insertionsDisabledTimelineWarning &
      "'WARN: ERROR: Adding in a missed TimeLine entry with an earlier offset ...'"
    res badEntryTimelineException &
      "'WARN: ERROR: Adding in a missed TimeLine entry with an earlier offset ...'"

    if msg.data eqs "1.Status Bad Blue microsecond TIMELINE" then
      say "nM> KEY nxm.sys.test.bad_blue_timeline.prm
      if errorsEnabled then
        invoke ,, nxm.sys.lib.Shell.info("Warning expected for invalid BLUE microsecond timeline") 
      endif
      status nxm.sys.test.bad_blue_timeline.prm
      call lookAtTerminal 1 ^badTimelineWarning errorsEnabled

    elseif msg.data eqs "2.Status Bad Blue high precision TC timeline" then
      say "nM> STATUS bad_tc_timeline.prm
      if errorsEnabled then 
        invoke ,, nxm.sys.lib.Shell.info("Warning expected for invalid BLUE TC timeline")
      endif
      status nxm.sys.test.bad_tc_timeline.prm
      call lookAtTerminal 2 ^badTimelineWarningOffset errorsEnabled

    elseif msg.data eqs "3.Status Bad PLATINUM high precision timeline" then
      say "nM> STATUS bad_timetag_timeline.prm
      if errorsEnabled then
        invoke ,, nxm.sys.lib.Shell.info("Warning expected for invalid PLATINUM timeline")
      endif
      status nxm.sys.test.bad_timetag_timeline.prm
      call lookAtTerminal 3 ^badTimelineWarning errorsEnabled

    elseif msg.data eqs "4.Create Bad timelime" then
      if errorsEnabled then 
        invoke ,, nxm.sys.lib.Shell.info("Warning expected for creating bad timeline")
      endif
      call testWithBadTime referenceFile spacing
      call lookAtTerminal 4 ^badTimelineWarningOffset errorsEnabled

    elseif msg.data eqs "5.Create Suspect timeline" then
      if errorsEnabled then
        invoke ,, nxm.sys.lib.Shell.info("Warning expected for probably invalid timeline")
      endif
      call testWithSuspectTime referenceFile spacing
      call lookAtTerminal 5 ^suspectTimelineWarning errorsEnabled

    elseif msg.data eqs "6.Timeline insertion with timeline insertions disabled" then
      if errorsEnabled then
        invoke ,, nxm.sys.lib.Shell.info("Warning expected for timeline insertions disabled")
      endif
      call testWithBadOffset referenceFile spacing
      call lookAtTerminal 6 ^insertionsDisabledTimelineWarning errorsEnabled

    elseif msg.data eqs "7.Add Bad Entry Using User API" then
      if errorsEnabled then
        info "Should See INFO message below stating that test PASSed (if running this test stand-alone)"
      endif
      call testAddBadEntryUserAPI referenceFile spacing
      if errorsEnabled ISFALSE then info "No Exception expected"

    else
      say "^reg.main.name: unknown start time file: ^msg.data"
    endif
  else
    say "^reg.main.name: Unhandled message name: ^msg.name from fid: ^msg.fid data: ^msg.data"
  endif
return

!******************************************************************************!
! If an unexpected exception is caught, mark test as failed, unless it is expected
!******************************************************************************!
procedure processException m:emsg
  if expectedException REXISTS then
    assert/text="^reg.main.name: Expected ERROR starts with: ^{expectedException}" expectedException EQSS emsg.data.message
    remove expectedException
  else
    assert/text="^reg.main.name: Caught unexpected exception ^{emsg.data}" "FALSE" isTrue
    if "Trace" SUBS ENV.DEBUG then invoke ,, emsg.data.printStackTrace()
  endif
return

!******************************************************************************!
! Instructs user to look at terminal for warning
!******************************************************************************!
procedure lookAtTerminal L:num S:msg Z:errorsEnabled
  say "***************************************************"
  if errorsEnabled then
    info "Terminal warning #^{num}: ^msg"
  else
    info "No warnings or errors expected"
  endif
return

!******************************************************************************!
! Create a TimeLine with evenly spaced entries using
! TestTimelineCreator.timelineByElement
!******************************************************************************!
procedure testWithEvenlySpacedEntries fn:referenceFile L:spacing

  !---------------------------------------------------------------------
  ! Get values from reference file
  !---------------------------------------------------------------------
  
  ! Get number elements and delta
  status referenceFile SIZE=L:numElements XDELTA=D:delta

  ! Get bytes per element and Start Time
  file open/d tcprectag referenceFile
  ! Get bytes per element
  invoke L:bpe tcprectag.getBPE()
  ! Get Start Time
  invoke starttime tcprectag.getTime()
  file close tcprectag
  
  !---------------------------------------------------------------------
  ! Set Element Offsets and time adjustment for timeline entries
  !---------------------------------------------------------------------
  res adjustment 0.1
  
  ! Create single entry array with offset entry interval
  ! (KeyObject invoke methods treat varargs as an array) 
  res offsetEntries (^spacing)
  invoke oneOffsetArray=nxm.sys.test.TestTimelineCreator.getIntArray(1)
  invoke ,, offsetEntries.toArray(oneOffsetArray,0)

  !---------------------------------------------------------------------
  ! Create TimeLine with evenly spaced entries
  !---------------------------------------------------------------------

  invoke timeline_e=nxm.sys.test.TestTimelineCreator.timelineByElement(-1,delta,bpe,starttime,adjustment,numElements,oneOffsetArray)
  res timeline_e
  invoke tllist timeline_e.list(7)
  res tllist

  !---------------------------------------------------------------------
  ! Create Table with these TimeLine entries
  !---------------------------------------------------------------------
  invoke timelinetbl=timeline_e.toTable(12,bpe)
  res timelinetbl

return

!******************************************************************************!
! Create a TimeLine from a Table
! TestTimelineCreator.timelineFromTable
!
! KEY is element offset as String and VALUE is Time as String
!
!******************************************************************************!
procedure createFromTable fn:referenceFile t:timelinetbl U:timeline_result

  !---------------------------------------------------------------------
  ! Get values from reference file
  !---------------------------------------------------------------------

  ! Get number elements and delta
  status referenceFile SIZE=L:numElements XDELTA=D:delta

  ! Get bytes per element and Start Time
  file open/d filetag referenceFile
  ! Get bytes per element
  invoke L:bpe filetag.getBPE()
  file close filetag

  !---------------------------------------------------------------------
  ! Create TimeLine from a Table
  !---------------------------------------------------------------------
  invoke timeline_result=nxm.sys.test.TestTimelineCreator.timelineFromTable(delta,bpe,timelinetbl)
  !res timeline_result
  !invoke tllist timeline_result.list(7)
  !res tllist

return

!******************************************************************************!
! Create a TimeLine with bad Time using
! TestTimelineCreator.timelineBadTime
!
! EXPECTED: This will give a warning
!******************************************************************************!
procedure testWithBadTime fn:referenceFile L:entryInterval

  !---------------------------------------------------------------------
  ! Get values from reference file
  !---------------------------------------------------------------------

  ! Get number elements and delta
  status referenceFile SIZE=L:numElements XDELTA=D:delta
  !res numElements
  !res delta
  
  ! Get bytes per element and Start Time
  file open/d filetag referenceFile
  ! Get bytes per element
  invoke L:bpe filetag.getBPE()
  !res bpe
  ! Get Start Time
  invoke starttime filetag.getTime()
  !res starttime
  file close filetag

  !---------------------------------------------------------------------
  ! Try to create TimeLine with bad back in time timeline entry
  !---------------------------------------------------------------------
  invoke timeline_bad=nxm.sys.test.TestTimelineCreator.timelineBadTime(delta,bpe,starttime,numElements,entryInterval)
  !res timeline_bad
  !invoke tllist timeline_bad.list(7)
  !res tllist
  
  !---------------------------------------------------------------------
  ! Only needed when creating new files with this bad timeline
  !---------------------------------------------------------------------
  !call createFileSetWithTimeline referenceFile timeline_bad "bad_"

return

!******************************************************************************!
! Create a TimeLine with probably invalid Time that is back in time with
! respect to dt * offset using TestTimelineCreator.timelineBadTime
!
! EXPECTED: This will give a warning
!******************************************************************************!
procedure testWithSuspectTime fn:referenceFile L:entryInterval

  !---------------------------------------------------------------------
  ! Get values from reference file
  !---------------------------------------------------------------------

  ! Get number elements and delta
  status referenceFile SIZE=L:numElements XDELTA=D:delta
  !res numElements
  !res delta
  ! overwrite delta for this test because entry needs to be 1e7 back in time
  ! with respect to expected value
  res delta 1e7
  
  ! Get bytes per element and Start Time
  file open/d filetag referenceFile
  ! Get bytes per element
  invoke L:bpe filetag.getBPE()
  !res bpe
  ! Get Start Time
  invoke starttime filetag.getTime()
  !res starttime
  file close filetag

  !---------------------------------------------------------------------
  ! Try to create TimeLine with suspect in time timeline entry
  ! that is back in time with respect to dt * offset
  !---------------------------------------------------------------------
  invoke timeline_suspect=nxm.sys.test.TestTimelineCreator.timelineSuspectTime(delta,bpe,starttime,numElements,entryInterval)
  !res timeline_suspect
  !invoke tllist timeline_suspect.list(7)
  !res tllist
  
  !---------------------------------------------------------------------
  ! Only needed when creating new files suspect timeline
  !---------------------------------------------------------------------
  !call createFileSetWithTimeline referenceFile timeline_suspect "suspect_"

return


!******************************************************************************!
! Create a TimeLine where not all the offsets are in increasing order
! TestTimelineCreator.timelineBadOffsets
!
! NOTE: Support for adding missed entries SHOULD BE added in NXM-3042
! Currently the offset TimeLine just creates an out of order TimeLine
!******************************************************************************!
procedure testWithBadOffset fn:referenceFile L:entryInterval

  !---------------------------------------------------------------------
  ! Get values from reference file
  !---------------------------------------------------------------------

  ! Get number elements and delta
  status referenceFile SIZE=L:numElements XDELTA=D:delta
  !res numElements
  !res delta
  
  ! Get bytes per element and Start Time
  file open/d filetag referenceFile
  ! Get bytes per element
  invoke L:bpe filetag.getBPE()
  !res bpe
  ! Get Start Time
  invoke starttime filetag.getTime()
  !res starttime
  file close filetag
  !---------------------------------------------------------------------
  ! Try to create TimeLine with bad back in time timeline entry
  !---------------------------------------------------------------------
  invoke timeline_o=nxm.sys.test.TestTimelineCreator.timelineBadOffset(delta,bpe,starttime,numElements,entryInterval)
  !res timeline_o
  !invoke tllist timeline_o.list(7)
  !res tllist

return

!******************************************************************************!
! Add bad latter offset but back in time entry using user API
! (This will throw an Exception unless error reporting is disabled)
!******************************************************************************!
procedure testAddBadEntryUserAPI fn:referenceFile L:entryInterval

  !create timeline from table
  res timelinetbl {"2"="2017:04:06::00:30:01.0948091", &
                   "4"="2017:04:06::00:30:02.1948091", &
                   "6"="2017:04:06::00:30:03.2948091", &
                   "8"="2017:04:06::00:30:04.3948091"}
  call createFromTable referenceFile timelinetbl timeline_result

  ! create bad time (later offset, but earlier time) to add to the timeline
  timex "2017:04:06::00:30:02.2" d:badtime

  ! This will throw an Exception if error reporting is not disabled
  if errorsEnabled then
    set exceptionPt1 "KeyObject: An exception occurred while trying to run "
    set exceptionPt2 "public boolean nxm.sys.lib.TimeLine.setTimeAt(double,double,double)"
    set expectedException "^{exceptionPt1}^{exceptionPt2}"
  endif

  ! add the bad timeline entry
  invoke ,, timeline_result.setTimeAt(10,bpe,^badtime)

return

!******************************************************************************!
! Create a set of files (BLUE microsecond, BLUE TC, and PLATINUM with this
! by creating a file like the reference file, but with the new timeline
! TestTimelineCreator.timelineBadTime
!
! EXPECTED: This will give a warning
!******************************************************************************!
procedure createFileSetWithTimeline fn:referenceFile U:newtimeline S:basename

  res giveFileDetails true ! status/key each file as created

  !---------------------------------------------------------------------
  ! Create files with bad timeline
  !---------------------------------------------------------------------

  res TIMELINEfile ^{basename}blue_timeline.prm
  res TCfile       ^{basename}tc_timeline.prm
  res TIMETAGfile  ^{basename}timetag_timeline.prm
  
  convert referenceFile KWCONV TCfile OPTIONS={}
  ! replace the second file's timeline object with the original file's timeline object
  file open/d filetag TCfile{flags="|Input|Output|",USEBLUETCTIMELINE=true}
  invoke ,, filetag.setTimeLineObject(^newtimeline)
  file close filetag

  if giveFileDetails then
    say ""
    say ""
    say "*****************status/key TCfile***************************"

    status/key TCfile

    say ""
    say ""
    say "*****************convert badTC KWCONV badTIMELINEC***********"
  endif
  
  convert TCfile KWCONV TIMELINEfile{USEBLUETCTIMELINE=false} OPTIONS={}

  if giveFileDetails then
    say ""
    say ""
    say "*******************status/key TIMELINEfile*******************"

    status/key TIMELINEfile

    say ""
    say ""
    say "******************convert badTC KWCONV badTIMETAG************"
  endif
  
  convert TCfile KWCONV TIMETAGfile{USEPLATINUMTIMELINE=true} OPTIONS={}

  if giveFileDetails then
    say ""
    say ""
    say "******************status/key TIMETAGfile*********************"

    status/key TIMETAGfile
  endif

return


