#
# Copyright 2007-2008 University of Zagreb, Croatia.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#

# Boeing: refactor menus
set TOOLSMENUPATH .menubar.tools
set TOPOMENUPATH ${TOOLSMENUPATH}.t_g
menu $TOPOMENUPATH -tearoff 1
${TOOLSMENUPATH} add cascade -label "Topology generator" -underline 0 -menu ${TOPOMENUPATH}
# also throughout:
# s/.menubar.t_g/${TOPOMENUPATH}/g
# s///g
# end Boeing

set m ${TOPOMENUPATH}.random
menu $m -tearoff 0
${TOPOMENUPATH} add cascade -label "Random" -menu $m -underline 0 
foreach i [list 1 5 10 15 20 30 40 50 75 100] {
    set n $m.$i
    menu $n -tearoff 0
    $m add command -label "R($i)" -command "R \[newNodes $i\]"
}

set m ${TOPOMENUPATH}.grid
menu $m -tearoff 0
${TOPOMENUPATH} add cascade -label "Grid" -menu $m -underline 0 
foreach i [list 1 5 10 15 20 25 30 35 40 50 60 70 80 90 100] {
    set n $m.$i
    menu $n -tearoff 0
    $m add command -label "G($i)" -command "G \[newNodes $i\]"
}

set m ${TOPOMENUPATH}.gridc
menu $m -tearoff 0
${TOPOMENUPATH} add cascade -label "Connected Grid" -menu $m -underline 0 
    
for { set i 1 } { $i <= 10 } { incr i } {
    set n $m.$i
    menu $n -tearoff 0
    $m add cascade -label "$i x N" -menu $n -underline 0
    for { set j 1 } { $j <= 10 } { incr j } {
	$n add command -label "$i x $j" -command "Gchelper $i $j"
    }
}

set m ${TOPOMENUPATH}.chain
menu $m -tearoff 0
${TOPOMENUPATH} add cascade -label "Chain" -menu $m -underline 0 
for { set i 2 } { $i <= 24 } { incr i } {
    $m add command -label "P($i)" -command "P \[newNodes $i\]"
}
# Boeing
foreach i [list 32 64 128] {
    $m add command -label "P($i)" -command "P \[newNodes $i\]"
}
# end Boeing

set m ${TOPOMENUPATH}.star
menu $m -tearoff 0
${TOPOMENUPATH} add cascade -label "Star" -menu $m -underline 0 
for { set i 3 } { $i <= 25 } { incr i } {
    $m add command -label "S($i)" \
	-command "Kb \[newNodes 1\] \[newNodes [expr {$i - 1}]\]"
}

set m ${TOPOMENUPATH}.cycle
menu $m -tearoff 0
${TOPOMENUPATH} add cascade -label "Cycle" -menu $m -underline 0 
for { set i 3 } { $i <= 24 } { incr i } {
    $m add command -label "C($i)" -command "C \[newNodes $i\]"
}

set m ${TOPOMENUPATH}.wheel
menu $m -tearoff 0
${TOPOMENUPATH} add cascade -label "Wheel" -menu $m -underline 0 
for { set i 4 } { $i <= 25 } { incr i } {
    $m add command -label "W($i)" \
	-command "W \"\[newNodes 1\] \[newNodes [expr {$i - 1}]\]\""
}

set m ${TOPOMENUPATH}.cube
menu $m -tearoff 0
${TOPOMENUPATH} add cascade -label "Cube" -menu $m -underline 0 
for { set i 2 } { $i <= 6 } { incr i } {
    $m add command -label "Q($i)" \
	-command "Q \[newNodes [expr {int(pow(2,$i))}]\]"
}

set m ${TOPOMENUPATH}.clique
menu $m -tearoff 0
${TOPOMENUPATH} add cascade -label "Clique" -menu $m -underline 0 
for { set i 3 } { $i <= 24 } { incr i } {
    $m add command -label "K($i)" -command "K \[newNodes $i\]"
}

set m ${TOPOMENUPATH}.bipartite
menu $m -tearoff 0
${TOPOMENUPATH} add cascade -label "Bipartite" -menu $m -underline 0 
    
for { set i 1 } { $i <= 12 } { incr i } {
    set n $m.$i
    menu $n -tearoff 0
    $m add cascade -label "K($i,N)" -menu $n -underline 0
    for { set j $i } { $j <= [expr {24 - $i}] } { incr j } {
	$n add command -label "K($i,$j)" -command "Kbhelper $i $j"
    }
}


proc newNodes { n } {
    global curcanvas grid sizex sizey activetool activetoolp CORE_DATA_DIR
    global g_last_selected_node_type

    if { [lsearch {select start link bgobjs} $activetool] >= 0 } {
	set activetoolp ""
    }
    # some other tool is selected besides layer-2/3 nodes
    if { $activetoolp != "routers" && $activetoolp != "hubs" } {
	if { [info exists g_last_selected_node_type] && \
	     $g_last_selected_node_type != "" } {
	    set parent [lindex $g_last_selected_node_type 0]
	    set b [lindex $g_last_selected_node_type 1]
	    set imgf [lindex $g_last_selected_node_type 2]
	    popupMenuChoose $parent $b $imgf
	} else {
	    # select router by default (this properly sets some globals)
	    set icon "$CORE_DATA_DIR/icons/tiny/router.gif"
	    popupMenuChoose "routers" "router" $icon
        }
    }

    set v {}
    set r [expr {($n - 1) * (1 + 4 / $n) * $grid / 2}]
    set x0 [expr {$sizex / 2}]
    set y0 [expr {$sizey / 2}]
    set twopidivn [expr {acos(0) * 4 / $n}]

    set dy 32
    if { [lsearch {router rj45} $activetool] >= 0 } {
	set dy 28
    } elseif { [lsearch {hub lanswitch} $activetool] >= 0 } {
	set dy 24
    }

    for { set i 0 } { $i < $n } { incr i } {
	if { $activetoolp == "routers" } {
	    set new_node [newNode router]
	    setNodeModel $new_node $activetool
	} else {
	    set new_node [newNode $activetool]
	}
	set x [expr {$x0 + $r * cos($twopidivn * $i)}]
	set y [expr {$y0 - $r * sin($twopidivn * $i)}]
	setNodeCoords $new_node "$x $y"
	setNodeLabelCoords $new_node "$x [expr {$y + $dy}]"
	setNodeCanvas $new_node $curcanvas
	lappend v $new_node
    }

    return $v
}

proc topoGenDone { v } {
    global changed activetool

    set activetool select
    set changed 1
    updateUndoLog
    redrawAll
    selectNodes $v
}

#
# Chain
#
proc P { v } {
    .c config -cursor watch; update
    set n [llength $v]
    for { set i 0 } { $i < [expr {$n - 1}] } { incr i } {
	newLink [lindex $v $i] [lindex $v [expr {($i + 1) % $n}]]
    }
    topoGenDone $v
}

#
# Cycle
#
proc C { v } {
    .c config -cursor watch; update
    set n [llength $v]
    for { set i 0 } { $i < $n } { incr i } {
	newLink [lindex $v $i] [lindex $v [expr {($i + 1) % $n}]]
    }
    topoGenDone $v
}

#
# Wheel 
#
proc W { v } {
    .c config -cursor watch; update
    set n [llength $v]
    set vr [lindex $v 0]
    set vt "$v [lindex $v 1]"
    for { set i 1 } { $i < $n } { incr i } {
	newLink $vr [lindex $v $i]
	newLink [lindex $v $i] [lindex $vt [expr {$i + 1}]]
    }
    topoGenDone $v
}

#
# Cube
#
proc Q { v } {
    set n [llength $v]
    set order [expr int(log($n)/log(2))]
    for { set i 0 } { $i < $order } { incr i } {
	animateCursor
	set d [expr {int(pow(2, $i))}]
	for { set j 0 } { $j < $n } { incr j } {
	    if { [llength [ifcList [lindex $v $j]]] <= $i} {
		newLink [lindex $v $j] [lindex $v [expr {($j + $d) % $n}]]
	    }
	}
    }
    topoGenDone $v
}

#
# Clique
#
proc K { v } {
    set n [llength $v]
    for { set i 0 } { $i < [expr {$n - 1}] } { incr i } {
	animateCursor
	for { set j [expr {$i + 1}] } { $j < $n } {incr j } {
	    newLink [lindex $v $i] [lindex $v $j]
	}
    }
    topoGenDone $v
}

#
# Bipartite
#
proc Kb { v1 v2 } {
    set n1 [llength $v1]
    set n2 [llength $v2]
    for { set i 0 } { $i < $n1 } { incr i } {
	animateCursor
	for { set j 0 } { $j < $n2 } {incr j } {
	    newLink [lindex $v1 $i] [lindex $v2 $j]
	}
    }
    topoGenDone "$v1 $v2"
}

proc Kbhelper { n m } {
    set v [newNodes [expr $n + $m]]
    Kb [lrange $v 0 [expr $n -1]] [lrange $v $n end]
}

#
# Random
#
proc R { v } {
    global curcanvas
    set c .c
    set min 20
    set xmax [expr {[lindex [getCanvasSize $curcanvas] 0] - 2*$min}]
    set ymax [expr {[lindex [getCanvasSize $curcanvas] 1] - 2*$min}]

    expr { srand([clock clicks -milliseconds]) }

    .c config -cursor watch; update
    foreach node $v {
	set x [expr { int(rand() * $xmax) + $min} ]
	set y [expr { int(rand() * $ymax) + $min} ]
	setNodeCoords $node "$x $y"
	set dy 28
	setNodeLabelCoords $node "$x [expr {$y + $dy}]"
    }
    topoGenDone $v
}

#
# Grid
#
proc G { v } {
    global curcanvas
    set c .c
    set step 100
    set min 50
    set xmax [expr {[lindex [getCanvasSize $curcanvas] 0] - 2*$min}]
    set ymax [expr {[lindex [getCanvasSize $curcanvas] 1] - 2*$min}]

    .c config -cursor watch; update
    set x $min
    set y $min
    foreach node $v {
	if { $x >= $xmax } { ;# end of the row
	    set x $min
	    incr y $step
	    if { $y >= $ymax } {
		# xmax and ymax reached -- out of canvas space here!
		set y $ymax
	    }
        }
	setNodeCoords $node "$x $y"
	set dy 28 
	setNodeLabelCoords $node "$x [expr {$y + $dy}]"
	incr x $step
    }
    topoGenDone $v
}

#
# Connected Grid
#
proc Gc { v n m } {
    set step 100
    set dy 28 
    set y $step 

    set nodenum 0

    # m is number of rows
    for { set i 0 } { $i < $m } { incr i } {
	animateCursor
        set x 0 ;# start a new row
	# n is number of columns
	for { set j 0 } { $j < $n } {incr j } {
	    incr x $step
	    set node [lindex $v $nodenum]
	    setNodeCoords $node "$x $y"
	    setNodeLabelCoords $node "$x [expr {$y + $dy}]"
	    if { $x > $step } { ;# link each node with prev in row
	        set lastnode [lindex $v [expr {$nodenum - 1}]]
		newLink $lastnode $node
	    }
	    if { $y > $step } { ;# link each node with above in column
	        set lastnode [lindex $v [expr {$nodenum - $n}]]
		newLink $lastnode $node
	    }
	    incr nodenum 1 ;# on to the next column
	}
	incr y $step ;# on to the next row
    }
    topoGenDone $v
}

proc Gchelper { n m } {
    set v [newNodes [expr $n * $m]]
    Gc $v $n $m
}