#
# Copyright (C) 1998 by USC/ISI
# All rights reserved.                                            
#                                                                
# Redistribution and use in source and binary forms are permitted
# provided that the above copyright notice and this paragraph are
# duplicated in all such forms and that any documentation, advertising
# materials, and other materials related to such distribution and use
# acknowledge that the software was developed by the University of
# Southern California, Information Sciences Institute.  The name of the
# University may not be used to endorse or promote products derived from
# this software without specific prior written permission.
# 
# THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
# 
# $Header: /usr/src/mash/repository/vint/nam-1/tcl/netModel.tcl,v 1.6 1998/12/11 22:43:50 yaxu Exp $

NetworkModel instproc init { animator tracefile } {
	$self next $animator	;# create shadow, etc.
	$self nam_addressing $tracefile
	$self nam_layout $tracefile
	$self layout
}

# Read events from the trace file and extract addressing information from them
NetworkModel instproc nam_addressing { tracefile } {
    set stream [new NamStream $tracefile]
    set time "0"
    # skip all beginning non "*" events
    while {([$stream eof]==0)&&([string compare $time "*"]!=0)} {
	set line [$stream gets]
	set time [get_trace_item "-t" $line]
    }

    $self instvar netAddress
    if ![info exists netAddress] {
	    set netAddress [new Address]
    }
    while {([$stream eof]==0)&&([string compare $time "*"]==0)} {
	set cmd [lindex $line 0]
	set time [get_trace_item "-t" $line]
	if {[string compare $time "*"]!=0} {break}
	switch $cmd {
		"A" {
			set hier [get_trace_item "-n" $line]
			if {$hier != ""} {
				# PortShift
				set ps [get_trace_item "-p" $line]
				# PortMask
				set pm [get_trace_item "-o" $line]
				# McastShift
				set ms [get_trace_item "-c" $line]
				# McastMask
				set mm [get_trace_item "-a" $line]
				$netAddress portbits-are $ps $pm
				$netAddress mcastbits-are $ms $mm
			} else {
				set hier [get_trace_item "-h" $line]
				# NodeShift
				set nh [get_trace_item "-m" $line]
				# NodeMask
				set nm [get_trace_item "-s" $line]
				$netAddress add-hier $hier $nh $nm
			}
		}
	}
	# XXX
	# assuming that every line end with End-OF-Line
	set line [$stream gets]
    }
    $stream close
}

#read events from the tracefile and parse them as layout commands until
#we meet a read event
NetworkModel instproc nam_layout { tracefile } {
    set stream [new NamStream $tracefile]
    set time "0"
    # skip all beginning non "*" events
    while {([$stream eof]==0)&&([string compare $time "*"]!=0)} {
	set line [$stream gets]
	set time [get_trace_item "-t" $line]
    }
    while {([$stream eof]==0)&&([string compare $time "*"]==0)} {
	set cmd [lindex $line 0]
	set time [get_trace_item "-t" $line]
	if {[string compare $time "*"]!=0} {break}
	switch $cmd {
	    "n" {
		$self layout_node [lrange $line 1 end]
	    }
	    "l" {
		$self layout_link [lrange $line 1 end]
	    }
	    "L" {
		$self layout_lanlink [lrange $line 1 end]
	    }
	    "X" {
		$self layout_lan [lrange $line 1 end]
	    }
	    "q" {
		$self layout_queue [lrange $line 1 end]
	    }
	    "c" {
		$self layout_color [lrange $line 1 end]
	    }
	}
	# XXX
	# assuming that every line end with End-OF-Line
	set line [$stream gets]
    }
    $stream close
}

NetworkModel instproc layout_node {line} {
    set color black
    set shape circle
    set src ""
    set size 0
    set addr 0	;# default
    for {set i 0} {$i < [llength $line]} {incr i} {
	set item [string range [lindex $line $i] 1 end]
	switch $item {
	    "s" {
		set src [lindex $line [expr $i+1]]
	    }
	    "v" {
		set shape [lindex $line [expr $i+1]]
	    }
	    "c" {
		set color [lindex $line [expr $i+1]]
		if {[string range $color 0 0] == "\#"} {
		    set rgb [winfo rgb . $color]
		    set color "[$self lookupColorName [lindex $rgb 0] \
			[lindex $rgb 1] [lindex $rgb 2]]"
		}
	    }
	    "z" {
		set size [lindex $line [expr $i+1]]
	    }
	    "a" {
		    set addr [lindex $line [expr $i+1]]
	    }
	    "x" {
		    set xcor [lindex $line [expr $i+1]]
	    }
	    "y" {
		    set ycor [lindex $line [expr $i+1]]
	    }
	}
	if {[string range $item 0 0]=="-"} {incr i}
    }
    if {$src==""} {
	puts "Error in parsing tracefile line:\n$line\n"
	exit
    }

    if [info exists xcor] {
	$self node $src $shape $color $addr $size $xcor $ycor
    } else {
        $self node $src $shape $color $addr $size
    }
}

NetworkModel instproc layout_lan {line} {
    set name ""
    set rate ""
    set delay ""
    set orient down
    for {set i 0} {$i < [llength $line]} {incr i} {
	set item [string range [lindex $line $i] 1 end]
	switch $item {
	    "n" {
		set name [lindex $line [expr $i+1]]
	    }
            "r" {
                set rate [lindex $line [expr $i+1]]
            }
            "D" {
                set delay [lindex $line [expr $i+1]]
            }
            "o" {
                set orient [lindex $line [expr $i+1]]
            }
	}
	if {[string range $item 0 0]=="-"} {incr i}
    }
    if {$name==""} {
	puts "Error in parsing tracefile line:\n$line\n"
	exit
    }
    set th [nam_angle $orient]
    $self lan $name [bw2real $rate] [time2real $delay] [expr $th]
    
}

NetworkModel instproc layout_link {line} {
    $self instvar delay01
    #orient can default because pre-layout will have kicked us into 
    #autolayout mode by this point
    set orient right
    set src ""
    set dst ""
    set rate ""
    set delay ""
    set color ""
    set length 0
    for {set i 0} {$i < [llength $line]} {incr i} {
	set item [string range [lindex $line $i] 1 end]
	switch "$item" {
	    "s" {
		set src [lindex $line [expr $i+1]]
	    }
	    "d" {
		set dst [lindex $line [expr $i+1]]
	    }
	    "r" {
		set rate [lindex $line [expr $i+1]]
	    }
	    "D" {
		set delay [lindex $line [expr $i+1]]
	    }
	    "l" {
		set length [lindex $line [expr $i+1]]
	    }
	    "o" {
		set orient [lindex $line [expr $i+1]]
	    }
	    "c" {
		set color [lindex $line [expr $i+1]]
	    }
	}
	if {[string range $item 0 0]=="-"} {incr i}
    }
    if {($src=="")||($dst=="")||($rate=="")||($delay=="")} {
	puts "Error in parsing tracefile line:\n$line\n"
	exit
    }
    set th [nam_angle $orient]
    set rev [expr $th + 1]
    # This is easier than using mod arithmetic
    if { $rev > 2.0 } {
	set rev [expr $rev - 2.0]
    }
    #build the reverse link
    $self link $dst $src [bw2real $rate] [time2real $delay] $length $rev

    #and the forward one
    set result [$self link $src $dst \
	    [bw2real $rate]  [time2real $delay] $length $th]
    if { $src == 0 && $dst == 1 } {
		set delay01 $result
    }
    
    if { $color!=""} {
	$self ecolor $src $dst $color
	$self ecolor $dst $src $color
    }
}

NetworkModel instproc layout_lanlink {line} {
    $self instvar delay01
    #orient can default because pre-layout will have kicked us into 
    #autolayout mode by this point
    set orient right
    set src ""
    set dst ""
    for {set i 0} {$i < [llength $line]} {incr i} {
	set item [string range [lindex $line $i] 1 end]
	switch "$item" {
	    "s" {
		set src [lindex $line [expr $i+1]]
	    }
	    "d" {
		set dst [lindex $line [expr $i+1]]
	    }
	    "o" {
		set orient [lindex $line [expr $i+1]]
	    }
	}
	if {[string range $item 0 0]=="-"} {incr i}
    }
    if {($src=="")||($dst=="")} {
	puts "Error in parsing tracefile line:\n$line\n"
	exit
    }
    set th [nam_angle $orient] ;# global function
    $self lanlink $dst $src $th
}

NetworkModel instproc layout_queue {line} {
	for {set i 0} {$i < [llength $line]} {incr i} {
		set item [string range [lindex $line $i] 1 end]
		switch $item {
			"s" {
				set src [lindex $line [expr $i+1]]
			}
			"d" {
				set dst [lindex $line [expr $i+1]]
			}
			"a" {
				set angle [lindex $line [expr $i+1]]
			}
		}
		if {[string range $item 0 0]=="-"} {incr i}
	}
	$self queue $src $dst $angle
}

NetworkModel instproc layout_color {line} {
    for {set i 0} {$i < [llength $line]} {incr i} {
	set item [string range [lindex $line $i] 1 end]
	switch $item {
	    "i" {
		set ix [lindex $line [expr $i+1]]
	    }
	    "n" {
		set name [lindex $line [expr $i+1]]
		if {[string range $name 0 0] == "\#"} {
                    set rgb [winfo rgb . $color]
                    set name "[$self lookupColorName [lindex $rgb 0] \
                        [lindex $rgb 1] [lindex $rgb 2]]"
		}

	    }
	}
	if {[string range $item 0 0]=="-"} {incr i}
    }
    $self color $ix $name
}
