#!/usr/bin/tclsh
#
# A simple pack/unpack test
#

source oscPack.tcl
# Provides: proc packOSCpath {path types argList}
# Provides: proc makeElementFromPath  {path types argList}
# Provides: proc makeBundleFromElements {timestamp elementArray}

source oscUnpack.tcl
# Provides: proc unpackOSCpath oscBinStr => multilevel list
# Provides: proc handleEvent oscBinStr

source osctime.tcl
set ::osctime::debug 0
#
# This takes too long....
#
::osctime::setup

# How should we display some of the binary types ?
set ::oscUnpack::wantPackedMidi 0
set ::oscUnpack::wantHexBlob 1

#
# Sample callback routine
#
proc handleOSCmsg {path types valueList} {
	puts stdout [format "handleOSCmsg (%s) path=%s , types={%s} , values=\[%s\]" [clock format [clock seconds]] $path $types $valueList]
}

# How should we handle the reception ? See transmitOSC
set wantCallback 1

##########################################################################
proc testOSC {path types argList} {

	set debug $oscPack::debug

	if {$debug == 1} {
		puts stdout [format "Testing transmission with path=%s types={%s} values=\[%s\]" $path $types $argList]
	}

	set oscMsg [oscPack::packOSCpath $path $types $argList]

	if {[string length $oscMsg] > 0} {
		transmitOSC $oscMsg
	} else {
		puts stdout "FAILED oscPack::packOSCpath $path $types $argList"
	}
}
proc transmitOSC {oscMsg} {
	global wantCallback

	#
	# This is a dummy routine, that pretends to transmit,
	# but instead immediately decodes the oscMsg
	set debug $oscPack::debug

	if {$debug == 1} {
		puts stdout "\n====================================================================================="
		puts stdout "transmitOSC start : [clock format [clock seconds]]"
		set bytes [string length $oscMsg]
		set nibbles [expr $bytes * 2]
		binary scan $oscMsg H$nibbles hexrep

		puts stdout [format "Sending: %d bytes, raw:\n{%s}" $bytes $oscMsg]
		puts stdout [format "in hex:\n{%s}" $hexrep]
	}

	if {$wantCallback} {
		set ::oscUnpack::callback handleOSCmsg
		oscUnpack::handleEvent $oscMsg
	} else {
		set unpacked [oscUnpack::unpackOSCpath $oscMsg]
		puts stdout "$unpacked"
	}
}
##########################################################################

set path {/alpha/beta/gammaXXX}

set ::oscPack::haveGivenHexBlob 1
set ::oscPack::havePackedMidi 0

set iTimeStamp [::osctime::nowToOscTime]
set portId 11
set statusByte 0xa0
set data1 65
set data2 0

if {1 == 1} {

	set types {tidsstiTsFNIssficbcsmssts}
	set argList [list $iTimeStamp 32768 6.66666666666 omega gamma $iTimeStamp 0 alpha beta alpha 12345.67890 1 a {001133557799bbddff00} a alpha $portId $statusByte $data1 $data2 beta alpha $iTimeStamp beta]

	testOSC $path $types $argList
}

if {1 == 1} {
	# Simple bundle-test

	set types {tidsstiTsFNIssficbcsmssts}
	set argList [list $iTimeStamp 32768 6.66666666666 omega gamma $iTimeStamp 0 alpha beta alpha 12345.67890 1 a {001133557799bbddff00} a alpha $portId $statusByte $data1 $data2 beta alpha $iTimeStamp beta]

	set oscBundlePiece [::oscPack::makeElementFromPath $path $types $argList]

	set iTimeStamp [::osctime::futureToOscTime 5 15 1000]	; # now plus 5 and 15/1000th seconds into the future
	set oscBundleElement(0) $oscBundlePiece
	set oscBundleElement(1) $oscBundlePiece
	set oscBundleElement(2) $oscBundlePiece
	set oscBundleElement(3) $oscBundlePiece

	set bundle [::oscPack::makeBundleFromElements $iTimeStamp oscBundleElement]

	transmitOSC $bundle
}

if {1 == 0} {
	# test the 4 Symbolic options
	# Note, these do NOT affect what is sent/received, it ONLY
	# affects what you give and receive from that pack/unpack routines

	set types {iTsFNIs}
	set ::oscUnpack::wantSymbols {} 
		set ::oscPack::haveGivenSymbols 0
			set argList [list 32768 alpha beta]
			testOSC $path $types $argList

		set ::oscPack::haveGivenSymbols 1
			set argList [list 32768 1 alpha 0 {} NaN beta]
			testOSC $path $types $argList

	set ::oscUnpack::wantSymbols [list {<T>} {<F>} {<N>} {<I>}]
		set ::oscPack::haveGivenSymbols 0
			set argList [list 32768 alpha beta]
			testOSC $path $types $argList

		set ::oscPack::haveGivenSymbols 1
			set argList [list 32768 1 alpha 0 {} NaN beta]
			testOSC $path $types $argList
}

# Set back to default according to the spec.....
set ::oscPack::haveGivenSymbols 0
set ::oscUnpack::wantSymbols {} 

if {1 == 0} {
	# Blob test
	set ::oscPack::haveGivenHexBlob 1
	set types {sbs}
	set argList [list a {001133557799bbddff00} a]
	testOSC $path $types $argList
}

if {1 == 0} {
	# Midi, both packed and unpacked
	set types {sms}

	set oscPack::havePackedMidi 1
	if {$oscPack::havePackedMidi} {
		binary scan [binary format cccc [expr 0xff&$portId] [expr 0xff&$statusByte] [expr 0xff&$data1] [expr 0xff&$data2]] I pMidi
		puts stdout [format "Packed midi %x from %d %d %d %d" $pMidi $portId $statusByte $data1 $data2]
		set argList [list alpha $pMidi beta]
	} else {
		set argList [list alpha $portId $statusByte $data1 $data2 beta]
	}
	testOSC $path $types $argList

	set oscPack::havePackedMidi 0
	if {$oscPack::havePackedMidi} {
		binary scan [binary format cccc [expr 0xff&$portId] [expr 0xff&$statusByte] [expr 0xff&$data1] [expr 0xff&$data2]] I pMidi
		puts stdout [format "Packed midi %x from %d %d %d %d" $pMidi $portId $statusByte $data1 $data2]
		set argList [list alpha $pMidi beta]
	} else {
		set argList [list alpha $portId $statusByte $data1 $data2 beta]
	}
	testOSC $path $types $argList
}

if {1 == 0} {
	# Timestamps
	set iTimeStamp [::osctime::nowToOscTime]
	set types {sts}
	set argList [list alpha $iTimeStamp beta]
	testOSC $path $types $argList

	set iTimeStamp [::osctime::futureToOscTime 5 15 1000]	; # now plus 5 and 15/1000th seconds into the future
	set argList [list alpha $iTimeStamp beta]
	testOSC $path $types $argList

	set iTimeStamp [::osctime::instant]
	set argList [list alpha $iTimeStamp beta]
	testOSC $path $types $argList
}

if {[llength [after info]] > 0} {
	puts stdout "Waiting for : [after info]"
	vwait forever
}
