!******************************************************************************!
!  Macro to test "HEADERMOD" intrinsic
!
!  Author:  J. Hallam & J. Czechowski
!******************************************************************************!
startmacro

  call setDatDir

  ! HEADERMOD SHOULD NOT CREATE A FILE w/o /CREATE SWITCH
  set expectException "DOES_NOT_EXIST"
  if temp_headermod_non_existing_file FEXISTS then
    erase temp_headermod_non_existing_file
  endif
  headermod temp_headermod_non_existing_file
  if expectException NEQS "" then
    assert/text="^reg.main.name: do not create without /CREATE switch" &
          temp_headermod_non_existing_file NFEXISTS
  endif

  ! Create a file
  call createDataFile
  call create6000
  call convertSFtoSB

  foreach mode inList "Individual,Combined,AddSubRec"
    call createRecordBased 3000 mode true
    call createRecordBased 5000 mode true
    call createRecordBased 6000 mode true
    call createRecordBased 3000 mode false
    call createRecordBased 5000 mode false
    call createRecordBased 6000 mode false
    call createManyRecords 3000 mode false 30 ! short names, >26 subrecs
    call createManyRecords 5000 mode false 30 ! short names, >14 components
    call createManyRecords 6000 mode false 30 ! short names, >14 components
    call createManyRecords 3000 mode true  30 ! long  names, >26 subrecs
    call createManyRecords 5000 mode true  30 ! long  names, >14 components
    call createManyRecords 6000 mode true  30 ! long  names, >26 subrecs
  endfor

  ! Test conversion from type-2000 to type-1000...then back to type-1000
  call convert1000to2000andback

  call headermodPipe
  call createDetachedHeader
  call invalidHeadermodTag                     ! Since 3.5.2 BUG 2869
endmacro

!******************************************************************************!
! If an unexpected exception is caught, mark test as failed, unless it is expected
!******************************************************************************!
procedure processException emsg
  ! This is an expected exception with the name of the procedure in the error
  if expectException EQS "DOES_NOT_EXIST" then
    assert/text="^reg.main.name: do not create  w/o /CREATE switch" temp_headermod_non_existing_file NFEXISTS
    set expectException ""
  elseif ((expectException EQSS "HEADERMOD")  OR (expectException EQSS "KeyObject")) &
        AND ^emsg.data STARTS "nxm.sys.lib.MidasException: ^expectException" then
     res gotCorrectException "true"
     set expectException ""
  else  ! FAIL on unknown exception
    assert/text="^reg.main.name: Caught unexpected exception ^{emsg.data}" "FALSE" isTrue
    if "Trace" SUBS ENV.DEBUG then invoke ,, emsg.data.printStackTrace()
    pipe stop
  endif
return

!******************************************************************************!
! Set the dat directory
!******************************************************************************!
procedure setDatDir
  invoke nxmMajor env.nmversion.subString(0,1)
  invoke major java.lang.Integer.valueOf(nxmMajor)
  if major GE 4 then
    invoke s:datDir           nxm.sys.test.DatLocator.getDatDirLocation()
    invoke s:datDirSlash      nxm.sys.test.DatLocator.getDatDirSlashLocation()
    invoke z:sysDatFull       nxm.sys.test.DatLocator.sysDatFull()
    invoke z:sysTestDatExists nxm.sys.test.DatLocator.sysTestDatExists()
  else
    set s:datDir           "nxm.sys.dat"
    set s:datDirSlash      "nxm/sys/dat"
    set z:sysDatFull       true
    set z:sysTestDatExists false
  endif
return

!******************************************************************************!
procedure createDataFile
  set testfile "temp_headermod.tmp"
  headermod/create testfile FORMAT=SB
  remove myFormat
  status testfile format=myFormat
  assert/text="^reg.main.name: CREATE SB" myFormat EQS "SB"
  erase testfile
return

!******************************************************************************!
! Need tests for creating type 3000 files using both forms
procedure createRecordBased L:type S:mode Z:oldSchool
  set records {1={NAME=COL1, FORMAT=SF, OFFSET=  0, TYPE=UNDEFINED, UNITS=NONE,       xTYPE=UNDEFINED, xUNITS=NONE},&
               2={NAME=COL2, FORMAT=XA, OFFSET=  4, TYPE=UNDEFINED, UNITS=NONE,       xTYPE=UNDEFINED, xUNITS=NONE},&
               3={NAME=COL3, FORMAT=VD, OFFSET= 84, TYPE=UNDEFINED, UNITS=NONE,       xTYPE=UNDEFINED, xUNITS=NONE},&
               4={NAME=COL4, FORMAT=SL, OFFSET=108, TYPE=UNDEFINED, UNITS=NONE,       xTYPE=UNDEFINED, xUNITS=NONE},&
               5={NAME=COL5, FORMAT=SF, OFFSET=112, TYPE=SCALAR,    UNITS=NONE,       xTYPE=1,         xUNITS=0},&
               6={NAME=COL6, FORMAT=SF, OFFSET=116, TYPE=SCALAR,    UNITS=TIME_S,     xTYPE=1,         xUNITS=1},&
               7={NAME=COL7, FORMAT=VD, OFFSET=120, TYPE=GEODETIC,  UNITS=ALTITUDE_M, xTYPE=GEODETIC,  xUNITS=ALT},&
               8={NAME=COL8, FORMAT=SF, OFFSET=144, TYPE=UNDEFINED, UNITS=NONE,       xTYPE=NONE,      xUNITS=NONE}}
  set nsr 8
  set len 148

  set indiv ""
  set comb  ""
  foreach key inTable records
    set rec records.^{key}
    if oldSchool isTrue and type eq 5000 then
      set indiv "^{indiv},C(^{key})=(^{rec.name},^{rec.format},^{rec.type},^{rec.units})"
      set comb  "^{comb},^{rec.name}/^{rec.format}/^{rec.type}/^{rec.units}"
    elseif oldSchool isTrue then
      set indiv "^{indiv},SR(^{key})=(^{rec.name},^{rec.format},^{rec.offset})"
      set comb  "^{comb},^{rec.name}/^{rec.format}"
    else
      set indiv "^{indiv},SR(^{key})=(^{rec.name},^{rec.format},^{rec.offset},^{rec.type},^{rec.units})"
      set comb  "^{comb},^{rec.name}/^{rec.format}/^{rec.offset}/^{rec.type}/^{rec.units}"
    endif
  endfor
  set indiv   indiv.substring(1)
  set comb    comb.substring(1)

  if oldSchool isTrue and type eq 5000 then
    set comb    "COMPONENTS=(^comb)"
    set setType "" ! type should be automatic
  elseif oldSchool isTrue and type eq 3000 then
    set comb    "SR=(^comb)"
    set setType "" ! type should be automatic
  else
    set comb    "SR=(^comb)"
    set setType "TYPE=^type"
  endif

  if mode eqs "Individual" then
    run "header/create ram:tempfile TYPE=^type RL=^len NSR=^nsr XUNITS=1 ^indiv"
  elseif mode eqs "Combined" then
    run "header/create ram:tempfile ^setType XUNITS=TIME ^comb"

  elseif mode eqs "AddSubRec" then
    file open/n/f tag ram:tempfile
    set tag.type   type
    set tag.xunits TIME
    foreach key inTable records
      set rec records.^{key}
      invoke ,, tag.addSubRec(^{rec.name},^{rec.format},^{rec.offset},^{rec.type},^{rec.units})
    endfor
    file close tag
  endif

  file open tag ram:tempfile
  res recs tag.recordDefs
  assert/text="^reg.main.name: /CREATE ^mode ^type - TYPE=^type"            ^type    eq  tag.type
  assert/text="^reg.main.name: /CREATE ^mode ^type - XUNITS=1"              1        eq  tag.xunits
  assert/text="^reg.main.name: /CREATE ^mode ^type - XUNITS=TIME_S"         "TIME_S" eqs tag.xunitsname
  assert/text="^reg.main.name: /CREATE ^mode ^type - RL=^len"               len      eq  tag.rl
  assert/text="^reg.main.name: /CREATE ^mode ^type - NSR=^nsr"              nsr      eq  tag.nsr

  foreach key inTable records
    set exp records.^{key}
    set act recs.^{exp.name}

    assert/text="^reg.main.name: /CREATE ^mode ^type - ^{exp.name}.NAME=^{exp.name}"      exp.name   eqs act.name
    assert/text="^reg.main.name: /CREATE ^mode ^type - ^{exp.name}.FORMAT=^{exp.format}"  exp.format eqs act.format
    assert/text="^reg.main.name: /CREATE ^mode ^type - ^{exp.name}.OFFSET=^{exp.offset}"  exp.offset eq  act.offset

    if type eq 5000 then
      assert/text="^reg.main.name: /CREATE ^mode ^type - ^{exp.name}.TYPE=^{exp.type}"      exp.type  eqs act.type
      assert/text="^reg.main.name: /CREATE ^mode ^type - ^{exp.name}.UNITS=^{exp.units}"    exp.units  eqs act.units
    elseif type eq 6000 and oldSchool isFalse then
      assert/text="^reg.main.name: /CREATE ^mode ^type - ^{exp.name}.UNITS=^{exp.units}"    exp.units  eqs act.units
    endif

  endfor
  file close tag
  erase ram:tempfile
return

!******************************************************************************!
procedure create6000
  ! JC4 (20DEC07): I tested $NMROOT/nxm/sys/dat/testxy6000.prm with X-Midas 4.4.4 and it was able to
  ! STATUS, DATALIST and XDATALIST it without any problems. The file testxy6000.prm is a copy of
  ! testxy3000.prm that has been HEADERMOD'ed to become a Type 6000 file (same as we do below). For
  ! these tests, we use testxy6000.prm and testxy3000.prm as our "gold" copies and compare our
  ! results to them.

  noop ^{datDir}.testxy3000.prm ram:tempxy6000
  headermod        ram:tempxy6000 type=6000 sr=(ABSC/SF/0,ORD/SF/4,ORD2/SF/8,ORD3/SF/12)
  headermod/create ram:new6000    type=6000 sr=(ABSC/SF/0,ORD/SF/4,ORD2/SF/8,ORD3/SF/12)

  KEY ^{datDir}.testxy6000.prm GET NAME="SUBREC_DEF"    VALUE=expDef
  KEY ram:tempxy6000             GET NAME="SUBREC_DEF"    VALUE=actDefTemp
  KEY ram:new6000                GET NAME="SUBREC_DEF"    VALUE=actDefNew
  KEY ^{datDir}.testxy6000.prm GET NAME="SUBREC_DSCRIP" VALUE=expDes
  KEY ram:tempxy6000             GET NAME="SUBREC_DSCRIP" VALUE=actDesTemp
  KEY ram:new6000                GET NAME="SUBREC_DSCRIP" VALUE=actDesNew

  assert/text="^reg.main.name: HEADER Type 6000 (MAIN HEADER)"          ram:tempxy6000 feq/h ^{datDir}.testxy6000.prm
  assert/text="^reg.main.name: HEADER Type 6000 (DATA - 6000)"          ram:tempxy6000 feq/d ^{datDir}.testxy6000.prm
  assert/text="^reg.main.name: HEADER Type 6000 (DATA - 3000)"          ram:tempxy6000 feq/d ^{datDir}.testxy3000.prm
  assert/text="^reg.main.name: HEADER Type 6000 (SUBREC_DEF)"           "^expDef" eqs "^actDefTemp"
  assert/text="^reg.main.name: HEADER Type 6000 (SUBREC_DSCRIP)"        "^expDes" eqs "^actDesTemp"
  assert/text="^reg.main.name: /CREATE Type 6000 (MAIN HEADER)"   ram:new6000 feq/h ^{datDir}.testxy6000.prm
  assert/text="^reg.main.name: /CREATE Type 6000 (SUBREC_DEF)"    "^expDef" eqs "^actDefNew"
  assert/text="^reg.main.name: /CREATE Type 6000 (SUBREC_DSCRIP)" "^expDes" eqs "^actDesNew"
return

!******************************************************************************!
! Try creating a file that uses long names (greater than 4 chars) and more than 26 subrecords
procedure createManyRecords L:type S:mode Z:long L:recs
  if long isTrue then
    set name "MY_SUPER_HUGE_FANTASTICALLY_LONG_RECORD_NAME_THAT_I_AM_USING_TODAY_"
    set text "^reg.main.name: ManyRecords ^mode ^type, ^recs recs, long names"
  elseif type eq 6000 then
    set name "MY_RECORD_NUMBER_" ! can not exceed 24 characters
    set text "^reg.main.name: ManyRecords ^mode ^type, ^recs recs, short names"
  else
    set name "SR"
    set text "^reg.main.name: ManyRecords ^mode ^type, ^recs recs, short names"
  endif

  set testfile "ram:temp"

  ! create the header
  if mode eqs "Individual" then
    return ! not tested

  elseif mode eqs "Combined" then
    do i 1 recs
      if i eq 1 then
        set subrecs "^{name}^{i}/SF"
      else
        set subrecs "^{subrecs},^{name}^{i}/SF"
      endif
    enddo
    headermod/create testfile type=^type sr=(^{subrecs})
  elseif mode eqs "AddSubRec" then
    ! Set the file up as would be seen in a primitive then write some data to the file. This
    ! tests a condition that failed in snap_nxm270_23nov08 since there was a missing call to
    ! DataFile.setInternals() at the end of DataFile.setSubRec(..)

    file open/n/f out testfile
    set out.type     type
    set out.timecode 0.0
    set out.xstart   2008:11:28::00:00:00
    set out.xdelta   300
    set out.xunits   TIME_S
    set out.size     recs

    do i 1 recs
      invoke ,, out.addSubRec("^{name}^{i}","SF")
    enddo

    do j 0 16
      set row {}
      do i 1 recs
        calc row.^{name}^{i} j 1000 * i +
      enddo
      invoke ,, out.setData(j,row)
    enddo

    file close out
  else
    error "createManyRecords: invalid mode [^mode] specified"
  endif


  ! check the values
  file open in testfile
    assert/text="^text (NSR=^in.nsr)" in.nsr eq recs
    set offset 0
    do i 1 recs
      calc k i 1 -
      invoke def     in.getRecordDef(k)
      invoke rawName in.getRecName(k,true)
      set expName    "^{name}^{i}"
      set expRawName expName
      if long isTrue then
        if type eq 6000 then
          invoke subs expName.substring(0,23)
        else
          invoke subs expName.substring(0,3)
        endif
        set expRawName "~^{subs}"
      endif
      assert/text="^text (i=^i,REXISTS)" def REXISTS
      assert/text="^text (i=^i,NAME)"    def.name   eqs "^expName"
      assert/text="^text (i=^i,RAWNAME)" rawName    eqs "^expRawName"
      assert/text="^text (i=^i,FORMAT)"  def.format eqs "SF"
      assert/text="^text (i=^i,OFFSET)"  def.offset eq  offset
      calc offset offset 4 +
    enddo
  file close in
  erase testfile
return

!******************************************************************************!
procedure convertSFtoSB
  set testfile "temp_headermod_sf2sb"
  waveform out=testFile FORM=SF ELEM=10
  headermod testfile format=SB
  status testfile format=myformat
  assert/text="^reg.main.name: SF-to-SB" myFormat EQS "SB"
  erase testfile

return

!******************************************************************************!
procedure convert1000to2000andback

  ! INITIALIZE
  result testFile "testfile_headermod"
  result tempFile "tempfile_headermod"

  result nelsOrig 4k

  ! This is the test file used by more than one test
  waveform out=testFile ELEM=nelsOrig

  noop testFile tempFile
  status tempFile size=nels
  if nels NEQ nelsOrig then
    assert/text="^reg.main.name: 1000-to-2000, noop setup" FALSE
  else
    ! Set
    result fsExpected 100
    calc/quiet nelsExpected nelsOrig fsExpected /

    headermod tempFile type=2000 fs=fsExpected
    status tempFile size=nels2000 fs=frameSize
    result dbgText "^reg.main.name: 1000-to-2000, size = ^nels2000/fs = ^frameSize"
    assert/stat=tempStatus/text=dbgText nels2000 EQ nelsExpected AND frameSize EQ fsExpected
    if tempStatus EQS "PASS" then
      ! Convert 2000 back to 1000
      headermod tempFile type=1000
      status tempFile size=nels1000
      result dbgText "^reg.main.name: 2000-to-1000, size = ^nels1000/orig = ^nelsOrig"
      assert/text=dbgText nels1000 EQ nelsOrig
    else
      result dbgText "Unable to perform 2000-to-1000 headermod due to 1000-to-2000 failure"
      assert/text=dbgText false
    endif
  endif

  if tempFile FEXISTS erase tempFile

  ! CLEANUP
  if testFile REXISTS and testFile FEXISTS erase testFile

return

!******************************************************************************!
! test case for updating header of a PIPE (BUG 2610)
procedure headermodPipe
  set expframeSize 1k
  set format "SF"
  set size 4k  ! using a small size so test case completes quickly, must be >= expframeSize
  set expSize size/expframeSize
  set expType 1000
  pipe on
    ! create type 1000 pipe
    waveform _pipe format size
    status _pipe type=type size=sz
    assert/text="^reg.main.name: initial pipe is type 1000 [^type]" type eq 1000
    assert/text="^reg.main.name: initial pipe size is ^size [^sz]"  sz   eq size
    ! change pipe to type 2000
    headermod _pipe FrameSize=^expframeSize
    status _pipe type=type size=sz FrameSize=fs
    assert/text="^reg.main.name: pipe updated to type 2000 [^type]" type eq 2000
    assert/text="^reg.main.name: pipe size updated to ^expSize [^sz]" sz eq expSize
    assert/text="^reg.main.name: pipe frame size updated to ^expframeSize [^fs]" fs eq expframeSize
  pipe off
return

!******************************************************************************!
! test case for creating detached header using /DETACH switch
procedure createDetachedHeader
  headermod/create/detach detach_tempfile.tmp SR=(LABL/2A,ABSC/SD,ORD/SD)
  status detach_tempfile det=detflag

  assert/text="^reg.main.name: detached header file exists after /DETACH switch" detach_tempfile.det FEXISTS
  assert/text="^reg.main.name: detached flag is set to 1 after /DETACH switch" detflag EQ 1

  if detach_tempfile FEXISTS erase detach_tempfile
return

!******************************************************************************!
! test case for HEADERMOD with invalid TAG  Since 3.5.2  BUG 2869
procedure invalidHeadermodTag
  headermod/create ram:junk_2869

  res expectException "HEADERMOD: T=... not supported: use TYPE="
  res gotCorrectException "false"
  headermod ram:junk_2869 t=2000      ! T is NOT a valid TAG (must be TYPE=)
  assert/text="^reg.main.name: HEADERMOD with invalid Tag T= gives Exception" gotCorrectException eqs "true"

  res expectException "HEADERMOD: REP=... not supported: use DATAREP= or HEADREP="
  res gotCorrectException "false"
  headermod ram:junk_2869 REP=IEEE    ! REP is NOT a valid TAG (must be HR or DR)
  assert/text="^reg.main.name: HEADERMOD with invalid Tag REP= gives Exception" gotCorrectException eqs "true"

  res expectException "KeyObject: Can not access 'X'"
  res gotCorrectException "false"
  headermod ram:junk_2869 x=junk      ! x is NOT a valid TAG
  assert/text="^reg.main.name: HEADERMOD with invalid Tag x= gives Exception" gotCorrectException eqs "true"

  erase ram:junk_2869
return
