proc P { str } {
    catch {puts $str ; flush stdout}
}

proc PN { str } {
    catch {puts -nonewline $str ; flush stdout}
}

proc PP { str } {
    P ""
    P $str
    P ""
}

proc PS { } {
    P ""
    P "------------------------------------------------------------"
    P ""
}

proc PE { str } {
    P ""
    P "Error: $str"
    P ""
}

proc PH { str } {
    P ""
    P "Test: $str"
    PS
}

proc PF { floatVal { prec 4 } } {
    set fmtStr "%.${prec}f"
    return [format $fmtStr $floatVal]
}

proc PSec { msg sec } {
    P [format "%s: %.4f seconds" $msg $sec]
}

proc PrintMachineInfo {} {
    global tcl_platform

    P "Machine specific information:"
    P  "platform     : $tcl_platform(platform)"
    P  "os           : $tcl_platform(os)"
    P  "osVersion    : $tcl_platform(osVersion)"
    P  "machine      : $tcl_platform(machine)"
    P  "byteOrder    : $tcl_platform(byteOrder)"
    P  "wordSize     : $tcl_platform(wordSize)"
    P  "pointerSize  : $tcl_platform(pointerSize)"
    P  "user         : $tcl_platform(user)"
    P  "hostname     : [info hostname]"
    P  "Tcl version  : [info patchlevel]"
    P  "Tk version   : [package version Tk]"
    P  "poImg version: [package version poImg]"
    # P  "Visuals     : [winfo visualsavailable .]"
}

proc SetFileTypes { } {
    global fInfo

    set fInfo(suf)   ".tga"
    set fInfo(fmt)   "targa"
    set fInfo(vsn)   "int"
    set fInfo(phFmt) "tga"
}

proc RandomInit { seed } {
    variable randomSeed

    set randomSeed $seed
}

proc Random { } {
    variable randomSeed

    if { ! [info exists randomSeed] } {
        set randomSeed 1
    }
    set randomSeed [expr {($randomSeed * 9301 + 49297) % 233280}]
    return [expr {$randomSeed/double(233280)}]
}

proc RandomRange { range } {
    return [expr {int ([Random]*$range)}]
}

proc DegToRad { phi } {
    return [expr {$phi * 3.1415926535 / 180.0}]
}

proc RadToDeg { rad } {
    return [expr {$rad * 180.0 / 3.1415926535}]
}

proc ArrayToList { arr noElem } {
    upvar $arr a
    set tmpList [list]
    for { set i 0 } { $i < $noElem } { incr i } {
	lappend tmpList $a($i)
    }
    return $tmpList
}

proc CheckString { expected value msg { printCheck true } } {
    # Check, if two string values are identical.
    #
    # expected   - Expected string value.
    # value      - Test string value.
    # msg        - Message for test case.
    # printCheck - Print message for successful test case.
    #
    # Returns true, if both string values are identical.
    # If "printCheck" is set to true, a line prepended with `"Check:"` and the
    # message supplied in "msg" is printed to standard output.
    # If the check fails, return false and print message prepended with `"Error:"`.
    #
    # See also: CheckList CheckBoolean CheckNumber

    if { $expected ne $value } {
        puts "Error: $msg (Expected: \"$expected\" Have: \"$value\")"
        return false
    }
    if { $printCheck } {
        puts "Check: $msg (Expected: \"$expected\" Have: \"$value\")"
    }
    return true
}

proc CheckBoolean { expected value msg { printCheck true } } {
    # Check, if two boolean values are identical.
    #
    # expected   - Expected boolean value.
    # value      - Test boolean value.
    # msg        - Message for test case.
    # printCheck - Print message for successful test case.
    #
    # Returns true, if both boolean values are identical.
    # If $printCheck is set to true, a line prepended with `"Check:`" and the
    # message supplied in $msg is printed to standard output.
    # If the check fails, return false and print message prepended with `"Error:`".
    #
    # See also: CheckNumber CheckList CheckString

    if { [expr bool($expected)] != [expr bool($value)] } {
        puts "Error: $msg (Expected: $expected Have: $value)"
        return false
    }
    if { $printCheck } {
        puts "Check: $msg (Expected: $expected Have: $value)"
    }
    return true
}

proc CheckNumber { expected value msg { printCheck true } } {
    # Check, if two numerical values are identical.
    #
    # expected   - Expected numeric value.
    # value      - Test numeric value.
    # msg        - Message for test case.
    # printCheck - Print message for successful test case.
    #
    # Returns true, if both numeric values are identical.
    # If $printCheck is set to true, a line prepended with `"Check:"` and the
    # message supplied in $msg is printed to standard output.
    # If the check fails, return false and print message prepended with `"Error:"`.
    #
    # See also: CheckBoolean CheckList CheckString

    if { $expected != $value } {
        puts "Error: $msg (Expected: $expected Have: $value)"
        return false
    }
    if { $printCheck } {
        puts "Check: $msg (Expected: $expected Have: $value)"
    }
    return true
}

proc CheckList { expected value msg { printCheck true } } {
    # Check, if two lists are identical.
    #
    # expected   - Expected list.
    # value      - Test list.
    # msg        - Message for test case.
    # printCheck - Print message for successful test case.
    #
    # Returns true, if both lists are identical.
    # If $printCheck is set to true, a line prepended with `"Check:"` and the
    # message supplied in $msg is printed to standard output.
    # If the check fails, return false and print message prepended with `"Error:"`.
    #
    # See also: CheckBoolean CheckNumber CheckString

    if { [llength $expected] != [llength $value] } {
        puts "Error: $msg (List length differ. Expected: [llength $expected] Have: [llength $value])"
        return false
    }
    set index 0
    foreach exp $expected val $value {
        if { $exp != $val } {
            puts "Error: $msg (Values differ at index $index. Expected: $exp Have: $val)"
            return false
        }
        incr index
    }
    if { $printCheck } {
        if { [llength $value] <= 4 } {
            puts "Check: $msg (Expected: $expected Have: $value)"
        } else {
            puts "Check: $msg (Lists are identical. List length: [llength $value])"
        }
    }
    return true
}

proc CheckFile { fileName1 fileName2 msg { printCheck true } } {
    # Check, if two files are identical.
    #
    # fileName1  - First file name.
    # fileName2  - Second file name.
    # msg        - Message for test case.
    # printCheck - Print message for successful test case.
    #
    # Returns true, if both files are identical.
    # If "printCheck" is set to true, a line prepended with `"Check:"` and the
    # message supplied in "msg" is printed to standard output.
    # If the check fails, return false and print message prepended with `"Error:"`.
    #
    # See also: CheckList CheckBoolean CheckNumber CheckString

    if { ! [file isfile $fileName1] } {
        puts "Error: $msg (File not existent: \"$fileName1\")"
        return false
    }
    if { ! [file isfile $fileName2] } {
        puts "Error: $msg (File not existent: \"$fileName2\")"
        return false
    }

    if { [file size $fileName1] != [file size $fileName2] } {
        puts "Error: $msg (Expected size: [file size $fileName1] Have: [file size $fileName2])"
        return false
    } 

    set fp1 [open $fileName1 "r"]
    set fp2 [open $fileName2 "r"]

    fconfigure $fp1 -translation binary
    fconfigure $fp2 -translation binary

    set retVal  0
    set bufSize 2048

    set str1 [read $fp1 $bufSize]
    while { 1 } {
        set str2 [read $fp2 $bufSize]
        if { $str1 ne $str2 } {
            # Files differ
            set retVal 0
            break
        }
        set str1 [read $fp1 $bufSize]
        if { $str1 eq "" } {
            # Files are identical
            set retVal 1
            break
        }
    }
    close $fp1
    close $fp2

    if { $retVal == 0 } {
        puts "Error: $msg (Files differ: \"[file tail $fileName1]\" \"[file tail $fileName2]\")"
        return false
    } else {
        if { $printCheck } {
            puts "Check: $msg (Files are identical: \"[file tail $fileName1]\" \"[file tail $fileName2]\")"
        }
    }
    return true
}

